Skip to main content
 首页 » 编程设计

c#之OWIN 中间件 + Web API + 简单注入(inject)器

2024年01月21日27小虾米

我目前使用的 WebApiRequestLifestyle 具有默认范围的生活方式。我想在 OWIN 中间件和 API Controller 之一中注入(inject)服务,并且服务的范围应该仍然是 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; 
    } 
} 

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

这就是我现在的做法:
     using (container.BeginExecutionContextScope()) 
        { 
            var testService = container.GetInstance<ITestService>(); 
            app.Use<TestMiddleware>(testService); 
        } 

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

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

Injecting a dependency into OWIN Middleware and per web-request with Simple Injector

请您参考如下方法:

OWIN的Use<T>方法注册提供的T作为 OWIN 管道中的单例,无论您在容器中配置该类型的生命周期是什么。因此,当您在事件范围内解析中间件时,您(隐含地)告诉 OWIN 永久缓存此实例。

您在这里有两个选择:

  • 确保中间件组件可以用作 OWIN 管道中的单例,或
  • 解析每个请求的中间件组件。

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

    如果您的中间件组件具有较短生命周期的依赖关系,您应该根据请求请求解析该中间件。这意味着您不应该使用 OWIN 的 Use<T>(middleware)方法,因为这会使它成为单例。

    这是如何做到的:
    app.Use(async (context, next) => 
    { 
        var middleware = container.GetInstance<TestMiddleware>(); 
     
        await middleware.Invoke(context, next); 
    }); 
    

    请注意 TestMiddleware在每个请求上解决。这使 Simple Injector 可以完全控制已构建的对象图。然而,这意味着您需要对您的 TestMiddleware 进行小幅调整。类(class)。它应该是这样的:
    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(); 
        } 
    } 
    

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

    另请注意,中间件不是从 OwinMiddleware 继承的。了。由于中间件没有注入(inject)封装的中间件,因此从它继承变得毫无用处。