'Masstransit Consumer in .NET 4.8 Topshelf works only in Executable not in Service

we need to host a Masstransit RabbitMQ Consumer in a .NET 4.8 Windows Service.

We are using Dependency Injection and Topshelf to run, install and start the Service.

Running the Consumer as a Windows *.exe works fine: Messages are received.

But when starting as a Windows Service NO Messages are received as I can tell from the Log4Net Log.

This is the Main() Method using Topshelf to start our MassTransitRunner Instance with injected Logging and Configuration:

    var massTransitRunner = new MassTransitRunner(_logger, _config, args);
    _ = HostFactory.Run(x =>
    {
        x.Service<MassTransitRunner>(s =>
                            {
                                s.ConstructUsing(runner => massTransitRunner);
                                s.WhenStarted(runner => runner.Start());
                                s.WhenStopped(runner => runner.Stop());
                            });
        x.RunAsNetworkService();
        x.SetServiceName(nameof(RuleEngineCommandConsumer));
        x.SetDisplayName("_RuleEngine-CommandConsumer");
        x.SetDescription("Processes Commands with Results to trigger Transitions");
    });

And this is the Start()-Method of the MassTransitRunner class passed to Topshelf:

public void Start() {
    try
    {
        _logger.LogInformation("Starting...");

        var hostBuilder = _args.CreateMassTransitHostBuilder(null, null, Program.ConfigureServices, Assembly.GetExecutingAssembly());
        _host = hostBuilder.UseWindowsService().Build();
        _task = _host.StartAsync(_Cancellation.Token);
        //_host.Start();
        //_host.RunAsync(_Cancellation.Token);
        //await _task; => stopped without Starting

        _logger.LogInformation("Started");
    }
    catch (Exception e)
    {
        _logger.LogError(e, "Starting...");
    }
}

As you can see we have experimented with different Methods to start the Host, but only StartAsync worked.

The full Example Project can be inspected in Github

Any Help is really appreciated!



Solution 1:[1]

Actually I was making it harder than necessary:

  • TopShelf is not needed, because Microsoft.Extensions.Hosting NuGet Packages are built on .NET Standard 2.0 so they also work with .NET 4.8
  • My main Mistake was to only Start() the Host, instead of Run()ing it. This allowed the Main() Method to terminate, taking the Host with it.

The working Main() Method now looks like this:

    var hostBuilder = Host.CreateDefaultBuilder(args);
    hostBuilder = hostBuilder.ConfigureMassTransitConsumers(null, null
        , Assembly.GetExecutingAssembly());
    hostBuilder = hostBuilder.UseWindowsService(); //automatically detects whether in Service or Console...
    var host = hostBuilder.Build();
    host.Run(); //runs all registered IHostedService Classes and waits for their Completion

I have updated the sample project with a working RabbitMq Consumer hoping to give others a kick-start.

Thanks again to @chris-patterson for the quick answer and a great Messaging Framework!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Spoc