You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在无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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:42:47