Getting on the IBus

Exclusive offer: get 50% off this eBook here
Learning NServiceBus

Learning NServiceBus — Save 50%

Build reliable and scalable distributed software systems using the industry leading .NET enterprise Service Bus with this book and ebook

$23.99    $12.00
by David Boike | September 2013 | Enterprise Articles Open Source

In this article, by David Boike author of Learning NServiceBus, we'll explore the basics of NServiceBus by downloading the NServiceBus code and using it to build a simple solution to send a message from an MVC website to a backend service for processing.

(For more resources related to this topic, see here.)

Why NServiceBus?

Before diving in, we should take a moment to consider why NServiceBus might be a tool worth adding to your repertoire. If you're eager to get started, feel free to skip this section and come back later.

So what is NServiceBus? It's a powerful, extensible framework that will help you to leverage the principles of Service-oriented architecture ( SOA ) to create distributed systems that are more reliable, more extensible, more scalable, and easier to update.

That's all well and good, but if you're just picking up this book for the first time, why should you care? What problems does it solve? How will it make your life better?

Ask yourself whether any of the following situations describe you:

  • My code updates values in several tables in a transaction, which acquires locks on those tables, so it frequently runs into deadlocks under load. I've optimized all the queries that I can. The transaction keeps the database consistent but the user gets an ugly exception and has to retry what they were doing, which doesn't make them very happy.
  • Our order processing system sometimes fails on the third of three database calls. The transaction rolls back and we log the error, but we're losing money because the end user doesn't know if their order went through or not, and they're not willing to retry for fear of being double charged, so we're losing business to our competitor.
  • We built a system to process images for our clients. It worked fine for a while but now we've become a victim of our own success. We designed it to be multithreaded (which was no small feat!) but we already maxed out the original server it was running on, and at the rate we're adding clients it's only a matter of time until we max out this one too. We need to scale it out to run on multiple servers but have no idea how to do it.
  • We have a solution that is integrating with a third-party web service, but when we call the web service we also need to update data in a local database. Sometimes the web service times out, so our database transaction rolls back, but sometimes the web service call does actually complete at the remote end, so now our local data and our third-party provider's data are out of sync.
  • We're sending emails as part of a complex business process. It is designed to be retried in the event of a failure, but now customers are complaining that they're receiving duplicate emails, sometimes dozens of them. A failure occurs after the email is sent, the process is retried, and the emails is sent over and over until the failure no longer occurs.
  • I have a long-running process that gets kicked off from a web application. The website sits on an interstitial page while the backend process runs, similar to what you would see on a travel site when you search for plane tickets. This process is difficult to set up and fairly brittle. Sometimes the backend process fails to start and the web page just spins forever.
  • We added latitude and longitude to our customer database, but now it is a nightmare to try to keep that information up-to-date. When a customer's address changes, there is nothing to make sure the location information is also recalculated. There are dozens of procedures that update the customer address, and not all of them are under our department's control.

If any of these situations has you nodding your head in agreement, I invite you to read on.

NServiceBus will help you to make multiple transactional updates utilizing the principle of eventual consistency so that you do not encounter deadlocks. It will ensure that valuable customer order data is not lost in the deep dark depths of a multi-megabyte log file.

By the end of the book, you'll be able to build systems that can easily scale out, as well as up. You'll be able to reliably perform non-transactional tasks such as calling web services and sending emails. You will be able to easily start up long-running processes in an application server layer, leaving your web application free to process incoming requests, and you'll be able to unravel your spaghetti codebases into a logical system of commands, events, and handlers that will enable you to more easily add new features and version the existing ones.

You could try to do this all on your own by rolling your own messaging infrastructure and carefully applying the principles of service-oriented architecture, but that would be really time consuming. NServiceBus is the easiest solution to solve the aforementioned problems without having to expend too much effort to get it right, allowing you to put your focus on your business concerns, where it belongs.

So if you're ready, let's get started creating an NServiceBus solution.

Getting the code

We will be covering a lot of information very quickly in this article, so if you see something that doesn't immediately make sense, don't panic! Once we have the basic example in place, we will loop back and explain some of the finer points more completely.

There are two main ways to get the NServiceBus code integrated with your project, by downloading the Windows Installer package, and via NuGet. I recommend you use Windows Installer the first time to ensure that your machine is set up properly to run NServiceBus, and then use NuGet to actually include the assemblies in your project.

