Wednesday, August 25, 2010

Getting Started with NServiceBus Part 3: Putting Messages on the Bus

Last time we analyzed the Music Store code to come up with a schema for our messages. The next order of business is to modify the Music Store code to put messages on the bus. In order to do this we must first edit our web.config file to configure NSB. First you have to add the custom config section:
Next we add that section to create an Endpoint Mapping. What this does is tell the bus that the given Endpoint will be accepting messages defined in our schema assembly.

    
      
    
  
In our case the Endpoint is the address to the queue that will be accepting our messages. If you want at this point you can create this as a local, private, transactional MSMQ queue. Also be sure to have the Distributed Transaction Coordinator service up and running. Now that we have configured our Endpoint, we have to bootstrap NServiceBus and keep it going for the duration of our ASP.NET application. We can do this in the Global.asax.cs file using NSB's fluent configuration:
protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterRoutes(RouteTable.Routes);

            Bus = NServiceBus.Configure.WithWeb()
                .Log4Net()
                .DefaultBuilder()
                .XmlSerializer()
                .MsmqTransport()
                    .IsTransactional(false)
                    .PurgeOnStartup(false)
                .UnicastBus()
                    .ImpersonateSender(false)
                .CreateBus()
                .Start();
        }
I'll explain each configuration item bit by bit:

  • WithWeb - tells NSB to scan a web directory instead of a regular one
  • Log4Net - next configure Log4Net for logging
  • DefaultBuilder - use the default IoC container
  • XmlSerializer - serialize objects using XML
  • MsmqTransport - configure MSMQ as our transportation protocol
  • IsTransactional(false) - we don't want to hang a web app up in transactions, so turn this off
  • PurgeOnStartup(false) - since there is no queue for us to purge, turn this off
  • UnicastBus - configure our bus to send single point to point messages
  • ImpersonateSender(false) - turn off impersonation
  • CreateBus() - tell the IoC to create an instance of the bus
  • Start() - bootstrap the bus

Now that we've bootstrapped, NSB we can get on to sending messages. Our first message will be used to add something to a cart in the database. We head to the the ShoppingCartController.AddToCart method and modify it to send a message instead of interacting directly with the database.

public ActionResult AddToCart(int id)
        {

            // Retrieve the album from the database
            var addedAlbum = storeDB.Albums
                .Single(album => album.AlbumId == id);

            // Add it to the shopping cart
            var cart = ShoppingCart.GetCart(this.HttpContext);
            
            //cart.AddToCart(addedAlbum);

            Helpers.ServiceAgent<IAddToCartCommand>.Send(
                c => 
                {
                    c.CartId = cart.GetCartId(this.HttpContext);
                    c.AlbumId = addedAlbum.AlbumId;
                });
           
            // Go back to the main store page for more shopping
            return RedirectToAction("Index");
        }
I've added a utility class to actually put the message on the bus using similar NSB semantics. I'm doing this so that I don't have an explicit reference to NSB in my Controller code. The utility is very simple:
public static class ServiceAgent<T> where T : ICommand
    {
        public static void Send(Action<T> messageConstructor)
        {
            if (null != messageConstructor)
                MvcApplication.Bus.Send<T>(messageConstructor);
        }
    }
We'll do the same thing for placing an order. We modify the code in CheckOutController.AddressAndPayment:
[HttpPost]
        public ActionResult AddressAndPayment(FormCollection values)
        {
            ...
                else
                {
                    //order.Username = User.Identity.Name;
                    //order.OrderDate = DateTime.Now;

                    //Save Order
                    //storeDB.AddToOrders(order);
                    //storeDB.SaveChanges();

                    //Process the order
                    var cart = ShoppingCart.GetCart(this.HttpContext);
                    //cart.CreateOrder(order);

                    Int32 syntheticId = Helpers.IdGenerator.Generate();

                    Helpers.ServiceAgent.Send(
                        c =>
                        {
                            c.OrderId = syntheticId;
                            c.CartId = cart.GetCartId(this.HttpContext);
                        });

                    
                    
                    return RedirectToAction("Complete", 
                        new { id = syntheticId });
                }
            ...
        }
Here we're using the same utility class to put a message on the bus. Note that I'm generating the Order Id on the client side. This application shows the order id back to the user after they have placed the order. In order to pull this off, we have to create the id client site. I've created another utility to generate the Order Id:
public static class IdGenerator
    {
        public static Int32 Generate()
        {
            byte[] buffer = Guid.NewGuid().ToByteArray();
            return BitConverter.ToInt32(buffer, 0);
        }
    }
