Aspire is a stack for developing distributed applications provided by Microsoft.
This sample shows an Aspire AppHost project that orchestrates multiple NServiceBus endpoints, making use of the learning transport.
If you're missing certain capabilities to use Aspire with NServiceBus, share them and help shape the future of the platform.
Running the sample
- Run the AspireDemo.AppHost project
- Open the Aspire dashboard
- Review the metrics, traces, and structured log entries of each of the resources
- Open ServicePulse from the link in the Aspire dashboard to see the audit and health of the running endpoints
This sample requires Docker to run. Ensure the predefined container ports are free and available.
Code walkthrough
AspireDemo.AppHost
The Aspire orchestration project defines multiple resources and the relationships between them:
- A Particular platform resource named
particular, which includes:- Default ServiceControl error, audit and monitoring instances
- ServicePulse
- Learning transport
- Two projects, each of which is an NServiceBus endpoint. Both of these projects reference the
particularresource to access the transport connection string.clientUi: simulates a client application sending messages to the system periodicallysales: processes messages and simulates transient failures
Platform configuration
AddParticularPlatform registers the Particular Platform as a resource named particular. The . registers the remaining platform components using their default configuration — the ServiceControl error, audit and monitoring instances, ServicePulse, Learning transport and RavenDB for the database.
var platform = builder
.AddParticularPlatform("particular")
.AddDefaultComponents();
Endpoints
Each NServiceBus endpoint is added as an Aspire project and linked to the platform with WithParticularPlatform. This wires the endpoint to the platform's transport connection string. The ClientUI endpoint additionally uses WaitFor(sales) so that the Sales endpoint exists before it starts sending messages to it.
var sales = builder.AddProject<Projects.Sales>("Sales")
.WithParticularPlatform(platform);
builder.AddProject<Projects.ClientUI>("ClientUI")
.WaitFor(sales)
.WithParticularPlatform(platform);
AspireDemo.ServiceDefaults
The Aspire service defaults project provides extension methods to configure application hosts in a standardized way. This project is referenced by all of the NServiceBus endpoint projects.
The OpenTelemetry configuration has been updated to include NServiceBus metrics and traces.
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddMeter("NServiceBus.*")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddSource(builder.Environment.ApplicationName)
.AddSource("NServiceBus.*")
.AddAspNetCoreInstrumentation(tracing =>
// Exclude health check requests from tracing
tracing.Filter = context =>
!context.Request.Path.StartsWithSegments(HealthEndpointPath)
&& !context.Request.Path.StartsWithSegments(AlivenessEndpointPath)
)
// Uncomment the following line to enable gRPC instrumentation
// (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
//.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation();
});
Each endpoint project configures the learning transport:
var routing = endpointConfiguration.UseTransport(new LearningTransport());
Finally, each endpoint enables NServiceBus installers. Every time the application host is run, the transport and ServiceControl database are recreated and will not contain the queues and tables needed for the endpoints to run. Enabling installers allows NServiceBus to set up the assets that it needs at runtime.
endpointConfiguration.EnableInstallers();
Endpoint projects
Each of the endpoint projects contain the same code to create an application host, apply the configuration from the ServiceDefaults project on the NServiceBus endpoint.
var builder = Host.CreateApplicationBuilder();
builder
.AddServiceDefaults()
.AddNServiceBusEndpoint("Sales");
await builder.Build().RunAsync();
To demonstrate the platform's error handling, the Sales endpoint's handler throws an exception for a random subset of the messages it receives:
if (Random.Shared.Next(0, 5) == 0)
{
throw new Exception("Oops");
}
Failed messages are moved to the error queue, where they can be inspected and retried from ServicePulse.