Getting Started with NServiceBus

March 13, 2024#Software Development
Series: NServiceBus
Article
Author image.

Kyle McMaster, Senior Consultant

This post is the second in a series on NServiceBus. In the previous article, we looked at What is NServiceBus. In this article, we will look at how to get started with NServiceBus in .NET 8. All code for this article can be found in the NServiceBusTutorial repository on GitHub.

Prerequisites 📝

For this tutorial, we will use the Ardalis CleanArchitecture template. It’s worth noting that you do not need to use this template to use NServiceBus. But it is a good starting point for building a .NET application and our sample domain will be based on the entities and actions found in that solution. You can find the project template here or install it as a dotnet CLI template using the following command:

dotnet new install Ardalis.CleanArchitecture.Template::9.1.2

Then, in a new directory, run:

dotnet new clean-arch -o NServiceBusTutorial

This will give you a new solution with a few projects and a sample domain. You can find more information about the template and its structure in the Ardalis.CleanArchitecture README. For this tutorial, this project will give us a .NET web application with CRUD functionality for a Contributor entity which we can use to demonstrate how NServiceBus can be used to send and receive messages. Let’s dive right into sending an event when a new Contributor is added to the system.

The sample applications we’ll be building in this project will be a .NET web application and a .NET worker service. The web application will be used to send a message when a new Contributor is added to the system, and the worker service will be used to receive the message. Below is a simple architecture diagram of the applications and the queue between them.

Tutorial Architecture Diagram

Adding NServiceBus to the Project ➕

To add NServiceBus to the project, we will use the NServiceBus NuGet package. You can find the latest version of the package on NuGet. To add the package to the project, run the following command at the root of the solution:

dotnet add src/NServiceBusTutorial.Core/NServiceBusTutorial.Core.csproj package NServiceBus --version 8.1.6

This will add the NServiceBus package to the Core project. The Core project is where we will define our messages so that they can be shared between the web application and the endpoint that will process the messages. There is a noteworthy tradeoff taking a dependency on NServiceBus in the Core project. It will allow us to share the message definitions between the sending and receiving endpoints, but it will also mean that the Core project will have a dependency on NServiceBus. In larger applications or projects that span multiple repositories, you may move this shared message contract to a library that many projects can consume. This is a tradeoff that you will need to consider when designing your application. For this tutorial, we will take the tradeoff and add the NServiceBus package to the Core project.

Defining a Message 📨

In the Core project, we will define a message that will be sent when a new Contributor is added to the system. We will call this message ContributorCreated. We will define the message as a class that implements the IMessage interface from the NServiceBus package. The IMessage interface is a marker interface that is used to identify a class as a message. The message will contain the ContributorId, Name, and Status of the new Contributor. The message will look like this:

public class ContributorCreatedEvent : IMessage
{
  public Guid ContributorId { get; init; }
  public string Name { get; init; }
  public string Status { get; init; }
}

That’s it, we’ve defined our first NServiceBus message! Now, let’s send this message when a new Contributor is added to the system.

Configuring The Web Project Endpoint 🌐

To configure the NServiceBusTutorial.Web project as an endpoint, we will need to add the NServiceBus.Extensions.Hosting NuGet package.

dotnet add src/NServiceBusTutorial.Web/NServiceBusTutorial.Web.csproj package NServiceBus.Extensions.Hosting --version 2.0.0

In the Program.cs file in NServiceBusTutorial.Web we will register NServiceBus and its dependencies with our application. Typically, you will register the routing of messages, the transport mechanism for your persistence of messages, and additional NServiceBus configuration in this method. For this tutorial, our configuration is relatively simple. We set up a simple send-only endpoint using LearningTransport, define a route for a single message, and enable installers to create the necessary infrastructure for our endpoint.

builder.Host.UseNServiceBus(_ =>
{
  var endpointConfiguration = new EndpointConfiguration("contributors-api");
  
  var transport = endpointConfiguration.UseTransport<LearningTransport>();

  transport.Routing().RouteToEndpoint(
    typeof(ContributorCreatedEvent),
    "contributors-worker");

  endpointConfiguration.SendOnly();
  endpointConfiguration.EnableInstallers();

  return endpointConfiguration;
});

A Quick Note on the Learning Transport 🧠

In this tutorial, we are using the Transport, LearningTransport, which is an abstraction for defining the underlying persistence and queueing technology for your messages. LearningTransport is a Transport that is included with NServiceBus and is used for development and testing. It is not recommended for production use. We’ll revisit how Learning Transport works in a future article. For now, it is sufficient to know that it is a file system-based Transport that can be used to send and receive messages in a development environment. These messages will be written to the root of the repository in a folder called .learningtransport.

Sending a Message 📤

