Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Learn NServiceBus from .NET Core WebAPI

4.96/5 (12 votes)
13 Aug 2018CPOL5 min read 30.8K  
Convert an existing .NET Core WebAPI application to NServiceBus

Introduction

NServiceBus can be used in many different configurations; it is like a Swiss army knife when it comes to configuration possibilities. A good way to learn new things is to base the learning on what you already know. I thought a good way to learn how to use NServiceBus is to use it in a .NET Core web application that I already know well. My plan was to take an existing web API application and replace the web API interface with the NServiceBus, and keeping the rest. The user should not see any difference, the GUI and functionality should be the same.

Since .NET Core is a rather new release, there is some new stuff to learn. A very good document for learning .NET Core is this one.

WebAPI Project

I used an application for administration of company vehicles that I had developed just for fun a while ago. It consists of two projects working in a client/server configuration. They are both standard solutions from Visual Studio and based on C# MVC WebAPI Core 2.0. The server, called CarAPI, has two SQLite databases, Car.db and AspNet.db. The client, called CarClient, is a web GUI communicating with the server over RESTFul http.

Tests

There are no unit tests in the final solution. However, in order to enable tests, dependency injection, DI, is used during initialization of the client and the server. The server uses Autofac and the client the .NET Core built in DI features.

Clean Code

I have tried to follow most of the principles for Clean Code when writing these applications. Here is a good summary of what Clean Code means.

I always strive for avoiding using code from other programs that I do not fully understand. I also strive for doing everything as simple as possible and remove unnecessary code. I have tried to remove all unnecessary code in the applications and hope that you as reader inform me about possible improvements that you find.

SQLite Databases

There is no SQLite Server used and therefore, the server cannot connect to the SQLite database via an IP connection. The SQLite databases can be regarded as being text files. The CarAPI program creates and initializes Car.db if it is missing during the start of the program. The initialization of Car.db creates and populates two tables: Cars and Companies. With the tool “DB browser for SQLite”, you can open the databases. Opening Car.db will show the database as shown below:

The second database, AspNet.db, has the same functionality as ASPNETDB.mdf in a traditional Visual Studio web project, i.e., storing user identity data.

SQLite has an “in memory” mode that is especially useful during unit testing. Then, you open the connection like this:

It's common to use SQLite in unit tests and SQL Server in production. The SQL syntax is in most cases the same in SQLite and SQL Server.

In normal SQLite operation, you define the db context in the Startup.cs file during initialization with Autofac dependency injection:

Running CarAPI and CarClient

To run the system, please download the CarAPI and CarClient solutions, open them in Visual Studio 2017, and start CarAPI first by pressing F5. Then, start the CarClient by pressing F5. When running the CarClient, you have the possibility to create a user account. The code for this uses the classes and methods from Microsoft.AspNetCore.Authentication, Authorization and Identity classes, which you get from the Visual Studio project template.

When running the client as a logged in user, the first view looks like this:

The button “Show message queues” opens a pop up window showing all vehicles status and “dummy” message queues.

NServiceBus Callback Sample

Particular Software advises using Callbacks only in exceptional situations, e.g., to introduce messaging behind a synchronous API in a legacy component that can't be changed. They allow for gradually transitioning applications towards messaging. However, they're not a replacement for asynchronous messaging and don't offer similar benefits (in terms of scalability, loose coupling, etc.). For more information, refer to the documentation.

As base for the development of NServiceBusAPI, the following Callback sample is used:

I recommend that you download and run it to be sure how it works. Please note that you have to add the following line in Program.cs (it's a bug in the sample!):

C#
CultureInfo.CurrentUICulture = new CultureInfo("en-US");

Like this:

To send and receive object messages, the classes ObjectMessage, ObjectResponseMessage and ObjectMessageHandler are used:

I recommend that you run the Callback sample and become acquainted with the code.

NServiceBusAPI

To send messages in NServiceBusAPI, there are three categories of classes: Handlers, request messages and response messages. They look typically like this:

C#
[Serializable]

public class CreateCarRequest : IMessage
{
   public CreateCarRequest(Car car)
   {
      DataId = Guid.NewGuid();
      Car = car;
   }>

   public Guid DataId { get; set; }
   public Car Car { get; set; }
}

[Serializable]

public class CreateCarResponse : IMessage
{
   public CreateCarResponse()
   {
      DataId = Guid.NewGuid();
   }

   public Guid DataId { get; set; }
   public Car Car { get; set; }
}

public class CreateCarRequestHandler:IHandleMessages<CreateCarRequest>
{
   readonly DbContextOptionsBuilder<CarApiContext> _dbContextOptionsBuilder;
   
   public CreateCarRequestHandler(DbContextOptionsBuilder<CarApiContext> dbContextOptionsBuilder)
   {
      _dbContextOptionsBuilder= dbContextOptionsBuilder;
   }

   static ILog log = LogManager.GetLogger<CreateCarRequestHandler>();

   public Task Handle(CreateCarRequest message,    IMessageHandlerContext context)
   {
      log.Info("Received CreateCarRequest.");
      var response = new CreateCarResponse()
      {
         Car = message.Car
      };

      using (var unitOfWork = new CarUnitOfWork(new CarApiContext(_dbContextOptionsBuilder.Options))) 
      {
         unitOfWork.Cars.Add(message.Car);
         unitOfWork.Complete;
      }

      var reply = context.Reply(response);
      return reply;
   }

The actual data is fetched from the database in...

C#
CreateCarRequestHandler:IHandleMessages<CreateCarRequest>

...and delivered to the...

C#
CarController: Controller

... like this:

The pattern is simple. Please download and run the NServiceBusAPI solution to fully understand it. It consists of three projects: Client, Server and Shared. Classes used by both Client and Server are located in Shared. The Server project has the same purpose as the CarAPI project, i.e., the Server project accesses the databases, Car.db and AspNet.db. It is a console program and it starts like shown below in Program.cs. I have used as much as possible from CarAPI. The database is initiated in an extension method called InitSqLiteDb.

C#
class Program
{
   public static void Main(string[] args)
   {
      CultureInfo.CurrentUICulture = new CultureInfo("en-US");
      BuildWebHost(args).Run();
   }

   static IWebHost BuildWebHost(string[] args) =>
      WebHost.CreateDefaultBuilder(args)
         .UseKestrel()
         .UseContentRoot(Directory.GetCurrentDirectory())
         .UseIISIntegration()
         .UseStartup<Startup>()
         .InitSqLiteDb("DataSource=App_Data/Car.db")
         .Build();
   }
}

public static class WebHostBuilderExtension
{
   //
   // Summary:
   //     Defines the context for Car.db
   // Parameters:
   //   db: name and location of the database

   static readonly DbContextOptionsBuilder<CarApiContext>_optionsBuilder = 
                                           new DbContextOptionsBuilder<CarApiContext>();

   public static IWebHostBuilder InitSqLiteDb(this IWebHostBuilder hostBuilder, string db)
   {
      _optionsBuilder.UseSqlite(db);
      using (var context = new CarApiContext(_optionsBuilder.Options))
      {
         context.Database.EnsureCreated();
         context.EnsureSeedData();
      }
   }
}

For details, please see and run the code in NServiceBusAPI.

Points of Interest

Writing this article taught me several things, for example:

  • how to do dependency injection with Autofac
  • how to use SQLite during unit tests as complement to SQL Server
  • how to use extension methods for initializing a .NET Core program
  • how to use NServiceBus

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)