Contents
|
Using NServiceBus with ASP MVC3In order to see how to use NServiceBus in an Asp.Net Mvc3 application, open up the AsyncPagesMvc3 sample.
One thing to notice in the SendAndBlock 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.
Choosing SendAsync brings the following page:
Changing the number in the text box from even to odd numbers changes the result.
Now let's take a look into the code: In this sample, there are 3 projects:
Initializing the busThe samples' controllers holding on to a reference of the bus - this will be used later for the purposes of sending messages and receiving a response. In AsyncPagesMvc3 open up Global.asax.cs and look at the Application_Start method. In there you'll see the following code:
Configure.WithWeb()
.AsMasterNode()
.DefaultBuilder()
.ForMvc()
.Log4Net()
.XmlSerializer()
.MsmqTransport()
.IsTransactional(false)
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.CreateBus()
.Start(() => Configure.Instance.
ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
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 .ForMvc extension method is responsible to inject IBus into the controllers. It does this by implementing the Mvc3 interfaces IDependencyResolver and IControllerActivator. NServiceBus builder is utilized to register and instantiate IControllerActivator so when the controllers will be requested, the NServiceBus builder will have the opportunity to inject IBus implementation into their IBus public property. For more information on how the IBus is injected into the controllers please read here and also in David Boike's article: Injecting NServiceBus into ASP.NET MVC 3. 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. Sending a messageAsynchronous message sending - SendAsync controllerOpen SendAsyncController class: 1: var command = new Command { Id = number }; 2: Bus.Send(command).Register<int>(status=> 3: {AsyncManager.Parameters["errorCode"] = Enum.GetName(typeof(ErrorCodes), status);});
At line 1 a new NServiceBus message of the type "Command", and initializing its "Id" property with the value from the text box.
Bus.Return(ErrorCodes.Fail);
Or
Bus.Return(ErrorCodes.None);
Depending if the Command Id is an even or odd number. 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. Beginning NServiceBus 3, it is possible to send messages without implementing NServiceBus marker interfaces, please see Unobtrusive message and the accompanying sample. Synchronous message sending - SendAndBlockController controllerOpen SendAndBlockController class:
Bus.Send(command).Register(SimpleCommandCallback, this);
The controller is referencing it's IBus (that was injected when the controller was instantiated, by NServiceBus). We are calling the
send method passing in the "command" object we just created.
Routing ConfigurationNow open up the web.config file in AsyncPagesMvc3, and scroll down until you see the following: <MsmqTransportConfig ErrorQueue="error" NumberOfWorkerThreads="1" MaxRetries="5"/> <UnicastBusConfig> <MessageEndpointMappings> <add Messages="Messages" Endpoint="Server"/> </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 a queue named "Server". At Server project, the queue name equals to the namespace of the MessageEndpoint class, that is, "Server". 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 messageIn 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 which is name is determined by the namespace where the bus was configured in this case, in the global.asax: "AsyncPagesMVC3". Where to go next?If you are not familiar with Unobtrusive messaging mode, read the documentation here or see the working sample here. |