From time to time I manage to find some spare time, and when that happens there’s usually a long lists of things I’d like to do, one of which is coding.

Spoiler: it’s not at the top of my list ;-)

Last time it happened I released a couple of NServiceBus extensions to route messages and to define message conventions using attributes (there seems to be an interesting update coming). This time I managed to solve a much simpler problem:

As a user I need to know when an NServiceBus endpoint is started to perform some actions.

Sounds like a trivial problem to solve, especially when self-hosting endpoints using a console application:

public static async Task Main(string[] args)
{
    var endpointConfiguration = new EndpointConfiguration("SampleEndpoint");
    endpointConfiguration.UseTransport<LearningTransport>();
    
    var endpointInstance = await Endpoint.Start(endpointConfiguration);
    
    //here the endpoint is started, perform whatever action is needed.
}

So far, so good. So what’s the problem?

NServiceBus supports the .NET Core generic hosting paradigm, which means that the above can be rewritten as follows:

public static void Main(string[] args)
{
    CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseNServiceBus(context =>
        {
            var endpointConfiguration = new EndpointConfiguration("SampleEndpoint");
            endpointConfiguration.UseTransport<LearningTransport>();

            return endpointConfiguration;
        });

Using the generic hosting means that the endpoint lifecycle is not anymore controlled by our code. It’s controlled by the generic host, which means we have no place to perform the actions we need to perform when the endpoint is started.

The easiest solution is to create an NServiceBus Feature, and register a FeatureStartupTask that is invoked by NServiceBus when the endpoint is started.

Are you kidding me?

Sounds complex, for such simple task. Hence I created a thing, I called it NServiceBus.Extensions.EndpointStarted. It implements a Feature and a FeatureStartupTask and allows the user code to register a simple Func<IMessageSession, Task> during the endpoint configuration phase:

var endpointConfiguration = new EndpointConfiguration("SampleEndpoint");
endpointConfiguration.UseTransport<LearningTransport>();
endpointConfiguration.OnEndpointStarted(messageSession =>
{
    return Task.CompletedTask;
});

The OnEndpointStarted extension can be used also when using the generic hosting infrastructure:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseNServiceBus(context =>
        {
            var endpointConfiguration = new EndpointConfiguration("SampleEndpoint");
            endpointConfiguration.UseTransport<LearningTransport>();
            endpointConfiguration.OnEndpointStarted(messageSession =>
            {
                return Task.CompletedTask;
            });
            
            return endpointConfiguration;
        });

The package is available on NuGet as NServiceBus.Extensions.EndpointStarted, and the source code on GitHub. As usual, raise an issue if you face any issues :-)


Header image: Photo by Alex Paganelli on Unsplash