Now if you fire up the client and try to add items to the cart, you won't see any data in the subsequent screen. This is because we haven't implemented the server side to our solution that handles the messages. When placing an order you should see and order id just like you normally would.

Next time we'll implement the message handlers and talk about how to host, configure, and run a NSB instance.

Code can be found HERE

Wednesday, August 18, 2010

Getting Started with NServiceBus Part 2: Music Store Schema

Now that we've identified our architecture, the next order of business is to identify what information will be shared within the system.  In our example we will be sending commands to the server to update shopping carts and to place orders.  We'll need two classes to house that information.  First we'll take a look into adding something to a cart by looking at the ShoppingCartController class.  We quickly find the add method:

 public ActionResult AddToCart(int id)
 {
          ...
            cart.AddToCart(addedAlbum);
          ...
 }

This leads us to the AddToCart method:

 public void AddToCart(Album album)
 {
            ...
            if (cartItem == null)
            {
                // Create a new cart item
                cartItem = new Cart
                {
                    AlbumId = album.AlbumId,
                    CartId = shoppingCartId,
                    Count = 1,
                    DateCreated = DateTime.Now
                };
                storeDB.AddToCarts(cartItem);
            }
            else
            {
                // Add one to the quantity
                cartItem.Count++;
            }

            // Save it
            storeDB.SaveChanges();
 }

We find that all we need is the id of the album and the id of the cart to add it to, and therefore we can define our command as:

public interface IAddToCartCommand : ICommand
{
        String CartId { get; set; }
        Int32 AlbumId { get; set; }
}

public interface ICommand : IMessage
{
}

In order to share the reference to the Cart class we have to pull the Models namespace into a separate assembly out of the uber assembly the sample ships with.  There are three major things to note in this code.

First of all in order to identify a message to the NServiceBus infrastructure, we must mark the message with the IMessage interface.  This is how NSB will wire messages to message handlers.

The second note is that we've created an intermediary interface.  We have done this so we can easily differentiate between commands and events.  Commands denote one-way, point to point communication between known parties.  Events denote one-way, one to many communication with potentially unknown parties.  The other way we differentiate the two is to change how the verb in the name is used.  Typically commands will tell the server to do something, ex. "AddToCart".  An event will let us know something happened in the past, ex. "ItemAddedToCart".

Lastly we always use interfaces to define our message schema.  If we do so then NSB can gracefully handle the versioning of messages for us.  This becomes very important when we change our messages and we have to maintain backwards compatibility.

Now we can look at placing an order.  The code for this is a bit strange as its broken up into two different transactions, one for the "header" and one for the details.  The first part is in the AddressAndPayment method in the CheckoutController class, and the second part is in the ShoppingCart class:

        public ActionResult AddressAndPayment(FormCollection values)
        {
            var order = new Order();
            ...
                    order.Username = User.Identity.Name;
                    order.OrderDate = DateTime.Now;

                    //Save Order
                    storeDB.AddToOrders(order);
                    storeDB.SaveChanges();

                    //Process the order
                    var cart = ShoppingCart.GetCart(this.HttpContext);
                    cart.CreateOrder(order);

                    return RedirectToAction("Complete",
                        new { id = order.OrderId });
               ...
        }


 public int CreateOrder(Order order)
 {
            ...
            var cartItems = GetCartItems();

             foreach (var cartItem in cartItems)
            {
                var orderDetails = new OrderDetail
                {
                    AlbumId = cartItem.AlbumId,
                    OrderId = order.OrderId,
                    UnitPrice = cartItem.Album.Price
                };

                storeDB.OrderDetails.AddObject(orderDetails);
                ...
            }

            //Save the order
            storeDB.SaveChanges();
            ...
            //Return the OrderId as a confirmation number
            return order.OrderId;
}

In order to preserve consistency in our database, we'll perform all these actions in a single transaction.  This way we don't get orders without their details.  Also by using durable messaging, we'll ensure that orders don't get lost.  Within the code, the Order is constructed from the ShoppingCart object.  Therefore, all we need is the id of the current cart, and we can look up the rest of the information server side(also reducing trips to the server):

public interface IPlaceOrderCommand : ICommand
{
        String CartId { get; set; }
}


In summary we've decided on how our schema is going to look so that we can now start putting these messages On the Bus!  Next time we'll change the store front to put messages on the bus.  Code can be found here

