NServiceBus Home

Contents

  • Long-Running Processes
  •     Sagas

Using NServiceBus in a Web Application

In order to see how to use NServiceBus in a WebForms application, open up the AsyncPages sample.

First of all run the solution - a new browser window/tab should open up, as well as a console application. Enter the number "1" into the text box in the browser, and click "Go". You should see the result "None" appear, as shown below:

AsyncPages sample running

Changing the number in the text box from even to odd numbers changes the result.

One thing to notice is that the web page renders synchronously - from the user's perspective, the interaction is synchronous and blocking, even though behind the scenes NServiceBus is doing asynchronous messaging.

AsyncPages sample

Now let's take a look into the code:

In this sample, there are 3 projects - Messages, Server, and WebApplication1. WebApplication1 is a web application that will send messages (found in the Messages project) to the Server project, which is hosted as a console application.

Initializing the bus

In WebApplication1 open up Global.asax.cs and look at the Application_Start method. In there you'll see the following code:

Bus = NServiceBus.Configure.WithWeb()
    .Log4Net()
    .DefaultBuilder()
    .XmlSerializer()
    .MsmqTransport()
        .IsTransactional(false)
        .PurgeOnStartup(false)
    .UnicastBus()
        .ImpersonateSender(false)
    .CreateBus()
    .Start();

This code, by calling "WithWeb()" indicates to NServiceBus that it should scan the directory where the web application is deployed (which is different than non-web applications).

The rest of the code above is quite standard when hosting NServiceBus in your own process. You can read more about the other lines here.

Notice that we're holding on to a reference of the bus - this will be used later for the purposes of sending messages. This isn't the only option available - if the classes that you'll be using to send messages are managed by Dependency Injection, then they can get a reference to the bus by declaring a dependency on IBus. You can see an example of this here.

Sending a message

Now open up Default.aspx.cs in WebApplication1. In there you'll see the method Button1_Click with the following code:

int number = int.Parse(TextBox1.Text);
var command = new Command { Id = number };

Global.Bus.Send(command).Register<ErrorCodes>(
    code => Label1.Text = Enum.GetName(typeof (ErrorCodes), code)
    );

The first line of code is simply parsing the text passed in by the user. The second line is creating a new NServiceBus message of the type "Command", and initializing its "Id" property with the value from the text box.

Let's open up the class definition for the Command type in the Messages project:

[Serializable]
public class Command : IMessage
{
    public int Id { get; set; }
}

As you can see, this class is very simple - the only special thing about it is the IMessage interface that its implementing. This interface comes from NServiceBus and indicates that instances of this class can be sent and received by the bus. The IMessage interface itself is empty - a marker interface. For more information on defining messages, see here.

Now go back to Default.aspx.cs and look at the code "Global.Bus.Send(command)".

Global.Bus is referencing the Bus property of the Global class, which we saw previously in Global.asax.cs. Then we're calling the Send method passing in the "command" object we just created.

The "bus" isn't anything special in code - it's just an object you call methods on.

For now we're going to skip over the rest of the code and see what happens to the message we just sent.

Routing Configuration

Now open up the web.config file in WebApplication1, and scroll down until you see the following:

<MsmqTransportConfig InputQueue="MyWebClient" ErrorQueue="error" 
                     NumberOfWorkerThreads="1" MaxRetries="5"/>
<UnicastBusConfig>
    <MessageEndpointMappings>
        <add Messages="Messages" Endpoint="MyServerInputQueue"/>
    </MessageEndpointMappings>
</UnicastBusConfig>

There are 2 configuration sections we're looking at: MsmqTransportConfig and UnicastBusConfig.

For information on MsmqTransportConfig, click here.

The UnicastBusConfig section describes which messages should be sent to which queue. In the configuration above, we see that all messages belonging to the "Messages" assembly should be sent to MyServerInputQueue.

If you go and open the app.config file of the Server project, you'll see that the InputQueue property of its MsmqTransportConfig section is also "MyServerInputQueue":

<MsmqTransportConfig InputQueue="MyServerInputQueue" ErrorQueue="error" 
                     NumberOfWorkerThreads="1" MaxRetries="5"/>

This is how routing is configured in NServiceBus. In this case, the routing is configuring a request/response interaction rather than a publish/subscribe interaction, but later you'll see that the same configuration holds for all kinds of interactions.

Handling the message

In the Server project, open the CommandMessageHandler class - in it you'll see the following:

public class CommandMessageHandler : IHandleMessages<Command>
{
    public IBus Bus { get; set; }

    public void Handle(Command message)
    {
        Console.WriteLine("=================================================");

        Thread.Sleep(TimeSpan.FromSeconds(1));

        if (message.Id % 2 == 0)
            Bus.Return(ErrorCodes.Fail);
        else 
            Bus.Return(ErrorCodes.None);
    }
}

This class implements the NServiceBus interface "IHandleMessages<T>" where T is the specific message type being handled - in this case, the Command message.

Classes the implement this interface are managed by NServiceBus. When a message arrives in the input queue, it is deserialized and then, based on its type, NServiceBus instantiates the relevant classes and calls their "Handle" method - passing in the message object.

Notice the IBus property of the class - that's how it gets a reference to the bus. In the method body you can see it calling the Return method on the bus - this results in a message being sent back to WebApplication1, specifically putting a message in its input queue "MyWebClient".

Handling the Response

When the response arrives back at WebApplication1, the bus invokes the callback that was registered when the request was sent by this code:

int number = int.Parse(TextBox1.Text);
var command = new Command { Id = number };

Global.Bus.Send(command).Register<ErrorCodes>(
    code => Label1.Text = Enum.GetName(typeof (ErrorCodes), code)
    );

The method "Register" takes the callback code and tells the bus to invoke it when the response is received. There are several overloads to this method - the above accepts a generic Enum parameter, effectively casting the return code from the server to the given enum.

Finally, the code above updates the Text property of a label on the web page, setting it to the string that represents the enum value - sometimes "None", sometimes "Fail".

Legal

“NServiceBus” is among the trademarks of NServiceBus Ltd. All other product and company names and marks mentioned are the property of their respective owners and are mentioned for identification purposes only.

© 2010-2012 NServiceBus Ltd. All rights reserved.