This sample consists of a web application hosting MVC controllers and a console application hosting the NServiceBus endpoint. The web application sends a command to the endpoint, waits for a response, and returns the result to the user. The Web application shows two methods for sending commands:
SendAndBlock
: a method in synchronousController
classSendAsync
: a method in asynchronousAsyncController
class
In SendAndBlock
, the web page renders synchronously. From the user's perspective, the interaction is synchronous and blocking, even though behind the scenes NServiceBus is messaging asynchronously.
After running, the web application renders the following page:
Choosing SendAsync results in the following page:
Changing the number in the text box from even to odd changes the result.
Structure
The solution in the sample consists of three projects:
AsyncPagesMvc
: ASP.NET Core MVC application that sends messagesShared
: Common code including messages types definitionsServer
: Destination of messages sent from the MVC project. Hosted in a console application
Initializing NServiceBus
In AsyncPagesMvc
, open Program.
and see the code for the UseNServiceBus
method:
var builder = WebApplication.CreateBuilder();
builder.Host.UseNServiceBus(context =>
{
var endpointConfiguration = new EndpointConfiguration("Samples.Mvc.WebApplication");
endpointConfiguration.MakeInstanceUniquelyAddressable("1");
endpointConfiguration.EnableCallbacks();
endpointConfiguration.UseTransport(new LearningTransport());
return endpointConfiguration;
});
Sending a message
Asynchronous controller
Using AsyncController
:
var command = new Command
{
Id = number
};
var sendOptions = new SendOptions();
sendOptions.SetDestination("Samples.Mvc.Server");
var status = await messageSession.Request<ErrorCodes>(command, sendOptions);
return IndexCompleted(Enum.GetName(typeof(ErrorCodes), status));
Synchronous controller
Open the SendAndBlockController
class:
var command = new Command
{
Id = number
};
var sendOptions = new SendOptions();
sendOptions.SetDestination("Samples.Mvc.Server");
var status = messageSession.Request<ErrorCodes>(command, sendOptions).GetAwaiter().GetResult();
return IndexCompleted(Enum.GetName(typeof(ErrorCodes), status));
The controller is sending a command using an instance of IMessageSession
injected into the constructor. The Request
method is called, passing in the newly created command instance.
The Request
method returns once a response from the handler is received.
Handling the message
In the Server project, open the CommandMessageHandler
class to see the following:
public class CommandMessageHandler :
IHandleMessages<Command>
{
static ILog log = LogManager.GetLogger<CommandMessageHandler>();
public Task Handle(Command message, IMessageHandlerContext context)
{
log.Info("Hello from CommandMessageHandler");
Task reply;
if (message.Id % 2 == 0)
{
log.Info("Returning Fail");
reply = context.Reply(ErrorCodes.Fail);
}
else
{
log.Info("Returning None");
reply = context.Reply(ErrorCodes.None);
}
return reply;
}
}
CommandMessageHandler
implements the NServiceBus interface IHandleMessages
where T
is the message type being handled, in this case, the Command
message.
When a message arrives in the input queue it is deserialized and then, based on its type, NServiceBus instantiates the relevant IHandleMessages
implementations and calls their Handle
methods passing in the message object and the context object.
Notice in the method body the response is being returned to the originating endpoint. This will result in the message being added to the input queue of the AsyncPagesMVC
endpoint.