Pre-Startup Checks Fail Prior to gMSA Context Being Established by Windows Service

I am using NSB 7.7.3, the SqlServerTransport, and .NET 6.

I am building an application that runs NSB in a Windows worker service and my workplace is requiring that I use a group managed service account (gMSA) to provide credentials for the SQL Server endpoint and the SqlServerTransport.

SQL connection strings for the gMSA contain no credentials (only server, database, and designated settings). Credentials are passed within the context of the Windows service once it is running. However, prior to the Windows service launching, the host must be built in Program.cs:

IHost host = Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .UseNServiceBus(context =>
        {
            //Lots of NSB code including the below
             string connectionString = configuration.GetValue<string>("ConnectionStrings:Database");
             var transport = endpointConfiguration.UseTransport<SqlServerTransport>();
             transport.ConnectionString(connectionString);
             var subscriptions = transport.SubscriptionSettings();
             subscriptions.SubscriptionTableName(tableName: "NServiceBus.SubscriptionRouting");
        }
        //more code
        .Build();

        await host.RunAsync();

This code runs fine under standard service accounts, but when using a gMSA the code is running before the Windows service is launched. As a result, the NSB pre-startup checks fail due to no user credential being provided by the gMSA (which is only accessible within the context of the Windows service). Here’s the stack trace:

System.Exception: Pre start-up check failed: Could not open connection to the SQL instance. Check the original error message for details. Original error message: Login failed for user ''.
   at NServiceBus.ReceiveComponent.ReceivePreStartupChecks() in /_/src/NServiceBus.Core/Receiving/ReceiveComponent.cs:line 190
   at NServiceBus.StartableEndpoint.Start() in /_/src/NServiceBus.Core/StartableEndpoint.cs:line 38
   at NServiceBus.HostingComponent.Start(IStartableEndpoint startableEndpoint) in /_/src/NServiceBus.Core/Hosting/HostingComponent.cs:line 76
   at NServiceBus.ExternallyManagedContainerHost.Start(IBuilder externalBuilder) in /_/src/NServiceBus.Core/Hosting/ExternallyManagedContainerHost.cs:line 49
   at NServiceBus.Extensions.Hosting.NServiceBusHostedService.StartAsync(CancellationToken cancellationToken) in /_/src/NServiceBus.Extensions.Hosting/NServiceBusHostedService.cs:line 30
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)

I would like to know:

If there is any way to disable the pre-startup check for the SqlServerTransport/connection string (and possibly run it later).

or

If there is any way to configure an existing running host to start and create an NSB endpoint after Program.cs has run (ideally in the StartAsync Task of the worker service within the Windows service context containing the gMSA credentials).

All assistance is greatly appreciated.

Hi @jjx,

Nope, there’s no way to disable the pre-startup check.

However, waiting to start the NServiceBus endpoint until after Program.cs should not be a big deal. You just can’t use the .UseNserviceBus(…) construct and need to act like you’re self-hosting like before ASPNET Core was a thing.

Here’s the documentation on self-hosting. Basically you’re calling Endpoint.Start(config) and getting an IEndpointInstance back. You can assign that to a static variable or whatever. You can also cast it to an IMessageSession if you don’t want the code that has access to the instance to be able to call .Stop().

Thanks for pointing me in the right direction David! Self-hosting was the way to go. Much appreciated!