In the UseCases layer, we will send the ContributorCreatedEvent message when a new Contributor is added to the system. We will inject the IMessageSession interface into the CreateContributorHandler and use it to send the ContributorCreatedEvent message. The IMessageSession is NServiceBus’s interface for sending messages outside the context of a message handler (which we’ll see in a bit). The CreateContributorHandler will look like this:

var newContributor = new Contributor(request.Name, phoneNumber, ContributorStatus.NotSet);
var createdItem = await _repository.AddAsync(newContributor, cancellationToken);

var message = new ContributorCreatedEvent
{
  ContributorId = createdItem.Id,
  Name = createdItem.Name,
  Status = createdItem.Status.ToString()
};
await _messageSession.Send(message, cancellationToken);

return createdItem.Id;

That’s it! We are now able to send our first NServiceBus message This should look familiar if you’ve used a package like MediatR or an equivalent, with the difference that NServiceBus messages are being sent out of process and not in-process in this example. Now, let’s set up a .NET worker service to receive the message.

Setting Up a Worker Service Endpoint 🛠️

Now that our code to send a message is in place, we will set up a new endpoint to receive the message in a .NET worker service. First, we’ll create a new project called NServiceBusTutorial.Worker using the following command:

dotnet new worker -n NServiceBusTutorial.Worker -o src/NServiceBusTutorial.Worker

Then, we will add the project to our Solution file using the following command:

dotnet sln add src/NServiceBusTutorial.Worker/NServiceBusTutorial.Worker.csproj

Next, we will add the NServiceBus.Extensions.Hosting NuGet package to the NServiceBusTutorial.Worker project just like we did for the NServiceBusTutorial.Web project.

dotnet add src/NServiceBusTutorial.Worker/NServiceBusTutorial.Worker.csproj package NServiceBus.Extensions.Hosting --version 2.0.0

We can delete the Worker.cs file that was created by default as we won’t be using it. Then, we’ll update the contents of the Program.cs file to configure the Worker’s IHost as an endpoint. Similar to the NServiceBusTutorial.Web project, we will call the UseNServiceBus method but our endpoint will be the receiving name for the route we configured in the previous Transport. We’ll again use LearningTransport for this demo. The Program.cs file will look like this:

using NServiceBus;

var builder = Host.CreateDefaultBuilder();

builder.UseConsoleLifetime();
builder.UseNServiceBus(context => 
{
  var endpointConfiguration = new EndpointConfiguration("contributors-worker");
  endpointConfiguration.UseTransport<LearningTransport>();

  return endpointConfiguration;
});

var host = builder.Build();
host.Run();

This is all that is needed to set up our worker Service as an endpoint that can send and receive messages. Now, let’s create a message handler to process the ContributorCreatedEvent message.

Creating a Message Handler 📭

In the NServiceBusTutorial.Worker project, we will create a new class called ContributorCreatedEventHandler that will implement the IHandleMessages<ContributorCreatedEvent> interface. This interface is used to identify a class as a message handler for the ContributorCreatedEvent message. NServiceBus will register this detect and register this handler automagically 🪄 so there is no need to do any manual configuration for this class. For this sample, we will simply log that we received the message and the Id of the Contributor from the message body.

public class ContributorCreatedEventHandler(ILogger<ContributorCreatedEventHandler> logger) 
  : IHandleMessages<ContributorCreatedEvent>
{
  private readonly ILogger<ContributorCreatedEventHandler> _logger = logger;

  public Task Handle(ContributorCreatedEvent message, IMessageHandlerContext context)
  {
    _logger.LogInformation("Received {EventName} for {ContributorId}",
      nameof(ContributorCreatedEvent),
      message.ContributorId);
    return Task.CompletedTask;
  }
}

That’s it! We are now able to receive our first NServiceBus message. We have set up a default IHost as a worker service to receive the ContributorCreatedEvent message and log the Contributor’s Id. Now, let’s run the application and see it in action.

Running the Application 🏃‍♂️

Below is a gif that shows two console outputs from the NServiceBusTutorial.Web and NServiceBusTutorial.Worker projects. The bottom console output shows the NServiceBusTutorial.Web project running which receives a POST request which creates a Contributor and sends the ContributorCreatedEvent. The top console output shows the NServiceBusTutorial.Worker project receiving the ContributorCreatedEvent message and logging the ContributorId when it is received.

Output of the sample application be executed

Conclusion 🎬

In this article, we looked at how to get started with NServiceBus in .NET 8. We added the NServiceBus package to the Core project and defined a message that will be sent when a new Contributor is added to the system. We then configured the NServiceBusTutorial.Web project as an endpoint and sent the ContributorCreatedEvent message when a new Contributor is added to the system. We then set up a new endpoint in the NServiceBusTutorial.Worker project to receive the ContributorCreatedEvent message and log the ContributorId when it is received. In the next article, we will look at different types of messages like commands and events, the differences in how they are sent and received, and some small changes we can make to our code to reflect these differences.

Resources 🤓


Copyright © 2024 NimblePros - All Rights Reserved