Singleton每呼叫上下文(Web请求)在Unity

前几天我用ASP.Net线程有这个问题。 我想每个Web请求有一个单例对象。 我实际上需要这个工作单位。 我想为每个Web请求实例化一个工作单元,以便通过请求标识映射是有效的。 这样我就可以使用IoC将我自己的IUnitOfWork透明地注入到我的存储库类中,并且可以使用同一个实例来查询并更新我的实体。

由于我使用Unity,我错误地使用了PerThreadLifeTimeManager。 我很快意识到,ASP.Net线程模型不支持我想要的。 基本上它使用一个theadpool和回收线程,这意味着我得到一个UnitOfWork每个线程! 但是,我想要的是每个Web请求的一个工作单元。

有一点使用Google给了我这个伟大的职位 。 那正是我想要的; 除了很容易达到的统一部分。

这是我实现PerCallContextLifeTimeManager为统一:

public class PerCallContextLifeTimeManager : LifetimeManager { private const string Key = "SingletonPerCallContext"; public override object GetValue() { return CallContext.GetData(Key); } public override void SetValue(object newValue) { CallContext.SetData(Key, newValue); } public override void RemoveValue() { } } 

当然,我用这个来注册我的工作单位,代码如下:

 unityContainer .RegisterType<IUnitOfWork, MyDataContext>( new PerCallContextLifeTimeManager(), new InjectionConstructor()); 

希望能节省一些时间。

整洁的解决scheme,但LifetimeManager的每个实例应该使用一个唯一的键而不是一个常量:

 private string _key = string.Format("PerCallContextLifeTimeManager_{0}", Guid.NewGuid()); 

否则,如果你有多个注册PerCallContextLifeTimeManager的对象,它们共享相同的键来访问CallContext,并且你不会得到你想要的对象。

还值得实施RemoveValue,以确保对象被清理:

 public override void RemoveValue() { CallContext.FreeNamedDataSlot(_key); } 

虽然这很好的调用这个PerCallContextLifeTimeManager,我敢肯定这是不是 “安全”被视为一个ASP.Net每请求LifeTimeManager。

如果ASP.Net执行线程交换,那么通过CallContext传递给新线程的唯一事情就是当前的HttpContext – 您在CallContext中存储的任何内容都将消失。 这意味着在重载的情况下,上面的代码可能会产生意想不到的结果 – 我想这将是一个真正的痛苦,追查为什么!

唯一“安全”的方法是使用HttpContext.Current.Items,或者做一些事情:

 public class PerCallContextOrRequestLifeTimeManager : LifetimeManager { private string _key = string.Format("PerCallContextOrRequestLifeTimeManager_{0}", Guid.NewGuid()); public override object GetValue() { if(HttpContext.Current != null) return GetFromHttpContext(); else return GetFromCallContext(); } public override void SetValue(object newValue) { if(HttpContext.Current != null) return SetInHttpContext(); else return SetInCallContext(); } public override void RemoveValue() { } } 

这显然意味着依赖于System.Web 🙁

关于此的更多信息可在以下url获得:

http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html

感谢您的贡献,

但是这个提议的实现有两个缺陷,其中一个是Steven Robbins在回答中已经提到的一个严重的错误,Micah Zoltu 在评论中提到了这个问题 。

  1. 调用上下文不保证由asp.net保存一个请求。 在负载下,它可以切换到另一个,导致build议的实现中断。
  2. 它不会在请求结束时处理释放依赖项。

目前,Unity.Mvc Nuget包提供了一个PerRequestLifetimeManager来完成这个工作。 不要忘记在引导代码中注册相关的UnityPerRequestHttpModule ,否则依赖性释放也不会被处理。

使用引导

 DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule)); 

或者在web.config system.webServer/modules

 <add name="UnityPerRequestHttpModule" type="Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule, Microsoft.Practices.Unity.Mvc" preCondition="managedHandler" /> 

看来它目前的实现也适合于网页表单。 而且它甚至不依赖于MVC。 不幸的是,它的程序集,因为它包含的其他类。

要小心,如果您使用已parsing的依赖关系使用某个自定义http模块,则可能已经将其放置在模块EndRequest 。 这取决于模块执行顺序。

Interesting Posts