Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OwinMiddleware and dependency injection

I'm trying to create an OwinMiddleware object to register in a pipeline to pull out some creds from the incoming request and apply them to a service in our service container. The result of this would be that a service that requires auth that we use in the controllers will arrive pre-authed meaning the controllers no longer have to pull out authorization headers and principals and I can remove a lot of plumbing that passes these values down several layers.

We use DependencyInjection (Microsoft.Extensions.DependencyInjection) and more importantly this authed service is scoped which means it needs to be created and destroyed per request (i.e. otherwise it might accidentally use creds from previous requests). Its set to do so via a reasonably simple implementation of IDependencyResolver that uses a ServiceCollection. The scoping works via the .BeginScope() method that I don't quite understand because I can't find the sources that actually call .BeginScope() via HttpConfiguration.IDependencyResolver, I kinda get what its up to but not entirely. It works well though.

Now the problem with the object I have inheriting from OwinMiddleware is that I can't seem to get it communicating with the relevant scoped object via the IDependencyResolver.
As I don't control the creation of the OwinMiddleware object all I can do is specify the service I want to interact with in the constructor. However this is seemingly useless because it doesn't appear to give me the same instance of object later in the pipeline than I get here (I assume because it is scoped?).

Even if I put the IDependencyResolver into the constructor I still don't get the right instance of my service. I can verify the middleware is executing.

I saw other people talking some time ago about being able to override the Invoke() function of OwinMiddleware with extra params and this solving the scope issue. This seems to make sense if the middleware is only created once as any scoped constructor dependencies would be stale by the second request. Adding the dependency during the pipeline action makes much more sense to me. However with the version of the Owin lib I have (v3) there is only:

public abstract Task Invoke(IOwinContext context);

defined on the base so as far as I can tell my only point of entry for extra services in the middleware is via the constructor. Do I need a different version? Do I need to invoke something else special to inform the pipeline to construct new instances of my middleware per request?

This blog entry seems to state this will be fixed in aspnet 5 which I believe I'm on. So how and where is it fixed?

... things are not as clean when you want to pass in a class with its own dependencies and we want to start using dependency injection. Since the constructor for OwinMiddleware requires OwinMiddleware next, we cannot simply register the middleware itself and allow our DI container to resolve its dependencies.

From what I can see, if you do need to add another dependency to your middleware you have two options: new it up with a concrete implementation (bad) or pass it in using your project’s Dependency Resolver (anti-pattern, also different between MVC and Web API). If you find any nicer methods please tell me, as I’d love to know and update this section. This has apparently been resolved for ASP.NET 5, but that doesn’t help us now…

like image 209
Quibblesome Avatar asked Dec 29 '16 11:12

Quibblesome


People also ask

What is OWIN middleware?

OWIN allows web apps to be decoupled from web servers. It defines a standard way for middleware to be used in a pipeline to handle requests and associated responses. ASP.NET Core applications and middleware can interoperate with OWIN-based applications, servers, and middleware.

Is .NET framework middleware?

An ASP.NET Core app is built upon a series of middleware. Middleware is handlers that are arranged into a pipeline to handle requests and responses. In a Web Forms app, HTTP handlers and modules solve similar problems. In ASP.NET Core, modules, handlers, Global.

Does MVC use dependency injection?

The Dependency Injection (DI) Design PatternThe Dependency Resolver in ASP.NET MVC can allow you to register your dependency logic somewhere else (e.g. a container or a bag of clubs). The advantages of using Dependency Injection pattern and Inversion of Control are the following: Reduces class coupling.


1 Answers

It's probably not exactly what you would want, but that's the only solution I found without using custom DI provider.
You can set the data you want in the Owin environment context (which is scoped).

// SettingsMiddleware.cs
public class SettingsMiddleware : OwinMiddleware
{
    public SettingsMiddleware (OwinMiddleware next)
        : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        try
        {
            string data = context.Request.Headers["my-http-header-key"];
            context.Set("my-context-key", new MyCustomData
            {
                Data = data,
                // ... Anything else you want
            });
        }
        finally
        {
            await Next.Invoke(context);
        }
    }
}


// MyCustomData.cs
public class MyCustomData
{
    public string Data { get; set; }
    // ...
}


// SettingsService.cs
public interface ISettingsService
{
    MyCustomData GetHttpSettings();
}

public class SettingsService : ISettingsService
{
    public MyCustomData GetHttpSettings()
    {
        // Need Microsoft.Owin.Host.SystemWeb package for GetOwinContext.
        var owinContext = HttpContext.Current.GetOwinContext();
        var settings = owinContext.Get<MyCustomData >("my-context-key");
        return settings ?? new MyCustomData();
    }
}
like image 104
Mr Patience Avatar answered Oct 11 '22 11:10

Mr Patience