Windows Installer automates quite a bit of setup for you, all of which can be controlled through the advanced installation options:

  • NServiceBus binaries, tools, and sample code are installed.
  • The NServiceBus Management Service is installed to enable integration with ServiceInsight. .
  • Microsoft Message Queueing ( MSMQ ) is installed on your system if it isn't already. MSMQ provides the durable, transactional messaging that is at the core of NServiceBus.
  • The Distributed Transaction Coordinator ( DTC ) is configured on your system. This will allow you to receive MSMQ messages and coordinate data access within a transactional context.
  • RavenDB is installed, which provides the default persistence mechanism for NServiceBus subscriptions, timeouts, and saga data.
  • NServiceBus performance counters are added to help you monitor NServiceBus performance.

Download the installer from http://particular.net/downloads and install it on your machine. After the install is complete, everything will be accessible from your Start Menu. Navigate to All Programs | Particular Software | NServiceBus as shown in the following screenshot:

The install package includes several samples that cover all the basics as well as several advanced features. The Video Store sample is a good starting point. Multiple versions of it are available for different message transports that are supported by NServiceBus. If you don't know which one to use, take a look at VideoStore.Msmq.

I encourage you to work through all of the samples, but for now we are going to roll our own solution by pulling in the NServiceBus NuGet packages.

NServiceBus NuGet packages

Once your computer has been prepared for the first time, the most direct way to include NServiceBus within an application is to use the NuGet packages.

There are four core NServiceBus NuGet packages:

  • NServiceBus.Interfaces: This package contains only interfaces and abstractions, but not actual code or logic. This is the package that we will use for message assemblies.
  • NServiceBus: This package contains the core assembly with most of the code that drives NServiceBus except for the hosting capability. This is the package we will reference when we host NServiceBus within our own process, such as in a web application.
  • NServiceBus.Host: This package contains the service host executable. With the host we can run an NServiceBus service endpoint from the command line during development, and then install it as a Windows service for production use.
  • NServiceBus.Testing: This package contains a framework for unit testing NServiceBus endpoints and sagas.

The NuGet packages will also attempt to verify that your system is properly prepared through PowerShell cmdlets that ship as part of the package. However, if you are not running Visual Studio as an Administrator, this can be problematic as the tasks they perform sometimes require elevated privileges. For this reason it's best to run Windows Installer before getting started.

Creating a message assembly

The first step to creating an NServiceBus system is to create a messages assembly. Messages in NServiceBus are simply plain old C# classes. Like the WSDL document of a web service, your message classes form a contract by which services communicate with each other.

For this example, let's pretend we're creating a website like many on the Internet, where users can join and become a member. We will construct our project so that the user is created in a backend service and not in the main code of the website.

Follow these steps to create your solution:

  1. In Visual Studio, create a new class library project. Name the project UserService.Messages and the solution simply Example. This first project will be your messages assembly.
  2. Delete the Class1.cs file that came with the class project.
  3. From the NuGet Package Manager Console, run this command to install the NServiceBus.Interfaces package, which will add the reference to NServiceBus.dll.

    PM> Install-Package NServiceBus.Interfaces –ProjectName UserService.Messages

  4. Add a new folder to the project called Commands.
  5. Add a new class to the Commands folder called CreateNewUserCmd.cs.
  6. Add using NServiceBus; to the using block of the class file. It is very helpful to do this first so that you can see all of the options available with IntelliSense.
  7. Mark the class as public and implement ICommand. This is a marker interface so there is nothing you need to implement.
  8. Add the public properties for EmailAddress and Name.

When you're done, your class should look like this:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using NServiceBus; namespace UserService.Messages.Commands { public class CreateNewUserCmd : ICommand { public string EmailAddress { get; set; } public string Name { get; set; } } }

Congratulations! You've created a message! This will form the communication contract between the message sender and receiver. Unfortunately, we don't have enough to run yet, so let's keep moving.

Creating a service endpoint

