如何在无HttpContext的OWIN自托管WebAPI中用Castle Windsor注册类PerWebRequest的作用域服务
刚好我之前处理过类似的OWIN自托管Web API结合Castle Windsor的场景,给你分享下具体的实现方案,核心思路是借助OWIN请求上下文来绑定Castle Windsor的生命周期作用域,替代HttpContext的角色:
1. 完善你的SetupMiddleware,绑定请求级LifetimeScope
我们需要在请求进入时创建一个Windsor的ILifetimeScope,并将其存储到IOwinContext中,请求结束后自动释放这个作用域——这样就能实现和PerWebRequest一致的“每个请求一个实例”的效果。
完整的中间件代码如下:
public class SetupMiddleware : OwinMiddleware { private readonly IWindsorContainer _container; public SetupMiddleware(OwinMiddleware next, IWindsorContainer container) : base(next) { _container = container ?? throw new ArgumentNullException(nameof(container)); } public override async Task Invoke(IOwinContext context) { // 创建请求专属的LifetimeScope,用using包裹确保自动释放 using (var requestScope = _container.BeginLifetimeScope()) { // 将作用域存入Owin上下文,方便后续按需获取 context.Items["WindsorRequestScope"] = requestScope; try { // 传递请求给后续中间件/Web API处理 await Next.Invoke(context); } finally { // 请求结束清理上下文存储的作用域引用 context.Items.Remove("WindsorRequestScope"); } } } }
2. 注册服务时使用Scoped生命周期
在Castle Windsor中,LifestyleScoped()会将服务的生命周期绑定到当前的ILifetimeScope——也就是我们在每个请求中创建的那个作用域,完美匹配需求:
var container = new WindsorContainer(); // 注册请求级别的服务 container.Register( Component.For<IYourRequestScopedService>() .ImplementedBy<YourRequestScopedService>() .LifestyleScoped() );
3. 配置OWIN启动流程,确保中间件优先执行
一定要把SetupMiddleware作为第一个中间件注册,这样每个请求都会先创建作用域,再进入Web API处理:
public void Configuration(IAppBuilder app) { var container = new WindsorContainer(); // 先完成所有服务注册... // 注册SetupMiddleware,传入Windsor容器实例 app.Use<SetupMiddleware>(container); // 配置Web API,替换控制器激活器为Windsor实现 var webApiConfig = new HttpConfiguration(); webApiConfig.Services.Replace( typeof(IHttpControllerActivator), new WindsorHttpControllerActivator(container) ); // 添加路由、过滤器等其他Web API配置... app.UseWebApi(webApiConfig); }
4. 可选:自定义ScopeAccessor让Windsor自动识别请求作用域
如果需要更灵活的作用域获取逻辑(比如在非控制器的组件中解析依赖),可以自定义IScopeAccessor,让Windsor自动从Owin上下文获取当前请求的作用域:
public class OwinRequestScopeAccessor : IScopeAccessor { public ILifetimeScope GetScope(CreationContext context) { var owinContext = HttpContext.Current?.GetOwinContext(); if (owinContext == null || !owinContext.Items.TryGetValue("WindsorRequestScope", out var scope)) { throw new InvalidOperationException("未在Owin上下文中找到Windsor作用域,请确保SetupMiddleware已正确注册。"); } return (ILifetimeScope)scope; } } // 将自定义ScopeAccessor注册为单例 container.Register( Component.For<IScopeAccessor>() .ImplementedBy<OwinRequestScopeAccessor>() .LifestyleSingleton() );
关键注意点
- 务必保证
SetupMiddleware是第一个执行的中间件,否则会出现请求已进入Web API但作用域未创建的问题。 - 用
using包裹ILifetimeScope是核心,即使请求抛出异常,作用域也会被自动释放,避免内存泄漏。 - Web API必须替换控制器激活器为Windsor的
WindsorHttpControllerActivator,这样控制器的依赖才会从当前请求的作用域中解析。
内容的提问来源于stack exchange,提问作者Simple Code
相关产品推荐
相关产品推荐

