Unity 中的单例每次调用上下文(Web 请求)
几天前,我遇到了 ASP.Net 线程的问题。 我希望每个网络请求都有一个单例对象。 我实际上需要这个来完成我的工作单位。 我想为每个 Web 请求实例化一个工作单元,以便身份映射在整个请求过程中都有效。 这样我就可以使用 IoC 将我自己的 IUnitOfWork 透明地注入到我的存储库类中,并且我可以使用相同的实例来查询然后更新我的实体。
由于我使用的是Unity,所以我错误地使用了PerThreadLifeTimeManager。 我很快意识到 ASP.Net 线程模型不支持我想要实现的目标。 基本上它使用线程池并回收线程,这意味着我每个线程获得一个 UnitOfWork! 然而,我想要的是每个网络请求一个工作单元。
一些谷歌搜索给了我
这是我对 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());
希望它可以节省一些时间。
A few days ago, I had an issue with ASP.Net threading. I wanted to have a singleton object per web request. I actually need this for my unit of work. I wanted to instantiate a unit of work per web request so that identity map is valid through out the request. This way I could use an IoC to inject my own IUnitOfWork to my repository classes transparently, and I could use the same instance to query and then update my entities.
Since I am using Unity, I mistakenly used PerThreadLifeTimeManager. I soon realised that ASP.Net threading model does not support what I want to achieve. Basically it uses a threadpool and recycles threads, and that means that I get one UnitOfWork per thread!! However, what I wanted was one unit of work per web request.
A bit of googling gave me this great post. That was exactly what I wanted; except for the unity part which was quite easy to achieve.
This is my implementation for PerCallContextLifeTimeManager for unity:
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()
{
}
}
And of course I use this to register my unit of work with a code similar to this:
unityContainer
.RegisterType<IUnitOfWork, MyDataContext>(
new PerCallContextLifeTimeManager(),
new InjectionConstructor());
Hope it saves someone a bit of time.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一种巧妙的解决方案,但 LifetimeManager 的每个实例都应该使用唯一的键而不是常量:
否则,如果您有多个向 PerCallContextLifeTimeManager 注册的对象,它们将共享相同的键来访问 CallContext,并且您将无法获得预期的对象后退。
还值得实现RemoveValue来确保对象被清理:
Neat solution, but each instance of LifetimeManager should use a unique key rather than a constant:
Otherwise if you have more than one object registered with PerCallContextLifeTimeManager, they're sharing the same key to access CallContext, and you won't get your expected object back.
Also worth implementing RemoveValue to ensure objects are cleaned up:
虽然调用此 PerCallContextLifeTimeManager 很好,但我很确定这不“安全”地被视为 ASP.Net Per-request LifeTimeManager。
如果 ASP.Net 进行线程交换,那么通过 CallContext 传递到新线程的唯一就是当前的 HttpContext - 您存储在 CallContext 中的任何其他内容都将消失。 这意味着在重负载下,上面的代码可能会产生意想不到的结果 - 我想找出原因将是一个真正的痛苦!
唯一“安全”的方法是使用 HttpContext.Current.Items,或者执行类似的操作:
这显然意味着依赖于 System.Web :-(
有关这方面的更多信息,请访问:
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html
While this is fine calling this PerCallContextLifeTimeManager, I'm pretty sure this is not "safe" to be considered an ASP.Net Per-request LifeTimeManager.
If ASP.Net does its thread-swap then the only thing taken across to the new thread through CallContext is the current HttpContext - anything else you store in CallContext will be gone. This means under heavy load the code above could have unintended results - and I imagine it would be a real pain to track down why!
The only "safe" way to do this is with HttpContext.Current.Items, or doing something like:
This obviously means taking dependencies on System.Web :-(
Much more information on this available at:
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html
感谢您的贡献,
但是提出的实施问题有两个缺点,其中之一是 Steven Robbins 在 他的答案 和 Micah Zoltu 中已经指出的严重错误评论中。
目前,Unity.Mvc Nuget 包提供
PerRequestLifetimeManager
来完成这项工作。 不要忘记在引导代码中注册其关联的 UnityPerRequestHttpModule ,否则也不会处理依赖项释放。使用引导程序
或在 web.config
system.webServer/modules
中使用它当前的实现似乎也适用于 Web 表单。 而且它甚至不依赖于 MVC。 不幸的是,它的程序集确实如此,因为它包含一些其他类。
请注意,如果您使用已解析的依赖项使用某些自定义 http 模块,它们可能已经在模块
EndRequest
中进行了处理。 这取决于模块的执行顺序。Thanks for your contribution,
But the question proposed implementation has two drawbacks, one of which is a serious bug as already stated by Steven Robbins in his answer and Micah Zoltu in a comment.
Currently, Unity.Mvc Nuget package supplies a
PerRequestLifetimeManager
for doing the work. Do not forget to register its associatedUnityPerRequestHttpModule
in bootstrapping code otherwise dependencies releasing will not be handled either.Using bootstrapping
or in web.config
system.webServer/modules
It appears its current implementation is also suitable for web forms. And it does not even depend on MVC. Unfortunately, its assembly does, because of some other classes it contains.
Beware, in case you use some custom http module using your resolved dependencies, they may be already disposed in the module
EndRequest
. It depends on module execution order.