Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Endpoint hosting with the Generic Host

Component: NServiceBus
NuGet Package: NServiceBus (7.x)

The sample uses the Generic Host and the Microsoft.Extensions.Hosting.WindowsServices NuGet package to host NServiceBus as a Windows Service using the Generic Host underneath.

Prerequisites

The sample has the following prerequisites:

Running the sample as a console

In Visual Studio, press F5 to start the sample as a console application.

Running the sample as a Windows Service

  • Install PowerShell Core on Windows
  • Start PowerShell core with elevated permissions
  • Run dotnet publish in the directory of the sample; for example: C:\samples\generic-host
  • Run New-Service -Name WorkerTest -BinaryPathName "C:\samples\generic-host\bin\Debug\net48\publish\GenericHost.exe"
  • Run Start-Service WorkerTest
  • Go to the Event Viewer under Windows Logs\Applications and observe event log entries from source GenericHost with the following content
Category: MyMessageHandler
EventId: 0

Received message #{Number}
  • Once done, run Stop-Service WorkerTest and Remove-Service WorkerTest
Currently to use the Microsoft.Extensions.Logging library, the NServiceBus.MicrosoftLogging community package should be used.

Code walk-through

var builder = Host.CreateDefaultBuilder(args);
builder.UseWindowsService();

The snippet above shows how the host builder runs by default as a Windows Service. If the sample is started with the debugger attached, it uses the console's lifetime instead. To always use the console lifetime use the following code instead:

var builder = Host.CreateDefaultBuilder(args);
builder.UseConsoleLifetime();
builder.ConfigureLogging((ctx, logging) =>
{
    logging.AddConfiguration(ctx.Configuration.GetSection("Logging"));

    logging.AddEventLog();
    logging.AddConsole();
});

To enable integration with Microsoft.Extensions.Logging, the NServiceBus.MicrosoftLogging.Hosting community package is used and configured in combination with the standard logging.

Next, the builder configures NServiceBus using the NServiceBus.Extensions.Hosting package, including the critical error action that will shut down the application or service in case of a critical error.

builder.UseNServiceBus(ctx =>
{
    var endpointConfiguration = new EndpointConfiguration("Samples.Hosting.GenericHost");
    endpointConfiguration.UseTransport<LearningTransport>();

    endpointConfiguration.DefineCriticalErrorAction(OnCriticalError);

    return endpointConfiguration;
});

The critical error action:

private static async Task OnCriticalError(ICriticalErrorContext context)
{
    var fatalMessage =
        $"The following critical error was encountered:{Environment.NewLine}{context.Error}{Environment.NewLine}Process is shutting down. StackTrace: {Environment.NewLine}{context.Exception.StackTrace}";
    EventLog.WriteEntry(".NET Runtime", fatalMessage, EventLogEntryType.Error);

    try
    {
        await context.Stop().ConfigureAwait(false);
    }
    finally
    {
        Environment.FailFast(fatalMessage, context.Exception);
    }
}

To simulate work, a BackgroundService called Worker is registered as a hosted service:

return builder.ConfigureServices(services => { services.AddHostedService<Worker>(); });

The IMessageSession is injected into the Worker constructor, and the Worker sends messages when it is executed.

class Worker : BackgroundService
{
    private readonly IMessageSession messageSession;

    public Worker(IMessageSession messageSession)
    {
        this.messageSession = messageSession;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            var number = 0;
            while (!stoppingToken.IsCancellationRequested)
            {
                await messageSession.SendLocal(new MyMessage {Number = number++})
                    .ConfigureAwait(false);

                await Task.Delay(1000, stoppingToken).ConfigureAwait(false);
            }
        }
        catch (OperationCanceledException)
        {
            // graceful shutdown
        }
    }
}

Related Articles


Last modified