Saturday, August 14, 2010

NServiceBus for Admins Slide Deck

I've used this deck to introduce NSB to Admins and help them understand the key components of the infrastructure. The deck highlights what they will be responsible for and how to configure the infrastructure for NSB. There are a few slides that have imagery for the NSB site, so I attribute full credit to them for those slides.

Getting Started with NServiceBus Part 1: Analysis of ASP.NET MVC Music Store

In part one of our series we'll begin by analyzing the current state of our application.  I've chosen the ASP.NET MVC Music Store as my example as it has a very small feature set.  What we have is a very simple store front application where you can browse and purchase albums.  The application is your atypical web application that is entirely dependent on a Request/Response architecture.  There are a few places within the application where Request/Response may pose some challenges.

The Shopping Cart

Currently the application pushes a record to the database for each item in your cart.  As a user you really don't know this is happening until something goes wrong.  If for some reason the supporting database was no longer available, the user would not be able to add items to the cart.  Some may say that you have larger issues in that if the database is down, the whole site is down.  For our purposes let's pretend we cache all our static content on a CDN somewhere and we can still browse albums.  To keep our users filling there carts, we'll push a message to the server and update the database in a separate process altogether.

Checking Out

This feature works the same as the Shopping Cart, the user enters their information and their order is pushed to the database.  We have the same potential issue here, if we cannot accept orders our music store is not making us money.  We'd also hate to make a user who has a large order submit it all over again.  We're really concerned with 2 things here, making the customer happy and making sure the store is taking orders.  We'll take the same approach as above and push messages to the server and subsequently update the database.  Now the customers will be happy and we won't lose orders.

Architecture

To accomplish all of this we'll use NServiceBus to move messages to the server and process them.  We'll device a way to plug NSB into the ASP.NET runtime so we can send messages from the web application.  Next we'll create a NSB host on our server to handle the carts and the orders.

Summary

We'll found a couple of soft spots in our application where we can apply messaging to make the customer happy and keep the store running.  Next time we'll start to apply NSB to our solution and walk through the basics of configuring the web application to send messages.

Monday, August 9, 2010

NServiceBus - What did I just download?

I'm currently working on getting some teams in my organization On the Bus and I find myself often quickly explaining what you get when you download NSB.  It includes so much functionality that it helps to quickly dissect what is there.  I'm going to lay it out at a high level so we all know what's in there and where to go first.

Root Directory
The top level directory is pretty self explanatory, I'm going to jump right into the first level of directories and start the tour there.

Binaries

This directory contains the bare bones to run NSB.  The exe is the Generic Host provided with NSB.  This gives us a process to run NSB inside of.  The only other assemblies you really need to run basic NSB functionality is NServiceBus.Core, NServiceBus, and log4net.  The rest will depend on your use case.  The "containers" directory has the binaries for the container of your choice, you don't have to use the default container(Spring).  The "x64" directory has the x64 version of SQLite for testing purposes.

Docs

The "docs" directory has some slides and diagrams of some of the functionality included with NSB, more on these later.  It also has some common code snippets for Visual Studio.  Don't expect deep dive information in the slides, they are just pictures at this point.

Processes
The "processes" directory contains some NSB infrastructure that you'll need for certain NSB use cases.  
  • "distributor" - contains the background process for distributing load across many instances of NSB.  This process handles monitoring the work load and distributing the work to worker nodes.
  • "gateway" - contains the process that manages moving messages between disparate instances of NSB. This is especially useful if you have more that one data center.  You can move messages between sites using the gateway.
  • "proxy" - this process allows us to expose a single endpoint to several clients.  This is handy when you need to expose NSB through a firewall.
  • "timeout" - this process handles the watching of the clock for Sagas.  Sagas are analogous to long running workflows.  When using Sagas, you need something to keep a watch and wait up workflows when necessary.
Samples

  • "AsyncPages" - example of how to due asynchronous request/response on a web page using ASP.NET as your host process. 
  • "FullDuplex" - example of performing request/response in a non-web scenario
  • "GenericHost" - example of how the host provided with NSB works.  Via the concept of profiles we can manipulate the behaviour of the host.
  • "Manufacturing" - this example has a lot of stuff in it, including Pub/Sub, Sagas, interop with straight MSMQ, the included testing framework, message ordering, and more.  I found myself taking bits of this example and breaking it down into smaller examples.
  • "PubSub" - basic example of how to implement the Publish/Subscribe pattern in NSB.
  • "Versioning" - shows how that through interfaces, NSB allows us to gracefully version messages to consumers without breaking them.
  • "WcfIntegration" - shows off the OOTB support for exposing NSB as a HTTP/WCF service.  This becomes useful if you have to interact with another non-MSMQ system.
  • "WebServiceBridge" - hosts NSB from within ASP.NET again, only this time in a web service.  The web site in this sample using the service to bridge into NSB without knowing about NSB itself.
