A few days ago I had this 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.
几天前,我用ASP做了这个问题。净线程。我希望每个web请求都有一个单例对象。我的工作单位需要这个。我想为每个web请求实例化一个工作单元,这样身份映射在整个请求中都是有效的。通过这种方式,我可以使用IoC将我自己的IUnitOfWork透明地注入到我的存储库类中,并且我可以使用相同的实例来查询,然后更新我的实体。
Since I am using Unity, I mistakenly used PerThreadLifeTimeManager. I soon realised that ASP.Net threading model does not support what I want to acheive. Basically it uses a theadpool 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.
因为我在使用Unity,所以我错误地使用了PerThreadLifeTimeManager。我很快意识到ASP。Net线程模型不支持我想要的。基本上,它使用一个theadpool并回收线程,这意味着我每一个线程得到一个工作单元!然而,我想要的是每个web请求的一个工作单元。
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 acheive.
有一点谷歌搜索给了我这个伟大的职位。这正是我想要的;除了统一的部分,这很容易实现。
This is my implementation for PerCallContextLifeTimeManager for unity:
这是我对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()
{
}
}
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.
希望它能节省一些时间。
3 个解决方案
#1
25
Neat solution, but each instance of LifetimeManager should use a unique key rather than a constant:
简洁的解决方案,但是LifetimeManager的每个实例都应该使用唯一的键而不是常量:
private string _key = string.Format("PerCallContextLifeTimeManager_{0}", Guid.NewGuid());
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.
否则,如果在PerCallContextLifeTimeManager上注册了多个对象,那么它们将共享相同的键来访问CallContext,您将无法获得预期的对象。
Also worth implementing RemoveValue to ensure objects are cleaned up:
同样值得实现RemoveValue以确保对象被清理:
public override void RemoveValue()
{
CallContext.FreeNamedDataSlot(_key);
}
#2
20
While this is fine calling this PerCallContextLifeTimeManager, I'm pretty sure this is not "safe" to be considered an ASP.Net Per-request LifeTimeManager.
尽管调用PerCallContextLifeTimeManager是没问题的,但我敢肯定这不是一个“安全”的ASP。净每请求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!
如果ASP。Net执行它的线程交换,然后通过CallContext传递到新线程的唯一东西就是当前的HttpContext——你在CallContext中存储的任何其他东西都将消失。这意味着,在繁重的负载下,上面的代码可能会产生意想不到的结果——我想,找到原因将是一件非常痛苦的事情!
The only "safe" way to do this is with HttpContext.Current.Items, or doing something like:
唯一的“安全”方法是使用HttpContext.Current。项目,或做类似的事情:
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()
{
}
}
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
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html
#3
3
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.
但是,这个问题的提出有两个缺点,其中一个问题就像Steven Robbins在他的回答中提到的,Micah Zoltu在评论中提到的。
- Call context is not guaranteed to be preserved by asp.net for a single request. Under load, it can switch to another one, causing proposed implementation to breaks.
- 调用上下文不能保证由asp.net为单个请求保留。在负载下,它可以切换到另一个,导致建议的实现中断。
- It does not handle releasing of dependencies at request end.
- 它不处理在请求端释放依赖项。
Currently, Unity.Mvc Nuget package supply a PerRequestLifetimeManager
for doing the work. Do not forget to register its associated UnityPerRequestHttpModule
in bootstrapping code otherwise dependencies releasing will not be handled either.
目前,团结。Mvc Nuget包提供一个PerRequestLifetimeManager来完成这项工作。不要忘记在引导代码中注册它的相关联的unityperrequesthpmodule,否则依赖性释放也不会被处理。
Using bootstrapping
使用引导
DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
or in web.config system.webServer/modules
或在web。配置system.webServer /模块
<add name="UnityPerRequestHttpModule" type="Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule, Microsoft.Practices.Unity.Mvc" preCondition="managedHandler" />
It appears its current implementation is also suitable for web forms. And it does not even depend on MVC. Unfortunately, its assembly does, cause of some other classes it contains.
它的当前实现似乎也适用于web表单。它甚至不依赖于MVC。不幸的是,它的程序集产生了它所包含的其他类。
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.
请注意,如果您使用已解析的依赖项使用一些自定义http模块,那么它们可能已经在模块EndRequest中处理了。这取决于模块的执行顺序。
#1
25
Neat solution, but each instance of LifetimeManager should use a unique key rather than a constant:
简洁的解决方案,但是LifetimeManager的每个实例都应该使用唯一的键而不是常量:
private string _key = string.Format("PerCallContextLifeTimeManager_{0}", Guid.NewGuid());
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.
否则,如果在PerCallContextLifeTimeManager上注册了多个对象,那么它们将共享相同的键来访问CallContext,您将无法获得预期的对象。
Also worth implementing RemoveValue to ensure objects are cleaned up:
同样值得实现RemoveValue以确保对象被清理:
public override void RemoveValue()
{
CallContext.FreeNamedDataSlot(_key);
}
#2
20
While this is fine calling this PerCallContextLifeTimeManager, I'm pretty sure this is not "safe" to be considered an ASP.Net Per-request LifeTimeManager.
尽管调用PerCallContextLifeTimeManager是没问题的,但我敢肯定这不是一个“安全”的ASP。净每请求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!
如果ASP。Net执行它的线程交换,然后通过CallContext传递到新线程的唯一东西就是当前的HttpContext——你在CallContext中存储的任何其他东西都将消失。这意味着,在繁重的负载下,上面的代码可能会产生意想不到的结果——我想,找到原因将是一件非常痛苦的事情!
The only "safe" way to do this is with HttpContext.Current.Items, or doing something like:
唯一的“安全”方法是使用HttpContext.Current。项目,或做类似的事情:
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()
{
}
}
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
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html
#3
3
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.
但是,这个问题的提出有两个缺点,其中一个问题就像Steven Robbins在他的回答中提到的,Micah Zoltu在评论中提到的。
- Call context is not guaranteed to be preserved by asp.net for a single request. Under load, it can switch to another one, causing proposed implementation to breaks.
- 调用上下文不能保证由asp.net为单个请求保留。在负载下,它可以切换到另一个,导致建议的实现中断。
- It does not handle releasing of dependencies at request end.
- 它不处理在请求端释放依赖项。
Currently, Unity.Mvc Nuget package supply a PerRequestLifetimeManager
for doing the work. Do not forget to register its associated UnityPerRequestHttpModule
in bootstrapping code otherwise dependencies releasing will not be handled either.
目前,团结。Mvc Nuget包提供一个PerRequestLifetimeManager来完成这项工作。不要忘记在引导代码中注册它的相关联的unityperrequesthpmodule,否则依赖性释放也不会被处理。
Using bootstrapping
使用引导
DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
or in web.config system.webServer/modules
或在web。配置system.webServer /模块
<add name="UnityPerRequestHttpModule" type="Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule, Microsoft.Practices.Unity.Mvc" preCondition="managedHandler" />
It appears its current implementation is also suitable for web forms. And it does not even depend on MVC. Unfortunately, its assembly does, cause of some other classes it contains.
它的当前实现似乎也适用于web表单。它甚至不依赖于MVC。不幸的是,它的程序集产生了它所包含的其他类。
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.
请注意,如果您使用已解析的依赖项使用一些自定义http模块,那么它们可能已经在模块EndRequest中处理了。这取决于模块的执行顺序。