Now we're going to create a service endpoint that will handle our command message.

  1. Add a new class library project to your solution. Name the project UserService.
  2. Delete the Class1.cs file that came with the class project.
  3. From the NuGet Package Manager Console window, run this command to install the NServiceBus.Host package:

    PM> Install-Package NServiceBus.Host –ProjectName UserService

  4. Take a look at what the host package has added to your class library. Don't worry; we'll cover this in more detail later.
    • References to NServiceBus.Host.exe, NServiceBus.Core.dll, and NServiceBus.dll
    • An App.config file
    • A class named EndpointConfig.cs
  5. In the service project, add a reference to the UserService.Messages project you created before.
  6. Right-click on the project file and click on Properties , then in the property pages, navigate to the Debug tab and enter NServiceBus.Lite under Command line arguments . This tells NServiceBus not to run the service in production mode while we're just testing. This may seem obvious, but this is part of the NServiceBus promise to be safe by default, meaning you won't be able to mess up when you go to install your service in production.
Learning NServiceBus Build reliable and scalable distributed software systems using the industry leading .NET enterprise Service Bus with this book and ebook
Published: August 2013
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

Creating a message handler

Now we will create a message handler within our service.

  1. Add a new class to the service called UserCreator.cs.
  2. Add three namespaces to the using block of the class file:

    using NServiceBus; using NServiceBus.Logging; using UserService.Messages.Commands;

  3. Mark the class as public.
  4. Implement IHandleMessages<CreateNewUserCmd>.
  5. Implement the interface using Visual Studio's tools. This will generate a Handle(CreateNewUserCmd message) stub method.

Normally we would want to create the user here with calls to a database, but we don't have time for that! We're on a mission, so let's just demonstrate what would be happening by logging a message.

It is worth mentioning that a new feature in NServiceBus 4.0 is the ability to use any logging framework you like, without being dependent upon that framework. NServiceBus can automatically hook up to log4net or NLog—just add a reference to either assembly, and NServiceBus will find it and use it. You can even roll your own logging implementation if you wish.

However, it is not required to pick a logging framework at all. NServiceBus internalizes log4net, which it will use (via the NServiceBus.Logging namespace) if you don't explicitly include a logging library. This is what we will be doing in our example.

Now let's finish our fake implementation for the handler:

  1. Above the Handle method, add an instance of a logger:

    private static readonly ILog log =
    LogManager.GetLogger(typeof(UserCreator));

  2. To handle the command, remove NotImplementedException and replace it with:

    log.InfoFormat("Creating user '{0}' with email '{1}'", message.Name, message.EmailAddress);

When you're done, your class should look like this:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using UserService.Messages.Commands; using NServiceBus; namespace UserService { public class UserCreator : IHandleMessages<CreateNewUserCmd> { private static readonly ILog log = LogManager.GetLogger(typeof(UserCreator)); public void Handle(CreateNewUserCmd message) { log.InfoFormat("Creating user '{0}' with email '{1}'", message.Name, message.EmailAddress); } } }

Now we have a command message and a service endpoint to handle it. It's OK if you don't understand quite how it all connects quite yet. Next we need to create a way to send the command.

Sending a message from an MVC application

An ASP.NET MVC web application will be the user interface for our system. It will be sending a command to create a new user to the service layer, which will be in charge of processing it. Normally this would be from a user registration form, but in order to keep the example to the point, we'll take a shortcut and enter the information as query string parameters, and return data as JSON.

Because we will be viewing JSON data directly within a browser, it would be a good idea to make sure your browser supports displaying JSON directly instead of downloading it.

Firefox and Chrome natively display JSON data as plain text, which is readable but not very useful. Both browsers have an extension available called JSONView (although they are unrelated) which allows you to view the data in a more readable, indented format. Either of these options will work fine, so you can use whichever browser you prefer.

Beware that Internet Explorer will try to download JSON data to a file, which makes it cumbersome to view the output.

Creating the MVC website

First, follow these directions to get the MVC website set up. You can use either MVC 3 or MVC 4, but for the example we will be using MVC 3.

  1. Add a new ASP.NET MVC project to your solution and name it ExampleWeb. Select the Empty template and the Razor view engine.
  2. From the NuGet Package Manager Console , run this command to install the NServiceBus package:

    PM> Install-Package NServiceBus –ProjectName ExampleWeb

  3. Add a reference to the UserService.Messages project you created before.

Because the MVC project isn't fully controlled by NServiceBus, it is a little more involved to set up.