Tools
  • "MsmqUtils" - provides a program for you to run to validate your install of MSMQ and MSDTC.  This is a handy tool to make sure you start off on the right foot, I recommend running this right after you download NSB to avoid headaches.
  • "ReturnToSourceQueue.exe" - takes messages from a queue(typically an error queue) and pushes them back to the source queue.  This tool is very effective when you have a bunch of failures that you want to re-process.  I would make sure your SysAdmins know about this tool.
  • "UI.exe" - is a limited UI for managing NSB endpoints.
  • "XsdGenerator.exe" - this tool will generate an XSD file using an assembly of messages as input.  This is for the case where you don't want to directly distribute your messages assembly, but would rather have consumers build their own.

That pretty much covers it, there is a lot of stuff in here!  I'm hoping to next start talking about some of the use cases we've had to leverage NSB and get started on a demo project to walk through an application of NSB.




Installing NServiceBus Using the Network Service Account

Our defacto standard for Windows Services is to install under the "Network Service" account or "MachineName$". To get NSB to install under this account, I had to try several variations of the account name and finally it came down to using a fully qualified name:

nservicebus.host.exe /install /serviceName:"ServiceName" /displayName:"DisplayName" /userName:"NT AUTHORITY\Network Service" /password:""

Friday, August 6, 2010

Exposing NServiceBus as a REST(WCF) Endpoint


I recently had a situation where I wanted to expose NSB as a REST endpoint.  WCF hosting comes out of the box with NSB, but it defaults to an HTTP binding.  Normally it would be a problem to just add another endpoint via config, but when using the webHttpBinding in WCF we need the ability to decorate operations with some attributes which is not configurable in a config file.  Luckily for us, NSB gives us a simple extension point to wire in our own ServiceHost.  I started by creating my WCF contract:

[ServiceContract]
    public interface IProductCreatedRestService
    {
        [OperationContract]
        [WebInvoke(UriTemplate = "products", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
        void Create(ProductCreatedMessage message);
    }
Next up is the concrete implementation:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class ProductCreatedRestService : IProductCreatedRestService
    {
        private readonly IBus bus;

        public ProductCreatedRestService()
        {
            if ( null == this.bus )
                this.bus = Configure.Instance.Builder.Build<IBus>();
        }

        public void Create(ProductCreatedMessage message)
        {
            this.bus.Send(message);
        }
    }

 The big note here is that I'm building an instance of IBus using the NSB IoC container. An alternative would be to register the component at startup and let NSB property-inject IBus. The next thing I need to do is create and open up a WebServiceHost for my service. I do this via the IWantToRunAtStartup marker interface. NSB makes heavy use of the marker interface pattern. This allows it to identify certain classes via the IoC container. This interface let's us plugin our own custom code when NSB starts up and subsequently shuts down. Here is my startup class:

 public class RestServiceStartup : IWantToRunAtStartup
    {
        private WebServiceHost host;

        public void Run()
        {
            this.host = new WebServiceHost(typeof(ProductCreatedRestService));
            this.host.Open();
        }

        public void Stop()
        {
            if (null != this.host && this.host.State == System.ServiceModel.CommunicationState.Opened)
                this.host.Close();
        }
    }
My handler for the message is standard issue NSB fare:

 public void Handle(ProductCreatedMessage message)
        {
            // Normally you would do a Bus.Send here first
            if (message.ProductNumber == 1111)
                this.Bus.Return((Int32)CommandErrorCodes.Fail);
            else
                this.Bus.Return((Int32)CommandErrorCodes.Success);
        }
Now we can fire up our NSB instance and also jump into Fiddler to generate our request:





Seminal Post

Hey all the plan is to post some interesting things I've come across while working with NServiceBus.  I plan on launching a full on demo project in the very near future.  I need to find someplace to host my code(suggestions welcome) and also pick a pet project to modify.  I'm thinking of taking a bite from Ayende's plate and using the ASP.NET MVC sample project.  Stay tuned...