How to stop a MassTransit bus in an ASP.NET Core server?

You can use ApplicationLifetime events. Just make your IBus object class level variable.

public class Startup
{
    private IBus _bus;

    public void ConfigureServices(IServiceCollection services) {
        /* ... */

        _bus = Bus.Factory.CreateUsingRabbitMq ... 

        /* ... */
    }

    public void Configure(IApplicationLifetime appLifetime)
    {
        appLifetime.ApplicationStarted.Register(() => _bus.Start());
        appLifetime.ApplicationStopping.Register(() => _bus.Stop());
    }
}

There is IApplicationLifetime in .NET Core, which has several CancellationToken properties, including ApplicationStopped. So when you need to do something after asp.net application is shutdown and all requests are processed (like stopping your bus) - you can do it like this:

// lifetime will be injected to Configure from DI container
public void Configure(IApplicationBuilder app, IApplicationLifetime lifetime) {
    // subscribe to ApplicationStopped
    lifetime.ApplicationStopped.Register(OnApplicationStopped);
    // the rest
}

private void OnApplicationStopped() {
    _bus.Stop();
}

It's always good to explicitly release resources even on process shutdown. For example, some message might still be in transition when the process will be killed after shutdown. Doing explicit dispose will allow this transition to complete.


To add to the existing answers:

  1. If you use the MassTransit.AspNetCore's IServiceCollection.AddMassTransit() extension method, there's no need for a class level IBus instance. Startup's Configure() supports DI, so you can do this instead:
    public void Configure(IApplicationLifetime appLifetime, IBus bus)
    {
        appLifetime.ApplicationStarted.Register(() => bus.Start());
        appLifetime.ApplicationStopping.Register(() => bus.Stop());
    }
    
    If you don't want to use the package, you can still register IBus with the DI container (like in the question) and request it from Configure().
  2. The ASP.NET Core DI sample uses an IHostedService instead:

    public class BusService : IHostedService
    {
        private readonly IBusControl _busControl;
        public BusService(IBusControl busControl)
        {
            _busControl = busControl;
        }
    
        public Task StartAsync(CancellationToken cancellationToken) =>
            _busControl.StartAsync(cancellationToken);
    
        public Task StopAsync(CancellationToken cancellationToken) =>
            _busControl.StopAsync(cancellationToken);
    }
    

    The service is registered as:

    services.AddSingleton<IHostedService, BusService>();
    

    For more information on IHostedService, here's the doc page. I'm not sure I like the idea of having a background service just to stop the bus. Anyway, the sample repo I picked this example from is worth referring to.

  3. The third option is to do it yourself in Main(). Something like:

    var host = CreateWebHostBuilder(args).Build();
    var bus = host.Services.GetRequiredService<IBusControl>();
    
    await bus.StartAsync();
    await host.RunAsync();
    await bus.StopAsync();