First, create a class file within the root of your MVC application and name it ServiceBus.cs, then fill it with this code. For the moment, don't worry about what it does.

using System; using System.Collections.Generic; using System.Linq; using System.Web; using NServiceBus; using NServiceBus.Installation.Environments; namespace ExampleWeb { public static class ServiceBus { public static IBus Bus { get; private set; } public static void Init() { if (Bus != null) return; lock (typeof(ServiceBus)) { if (Bus != null) return; Bus = Configure.With() .DefineEndpointName("ExampleWeb") .DefaultBuilder() .UseTransport() .PurgeOnStartup(true) .UnicastBus() .CreateBus() .Start(() => Configure.Instance .ForInstallationOn() .Install()); } } } }

That was certainly a mouthful! Don't worry about remembering all this; it's part of a fluent API that makes it pretty easy to discover things you need to configure through IntelliSense.

For now, suffice it to say that this is the code that initializes the service bus within our MVC application, and provides access to a single static instance of the IBus interface that we can use to access the service bus. If we were to compare the service bus to Ethernet (which is a fairly apt comparison) we have just detailed how to turn on the Ethernet card.

Now we need to call the Init() method from our Global.asax.cs file so that the Bus property is initialized when the application starts up.

protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); ServiceBus.Init(); }

Now NServiceBus has been set up to run in the web application, so we can send our message. Create a HomeController class and add these methods to it:

public ActionResult Index() { return Json(new { text = "Hello world." }); } public ActionResult CreateUser(string name, string email) { var cmd = new CreateNewUserCmd { Name = name, EmailAddress = email }; ServiceBus.Bus.Send(cmd); return Json(new { sent = cmd }); } protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior) { return base.Json(data, contentType,
contentEncoding, JsonRequestBehavior.AllowGet); }

The first and last methods aren't too important. The first returns some static JSON for the /Home/Index action because we aren't going to bother adding a view for it. The last one is for convenience to make it easier to return JSON data as a result of an HTTP GET request.

The highlighted method is the important one—this is where we create an instance of our command class and send it on the bus via the static instance ServiceBus.Bus. Lastly we return the command to the browser as JSON data so that we can see what we created.

The last step is to add some NServiceBus configuration to the MVC application's Web.config file. We need to add two configuration sections. We already saw MessageForwardingInCaseOfFaultConfig in the app.config file that NuGet added to the service project, so we can copy it from there. However we need to add a new section called UnicastBusConfig anyway, so the XML for both is included here for convenience:

<configuration> <configSections> <section name="MessageForwardingInCaseOfFaultConfig"
type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig,
NServiceBus.Core" /> <section name="UnicastBusConfig"
type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" /> </configSections> <MessageForwardingInCaseOfFaultConfig ErrorQueue="error" /> <UnicastBusConfig> <MessageEndpointMappings> <add Messages="UserService.Messages" Endpoint="UserService" /> </MessageEndpointMappings> </UnicastBusConfig> <!-- Rest of Web.config --> </configuration>

The first highlighted line determines what happens to a message that fails. The second highlighted line determines routing for messages. For now it is sufficient to say that it means that all messages found in the UserService.Messages assembly will be sent to the UserService endpoint, which is our service project.

NServiceBus also includes PowerShell cmdlets that make it a lot easier to add these configuration blocks. You could generate these sections using the Add-NServiceBusMessageForwardingInCaseOfFaultConfig cmdlet and the Add-NServiceBusUnicastBusConfig cmdlet.

Running the solution

One thing that will be useful when developing NServiceBus solutions is being able to specify multiple startup projects for a solution.

  1. In the Solution Explorer , right-click on the solution file and click on Properties .
  2. On the left, navigate to Common Properties | Startup Project .
  3. Select the Multiple startup projects radio button.
  4. Set the Action for the service project and the MVC project to Start and order them so that the MVC project starts last.
  5. Click on OK .

Now, build the solution if you haven't already, and assuming there are no compilation errors, click on the Start Debugging button or press F5 .

So what happens now? Let's take a look.

When you run the solution, both the MVC website and a console window should appear as shown in the preceding screenshots. As we can see, the browser window isn't terribly exciting right now; it's just showing the JSON results of the /Home/Index action. The console window is far more interesting.

