OWIN中间件+ Web API +简单注入器

Gok*_*ath 1 c# dependency-injection simple-injector asp.net-web-api owin

我目前正在使用WebApiRequestLifestyle具有默认的范围生活方式.我想在OWIN中间件和其中一个API控制器中注入一个服务,服务的范围应该仍然是WebAPI,即对于整个请求,应该只有一个服务实例.

public class TestMiddleware : OwinMiddleware
{
    private readonly ITestService _testService;

    public TestMiddleware(OwinMiddleware next, ITestService testService) : base(next)
    {
        _testService = testService;
    }

    public override async Task Invoke(IOwinContext context)
    {
        var test = _testService.DoSomething();
        await Next.Invoke(context);
    }
}

public class ValuesController : ApiController
{
    private readonly ITestService _testService;

    public ValuesController(ITestService testService)
    {
        _testService = testService;
    }
}
Run Code Online (Sandbox Code Playgroud)

整个请求的ITestService实例应该相同.我该如何注册中间件?

这就是我现在这样做的方式:

     using (container.BeginExecutionContextScope())
        {
            var testService = container.GetInstance<ITestService>();
            app.Use<TestMiddleware>(testService);
        }
Run Code Online (Sandbox Code Playgroud)

这种方法的问题是 - 在注册期间为中间件创建一个ITestService实例并永久保留(如单例),并且对于每个webapi请求,都会在控制器之间创建和共享新实例(webapi范围)

请不要指出这些问题 - WebApi + Simple Injector + OWIN

使用Simple Injector将依赖项注入OWIN Middleware和每个Web请求

Ste*_*ven 8

无论您在容器中配置哪种类型的生命周期,OWIN的Use<T>方法都会T在OWIN管道中注册提供的单例.因此,当您在活动作用域中解析中间件时,您(隐式)告诉OWIN永远缓存此实例.

你有两个选择:

  1. 确保中间件组件可以在OWIN管道中用作单例,或者
  2. 在每个请求上解析中间件组件.

确保中间件组件可以用作单例很容易.只需在Simple Injector中将其注册为singleton,当您调用时Verify(),Simple Injector将检测此组件是否可用作单例,或者它是否具有较短生活方式的依赖项.但这确实意味着所有依赖项都应该是单例,并且在构建对象图之后,应该通过方法调用传递运行时数据(如DbContext和其他数据对象).我认为这是一个很好的做法,但这可能是你的应用程序的一个很大的变化,可能是一个很大的转变.因此,我认为这超出了这个问题的范围,所以你应该选择2.

如果您的中间件组件具有较短生活方式的依赖项,则应根据请求请求解析该中间件.这意味着你不应该使用OWIN的Use<T>(middleware)方法,因为这会使它成为单身.

这是怎么做的:

app.Use(async (context, next) =>
{
    var middleware = container.GetInstance<TestMiddleware>();

    await middleware.Invoke(context, next);
});
Run Code Online (Sandbox Code Playgroud)

请注意,TestMiddleware每个请求都会解析.这使Simple Injector可以完全控制构建的对象图.但这意味着您需要对您的TestMiddleware班级进行一些小调整.它应该是这样的:

public sealed class TestMiddleware
{
    private readonly ITestService _testService;

    public TestMiddleware(ITestService testService)
    {
        _testService = testService;
    }

    public async Task Invoke(IOwinContext context, Func<Task> next)
    {
        var test = _testService.DoSomething();
        await next();
    }
}
Run Code Online (Sandbox Code Playgroud)

注意,OwinMiddleware参数从构造函数中删除,并由方法中的Func<Task>参数替换Invoke.这允许Simple Injector构造类型,因为它的构造函数将不再包含任何运行时参数.记住:通过构造函数编译时间依赖性,通过方法调用编译运行时数据.

另请注意,中间件不再继承OwinMiddleware.由于中间件没有注入包装的中间件,因此继承它变得毫无用处.