Using service.Gateway inside a Task or outside a service

I am having a lot of challenges with a null reference exception outside of the main thread of services. Even in some cases when I resolve it using HostContext.Resolve when I’m calling it from a background started in the App.

Any hints?

like so:

public object Any(dto req)
{

     Task.Factory.StartNew(()=> {var x = Gateway.Send<dto2>(new dto3())});

}

{System.ArgumentNullException: Value cannot be null.
Parameter name: provider
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at ServiceStack.Host.NetCore.NetCoreRequest.TryResolveT
at lambda_method(Closure , IResolver )
at ServiceStack.Host.ContainerResolveCache.CreateInstance(IResolver resolver, Type type, Boolean tryResolve)
at ServiceStack.Host.ServiceController.<>c__DisplayClass38_0.b__0(IRequest req, Object dto)
at ServiceStack.Host.ServiceController.Execute(Object requestDto, IRequest req)
at ServiceStack.InProcessServiceGateway.ExecSync[TResponse](Object request)
at ServiceStack.InProcessServiceGateway.Send[TResponse](Object requestDto)
at BatchApp.Bertrams.Impl.BetramServices.<>c__DisplayClass12_0.b__0() in /Users/kevin/Projects/TextbookMCF/src/BatchApp/Bertrams/Impl/BetramServices.cs:line 403}

Executing it in a background thread executes it outside of the HTTP Request where it wont be able to access any scoped dependencies and wont work for Services needing to access the HTTP Request context.

If you just want to execute it without blocking, you can just execute it asynchronously:

var task = Gateway.SendAsync<dto2>(new dto3());
//.... do other work
var x = await task; //wait for response

Otherwise you can try resolving the Service from the HTTP Request worker thread then calling the method in the background thread:

var service = ResolveService<MyService>();

Task.Factory.StartNew(() => {
    using (service) {
        var x = service.Any(new dto3());
    }
});

Although ideally you’d isolate functionality you want to execute in a background thread so it’s decoupled from the HTTP Request context. So instead of calling a Service, call your own dependency with anything you need from the IRequest context passed in as arguments, e.g:

var arg = Request.QueryString["arg"];
Task.Factory.StartNew(()=> { 
    var x = MyDependency.Exec(new dto3 { arg = arg }); 
});

This way you can be assured that its completely decoupled from the HTTP Request and none of your logic/dependencies are relying on accessing the HTTP Request Context in a background thread.

Revisiting this - what is the actual purpose of Gateway within a service? It only seems to work if called from Http?

The gateway provides a decoupled way to invoke services, where the same generic interface can be used to call either internal or external services. The Service Gateway docs describes it in more detail.

But it’s not clear what the cause of your issue is, it’s suggests it’s failing trying to resolve a dependency from ASP.NET Core IOC, perhaps you’re trying to resolve a request scoped dependency in a background thread which you shouldn’t do when executing outside of the request context.

The latest v5.4.1 pre-release packages on MyGet are now have source-link enabled maybe you can use it to debug which dependency is the cause of the issue.