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

如何检测StructureMap解析实例来自HttpContext还是ThreadContext?

在OWIN环境下判断StructureMap HybridHttpOrThreadLocalScoped实例的作用域来源

问题背景

我使用StructureMap 2.6.3注册了如下服务:

public class PersistenceRegistry : Registry
{
    public PersistenceRegistry()
    {
        For<IClearableSessionProvider>().HybridHttpOrThreadLocalScoped().Use<FirebirdSessionProvider>();   
    }
}

需要判断解析得到的IClearableSessionProvider实例是来自HttpContext作用域还是ThreadContext作用域,且无需直接访问上下文,仅需区分当前处于HttpRequest环境还是后台线程环境。

此前尝试通过注入HttpContext相关依赖判断环境,但HttpContext.Current始终返回null:

  1. 注册IHttpProvider的方式:
public interface IHttpProvider
{
    HttpContext GetHttpContext();
}

public class HttpProvider
{
    HttpContext GetHttpContext()
    {
        return HttpContext.Current;
    }
}
  1. 注册HttpContextBase的方式:
For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current))

问题根源在于应用基于OWIN构建,而HttpContext.Current属于传统System.Web上下文,与OWIN上下文不兼容。

解决方案

方案一:利用OWIN上下文判断环境

OWIN应用中应使用IOwinContext而非HttpContext.Current来获取请求上下文,步骤如下:

  1. 注册OWIN上下文到StructureMap
    在OWIN启动类中,将IOwinContext注册为从当前OWIN环境获取:
public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var container = new Container(new PersistenceRegistry());
        
        container.Configure(cfg =>
        {
            // 通过System.Web.Owin扩展方法获取OWIN上下文
            cfg.For<IOwinContext>().Use(() => HttpContext.Current.GetOwinContext());
        });
        
        // 其他OWIN中间件配置逻辑
    }
}

注意:需引用System.Web.Owin程序集以使用GetOwinContext()扩展方法。

  1. 在服务中注入OWIN上下文并判断
    修改FirebirdSessionProvider,注入IOwinContext后通过其是否为空判断环境:
public class FirebirdSessionProvider : IClearableSessionProvider
{
    private readonly IOwinContext _owinContext;

    public FirebirdSessionProvider(IOwinContext owinContext)
    {
        _owinContext = owinContext;
    }

    public bool IsFromHttpRequestContext()
    {
        // OWIN上下文不为空则处于HttpRequest环境
        return _owinContext != null;
    }

    // 实现IClearableSessionProvider的其他方法
}

若_owinContext不为空,说明实例来自Http作用域;反之则来自Thread作用域。

方案二:自定义作用域标识(不依赖上下文)

通过给不同作用域的实例注入标识参数,直接区分来源环境:

  1. 修改StructureMap注册逻辑
    分别注册Http作用域和Thread作用域的实例,并传入不同的标识参数:
public class PersistenceRegistry : Registry
{
    public PersistenceRegistry()
    {
        // Http作用域实例,传入isHttpContext=true
        For<IClearableSessionProvider>().HttpScoped().Use<FirebirdSessionProvider>()
            .Ctor<bool>("isHttpContext").Is(true);
        
        // Thread作用域实例,传入isHttpContext=false并命名
        For<IClearableSessionProvider>().ThreadLocalScoped().Use<FirebirdSessionProvider>()
            .Ctor<bool>("isHttpContext").Is(false)
            .Named("ThreadScoped");
        
        // 配置Hybrid策略,优先使用Http作用域实例, fallback到Thread作用域
        For<IClearableSessionProvider>().HybridHttpOrThreadLocalScoped()
            .AddInstances(x =>
            {
                x.Type<FirebirdSessionProvider>().Named("HttpScoped").IsHttpScoped();
                x.Type<FirebirdSessionProvider>().Named("ThreadScoped").IsThreadLocalScoped();
            });
    }
}
  1. 在服务中接收标识参数
    修改FirebirdSessionProvider,通过构造参数接收标识并保存:
public class FirebirdSessionProvider : IClearableSessionProvider
{
    public bool IsFromHttpRequestContext { get; }

    public FirebirdSessionProvider(bool isHttpContext)
    {
        IsFromHttpRequestContext = isHttpContext;
    }

    // 实现IClearableSessionProvider的其他方法
}

之后直接通过IsFromHttpRequestContext属性即可判断实例的来源环境,无需访问任何上下文。

内容的提问来源于stack exchange,提问作者fharreau

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:01:42