1

I'm running a few NServiceBus endpoints that are built using the generic host configuration (https://docs.particular.net/samples/hosting/generic-host/). These endpoints run in Docker containers. Now, I want to schedule a message (with hangfire). Whenever the scheduled message is executed, I get the following error:

Value cannot be null. (Parameter 'session')

System.ArgumentNullException: Value cannot be null. (Parameter 'session')
   at NServiceBus.Guard.AgainstNull(String argumentName, Object value)
   at NServiceBus.IMessageSessionExtensions.Send(IMessageSession session, Object message)
   at Provisioning.Handlers.CustomerCreatedHandler.Reauthenticate(Guid customerId) in /src/Provisioning/Handlers/CustomerCreatedHandler.cs:line 30

This is because the Send() method doesn't have a message session. However, how do I obtain this session? Looking at https://docs.particular.net/nservicebus/hosting/, you can create a session by starting a new endpoint from a EndpointConfiguration. Since I use generic host, I only have the EndpointConfiguration but I don't have access to the endpoint that is created from this (or at least I don't know how to). This is what my configuration looks like (extremely simplified):

hostBuilder = Host.CreateDefaultBuilder()
    .UseConsoleLifetime()
    .UseNServiceBus(xtc =>
    {
        var endpointConfiguration = new EndpointConfiguration("endpointName");
        endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
        endpointConfiguration.EnableInstallers();
        endpointConfiguration.DefineCriticalErrorAction(OnCriticalError);

        // removed all config

        return endpointConfiguration;
    });

And this is started with:

await hostBuilder.Build().RunAsync();

I'm using NServiceBus 7 by the way.

Edit:

This is how I schedule the Hangfire task (updated based on Szymon's answer, but not working yet):

public class CustomerCreatedHandler : IHandleMessages<CustomerCreated>
{
    private static IServiceProvider _provider;

    public CustomerCreatedHandler(IServiceProvider provider)
    {
        _provider = provider;
    }

    public async Task Handle(CustomerCreated message, IMessageHandlerContext context)
    {
        RecurringJob.AddOrUpdate($"Reauthenticate-{message.CustomerId}", () => Reauthenticate(message.CustomerId), Cron.Hourly);
    }

    public static Task Reauthenticate(Guid customerId)
    {
        IMessageSession session = _provider.GetService<IMessageSession>();
        return session.Send(new AuthenticateCustomer { CustomerId = customerId });
    }
}

It results in:

System.ArgumentNullException
Value cannot be null. (Parameter 'provider')

System.ArgumentNullException: Value cannot be null. (Parameter 'provider')
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Provisioning.Handlers.CustomerCreatedHandler.Reauthenticate(Guid customerId) in /src/Provisioning/Handlers/CustomerCreatedHandler.cs:line 33
Leon Cullens
  • 12,276
  • 10
  • 51
  • 85

1 Answers1

2

You can resolve the IMessageSession from IServiceProvider as shown here in the background worker.

Szymon Pobiega
  • 3,358
  • 17
  • 18
  • Thank you Szymon. I tried this, but 'provider' is empty. Do I need to do anything to register it in my endpoint config? See my updated post for the code snippet. – Leon Cullens May 15 '20 at 16:19
  • I think the problem is with the way the IServiceProvider is accessed in the Hangfire callback. If Hangfire executes the callback before the NServiceBus handler executed, the static field is null and you get the exception. In order to make it work you need to integrate Hangfire with IServiceCollection. Alternatively, you need to retrieve the IServiceCollection at startup and store it in a static field – Szymon Pobiega May 19 '20 at 08:55