3
votes

I have a Service Fabric asp.net core stateless service which implements custom middleware. In that middleware I need access to my service instance. How would I go about injecting this using asp.net core's built-in DI/IoC system?

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext)
    {
        // ** need access to service instance here **
        return _next(httpContext);
    }
}

Someone mentioned accomplishing this using TinyIoC in Web Api 2 in the Apr 20, 2017 Q&A #11 [45:30] with the Service Fabric team. As well that the current recommended method is to use asp.net core.

Any help or examples would be greatly appreciated!

2

2 Answers

6
votes

In the asp.net core stateless service that creates the ServiceInstanceListener you can inject the context like this:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new[]
        {
            new ServiceInstanceListener(serviceContext =>
                new WebListenerCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                {
                    logger.LogStatelessServiceStartedListening<WebApi>(url);

                    return new WebHostBuilder().UseWebListener()
                                .ConfigureServices(
                                    services => services
                                        .AddSingleton(serviceContext) // HERE IT GOES!
                                        .AddSingleton(logger)
                                        .AddTransient<IServiceRemoting, ServiceRemoting>())
                                .UseContentRoot(Directory.GetCurrentDirectory())
                                .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                .UseStartup<Startup>()
                                .UseUrls(url)
                                .Build();
                }))
        };
    }

Your middleware than can use it like this:

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext, StatelessServiceContext serviceContext)
    {
        // ** need access to service instance here **
        return _next(httpContext);
    }
}

For a complete example take a look at this repository: https://github.com/DeHeerSoftware/Azure-Service-Fabric-Logging-And-Monitoring

Points of interest for you:

1
votes

Dependency injection via constructor works for middleware classes as well as for others. Just add additional parameters to the middleware constructor

public MyMiddleware(RequestDelegate next, IMyService myService)
{
    _next = next;
    ... 
}

But also you can add dependency directly to the Invoke method

Documentation: Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors are not shared with other dependency-injected types during each request. If you must share a scoped service between your middleware and other types, add these services to the Invoke method's signature. The Invoke method can accept additional parameters that are populated by dependency injection.

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
    {
        svc.MyProperty = 1000;
        await _next(httpContext);
    }
}