The sample uses the Generic Host and the Microsoft.
NuGet package to host NServiceBus as a Windows Service using the Generic Host underneath.
Prerequisites
The sample has the following prerequisites:
- .NET 4.8 SDK
- PowerShell Core for Windows in case the sample is to be installed as a Windows Service
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\
and observe event log entries from sourceApplications GenericHost
with the following content
Category: MyMessageHandler
EventId: 0
Received message #{Number}
- Once done, run
Stop-Service WorkerTest
andRemove-Service WorkerTest
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.
community package is used and configured in combination with the standard logging.
Next, the builder configures NServiceBus using the NServiceBus.
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
}
}
}