Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Endpoint hosting with the Generic Host

Component: NServiceBus
NuGet Package: NServiceBus (8.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();

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(new LearningTransport());

    endpointConfiguration.DefineCriticalErrorAction(OnCriticalError);

    return endpointConfiguration;
});

The critical error action:

private static async Task OnCriticalError(ICriticalErrorContext context, CancellationToken cancellationToken)
{
    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(cancellationToken).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 cancellationToken)
    {
        try
        {
            var number = 0;
            while (!cancellationToken.IsCancellationRequested)
            {
                await messageSession.SendLocal(new MyMessage { Number = number++ }, cancellationToken)
                    .ConfigureAwait(false);

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

Related Articles


Last modified