If you remember, we never created a console application; our service endpoint was a class project. When we included the NServiceBus.Host NuGet package, a reference to NServiceBus.Host.exe was added to the class project (remember a .NET executable is also an assembly that can be referenced) and the project was set to run that executable when you debug it.

While it might not be easy to see in the screenshot, NServiceBus uses different colors to log messages of different levels of severity. In the screenshot, INFO messages are logged in green, and WARN messages are displayed in yellow. In addition, there can be DEBUG messages displayed in white, or ERROR and FATAL messages which are both logged in red. By default, the INFO log level is used for display, which is filtering out all the DEBUG messages here, and luckily we don't have any ERROR or FATAL messages!

The entire output is too much to show in a screenshot. It's worth reading through, even though you may not understand everything that's going on quite yet. Here are some of the important points:

  • NServiceBus reports how many total message types it has found. In my example, four messages were found. Only one of those is ours; the rest are administrative messages used internally by NServiceBus. If this had said zero messages were found, that would have been distressing!
  • The License Manager checks for a valid license. You can get a free developer license that allows unrestricted non-production use for 90 days. At the end of that, you can get a new one for another 90 days. For all licensing concerns, go to http://particular.net/licensing.
  • The status of several features is listed for debugging purposes.
  • NServiceBus checks for the existence of several queues, and creates them if they do not exist. In fact, if we go to the Message Queuing manager, we will see that the following private queues have now been created:
    • audit
    • error
    • exampleweb
    • exampleweb.retries
    • exampleweb.timeouts
    • exampleweb.timeoutdispatcher
    • userservice
    • userservice.retries
    • userservice.timeouts
    • userservice.timeoutsdispatcher

That's a lot of plumbing that NServiceBus takes care of for us! But this just gets the endpoint ready to go. We still need to send a message!

Visual Studio will likely give you a different port number for your MVC project than in the example, so change the URL in your browser to the following, keeping the host and port the same. Feel free to use your own name and email address:

/Home/CreateUser?name=David&email=david@example.com

Look at what happens in your service window:

INFO UserService.UserCreator [(null)] <(null)> -
Creating user 'David' with email 'david@example.com'

This might seem simple, but consider what had to happen for us to see this message. First, in the MVC website, an instance of our message class was serialized to XML, and then that payload was added to an MSMQ message with enough metadata to describe where it came from and where it needed to go. The message was sent to an input queue for our background service, where it waited to be processed until the service was ready for it. The service pulled it off the queue within a transaction, deserialized the XML payload, and was able to determine a handler that could process the message. Finally, our message handler was invoked, which resulted in the message being output to the log.

This is a great start, but there is a great deal more to discover.

Summary

In this article, we created an MVC web application and an NServiceBus hosted service endpoint. Through the web application, we sent a command to the service layer to create a user, where we just logged the fact that the command was received, but in real life we would likely perform database work to actually create the user. For our example, our service was running on the same computer, but our command could just as easily be sent to a different server, enabling us to offload work from our web server.

Resources for Article :


Further resources on this subject:


Learning NServiceBus Build reliable and scalable distributed software systems using the industry leading .NET enterprise Service Bus with this book and ebook
Published: August 2013
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

About the Author :


David Boike

David Boike is a Principal Consultant with ILM Professional Services with more than a decade of development experience in ASP.NET and related technologies and has been an avid proponent of NServiceBus since Version 2.0 in 2010. He is also an alumnus of Udi Dahan's Advanced Distributed Systems Design course. David resides in the Twin Cities with his wife and daughter. He can be found on Twitter at @DavidBoike and on his blog at http://www.make-awesome.com.

Books From Packt


Instant RabbitMQ Messaging Application Development How-to [Instant]
Instant RabbitMQ Messaging Application Development How-to [Instant]

Scribus 1.3.5: Beginner's Guide
Scribus 1.3.5: Beginner's Guide

Drools Developer’s Cookbook
Drools Developer’s Cookbook

Oracle Service Bus 11g Development Cookbook
Oracle Service Bus 11g Development Cookbook

Learning JavaScriptMVC
Learning JavaScriptMVC

 web2py Application Development Cookbook
web2py Application Development Cookbook

 ASP.NET MVC 1.0 Quickly
ASP.NET MVC 1.0 Quickly

 ZeroMQ
ZeroMQ


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
x
5
t
p
Y
3
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software