Using NServiceBus in a ASP.NET Web Application


NuGet packages

6-pre NServiceBus
5.x NServiceBus
4.x NServiceBus
This topic contains pre-release documentation (for Version 6-pre) and is subject to change prior to the final release.

Run the solution, a new browser window/tab opens, as well as a console application.

Enter the number "1" into the text box in the browser, and click "Go". Notice the result "None" appear, as shown:

AsyncPages sample running

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

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.

This sample has three projects: Shared, Server, and WebApplication. WebApplication is a web application that sends messages (found in the Shared project) to the Server project, which is hosted as a console application.

Initializing the bus

In WebApplication, open Global.asax.cs and look at the code in the ApplicationStart method:

6-pre NServiceBus
EndpointConfiguration endpointConfiguration = new EndpointConfiguration("Samples.AsyncPages.WebApplication");
endpointConfiguration.ScaleOut()
    .InstanceDiscriminator("1");
endpointConfiguration.UseSerialization<JsonSerializer>();
endpointConfiguration.EnableInstallers();
endpointConfiguration.UsePersistence<InMemoryPersistence>();

Endpoint = NServiceBus.Endpoint.Start(endpointConfiguration).GetAwaiter().GetResult();
5.x NServiceBus
BusConfiguration busConfiguration = new BusConfiguration();
busConfiguration.EndpointName("Samples.AsyncPages.WebApplication");
busConfiguration.UseSerialization<JsonSerializer>();
busConfiguration.EnableInstallers();
busConfiguration.UsePersistence<InMemoryPersistence>();

Bus = NServiceBus.Bus.Create(busConfiguration).Start();
4.x NServiceBus
Configure.Serialization.Json();
Configure configure = Configure.With();
configure.Log4Net();
configure.DefineEndpointName("Samples.AsyncPages.WebApplication");
configure.DefaultBuilder();
configure.UseTransport<Msmq>();
configure.InMemorySagaPersister();
configure.UseInMemoryTimeoutPersister();
configure.InMemorySubscriptionStorage();
Bus = configure.UnicastBus()
    .CreateBus()
    .Start(() => configure.ForInstallationOn<Windows>().Install());
3.x NServiceBus
Configure configure = Configure.With();
configure.Log4Net();
configure.DefineEndpointName("Samples.AsyncPages.WebApplication");
configure.DefaultBuilder();
configure.JsonSerializer();
configure.MsmqTransport();
Bus = configure.UnicastBus()
    .CreateBus()
    .Start(() => configure.ForInstallationOn<Windows>().Install());

The rest of the code is typical for hosting NServiceBus in the process. The code holds a reference to the bus, which is used later for sending messages. This isn't the only option available; if the classes for sending messages are managed by Dependency Injection, then they can get a reference to the bus by declaring a appropriate dependency. See an example.

Sending a message

Open Default.aspx.cs in WebApplication to see the Button1Click method:

6-pre NServiceBus
int number;
if (!int.TryParse(TextBox1.Text, out number))
{
    return;
}
Command command = new Command
                {
                    Id = number
                };

SendOptions sendOptions = new SendOptions();
sendOptions.SetDestination("Samples.AsyncPages.Server");

ErrorCodes code = await Global.Endpoint.Request<ErrorCodes>(command, sendOptions);
Label1.Text = Enum.GetName(typeof(ErrorCodes), code);
int number;
if (!int.TryParse(TextBox1.Text, out number))
{
    return;
}
Command command = new Command
                {
                    Id = number
                };

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

The first line of code parses the text passed in by the user. The second line creates a new NServiceBus message of the type Command, and initializes its Id property with the value from the text box.

Open the class definition for the Command type in the Shared project:

6-pre NServiceBus
public class Command : IMessage
{
    public int Id { get; set; }
}
public class Command : IMessage
{
    public int Id { get; set; }
}

Return to Default.aspx.cs and look at the code Global.Bus.Send(command). Global.Bus references the Bus property of the Global class in Global.asax.cs. Then the code calls the Send method, passing in the newly created command object.

The "bus" isn't anything special in code; it is just an object for calling methods.

Skip the rest of the code and see what happens to the message just sent.

Handling the message

In the Server project, find this code in the CommandMessageHandler class:

6-pre NServiceBus
public class CommandMessageHandler : IHandleMessages<Command>
{
    static ILog log = LogManager.GetLogger<CommandMessageHandler>();

    public async Task Handle(Command message, IMessageHandlerContext context)
    {
        log.Info("Hello from CommandMessageHandler");

        if (message.Id % 2 == 0)
        {
            await context.Reply(ErrorCodes.Fail);
        }
        else
        {
            await context.Reply(ErrorCodes.None);
        }
    }
}
5.x NServiceBus
public class CommandMessageHandler : IHandleMessages<Command>
{
    static ILog log = LogManager.GetLogger<CommandMessageHandler>();
    IBus bus;

    public CommandMessageHandler(IBus bus)
    {
        this.bus = bus;
    }

    public void Handle(Command message)
    {
        log.Info("Hello from CommandMessageHandler");

        if (message.Id%2 == 0)
        {
            bus.Return(ErrorCodes.Fail);
        }
        else
        {
            bus.Return(ErrorCodes.None);
        }
    }
}
3.x - 4.x NServiceBus
public class CommandMessageHandler : IHandleMessages<Command>
{

    static ILog log = LogManager.GetLogger(typeof(CommandMessageHandler));
    IBus bus;

    public CommandMessageHandler(IBus bus)
    {
        this.bus = bus;
    }

    public void Handle(Command message)
    {
        log.Info("Hello from CommandMessageHandler");

        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. NServiceBus manages classes that implement this interface. 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.

In the method body notice the response being returned to the originating endpoint. This will result in a message being added to the input queue for MyWebClient.

Handling the response

When the response arrives back at WebApplication, the bus invokes the callback that was registered when the request was sent.

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

Finally, the code 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.

Related Articles


Last modified 2016-04-18 00:37:52Z