如何检测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:
- 注册
IHttpProvider的方式:
public interface IHttpProvider { HttpContext GetHttpContext(); } public class HttpProvider { HttpContext GetHttpContext() { return HttpContext.Current; } }
- 注册
HttpContextBase的方式:
For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current))
问题根源在于应用基于OWIN构建,而HttpContext.Current属于传统System.Web上下文,与OWIN上下文不兼容。
解决方案
方案一:利用OWIN上下文判断环境
OWIN应用中应使用IOwinContext而非HttpContext.Current来获取请求上下文,步骤如下:
- 注册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()扩展方法。
- 在服务中注入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作用域。
方案二:自定义作用域标识(不依赖上下文)
通过给不同作用域的实例注入标识参数,直接区分来源环境:
- 修改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(); }); } }
- 在服务中接收标识参数
修改FirebirdSessionProvider,通过构造参数接收标识并保存:
public class FirebirdSessionProvider : IClearableSessionProvider { public bool IsFromHttpRequestContext { get; } public FirebirdSessionProvider(bool isHttpContext) { IsFromHttpRequestContext = isHttpContext; } // 实现IClearableSessionProvider的其他方法 }
之后直接通过IsFromHttpRequestContext属性即可判断实例的来源环境,无需访问任何上下文。
内容的提问来源于stack exchange,提问作者fharreau
相关产品推荐
相关产品推荐

