几天前,我遇到了ASP.Net线程问题。我希望每个Web请求都有一个单例对象。我的工作单位实际上需要这个。我想为每个Web请求实例化一个工作单元,以便身份映射在整个请求中有效。这样我就可以使用IoC透明地将我自己的IUnitOfWork注入到我的存储库类中,并且我可以使用相同的实例来查询然后更新我的实体。
由于我使用Unity,我错误地使用了PerThreadLifeTimeManager。我很快意识到ASP.Net线程模型不支持我想要实现的目标。基本上它使用theadpool并回收线程,这意味着每个线程我得到一个UnitOfWork!但是,我想要的是每个网络请求的一个工作单元。
一些谷歌搜索给了我this great post。这正是我想要的;除了非常容易实现的统一部分。
这是我对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());
希望能节省一些时间。
答案 0 :(得分:25)
整洁的解决方案,但LifetimeManager的每个实例都应使用唯一键而不是常量:
private string _key = string.Format("PerCallContextLifeTimeManager_{0}", Guid.NewGuid());
否则,如果您在PerCallContextLifeTimeManager中注册了多个对象,则它们共享相同的密钥以访问CallContext,并且您将无法获得预期的对象。
还值得实现RemoveValue以确保清理对象:
public override void RemoveValue()
{
CallContext.FreeNamedDataSlot(_key);
}
答案 1 :(得分:21)
虽然调用这个PerCallContextLifeTimeManager很好,但我很确定不“安全”被认为是ASP.Net Per-request 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: - (
有关此内容的更多信息,请访问:
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html
答案 2 :(得分:4)
感谢您的贡献,
但提出实施的问题有两个缺点,其中一个是Steven Robbins在his answer和Micah Zoltu in a comment已经说过的严重错误。
目前,Unity.Mvc Nuget软件包提供了PerRequestLifetimeManager
来完成工作。不要忘记在引导代码中注册其关联的UnityPerRequestHttpModule
,否则也不会处理释放依赖关系。
使用bootstrapping
DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
或在web.config中system.webServer/modules
<add name="UnityPerRequestHttpModule" type="Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule, Microsoft.Practices.Unity.Mvc" preCondition="managedHandler" />
它的当前实现似乎也适用于Web表单。它甚至不依赖于MVC。不幸的是,它的汇编确实存在,因为它包含了其他一些类。
请注意,如果您使用已解析的依赖项使用某个自定义http模块,它们可能已经放置在模块EndRequest
中。这取决于模块执行顺序。