Entity Framework ASP.NET 和多线程中每个请求的上下文
Entity Framework Context per request in ASP.NET and Multi Threading
我的应用程序在 ASP.NET MVC 4.
我在每个请求中使用 BDContext,正如此处许多问题中所推荐的那样。
我有:
public static class ContextPerRequest {
private const string myDbPerRequestContext = "dbGeTraining_";
public static DbGesForma_v2 db {
get {
if (!HttpContext.Current.Items.Contains(myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString())) {
HttpContext.Current.Items.Add(myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString(), new DbGesForma_v2());
}
return HttpContext.Current.Items[myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString()] as DbGesForma_v2;
}
}
/// <summary>
/// Called automatically on Application_EndRequest()
/// </summary>
public static void DisposeDbContextPerRequest() {
// Getting dbContext directly to avoid creating it in case it was not already created.
var entityContext = HttpContext.Current.Items[myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString()] as DbGesForma_v2;
if (entityContext != null) {
entityContext.Dispose();
HttpContext.Current.Items.Remove(myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString());
}
}
}
我用 Application_EndRequest() 方法处理它。这种方法长期有效。
现在我正在尝试用这样的异步任务来实现一些东西:
Task.Factory.StartNew(() => {
DoSomething();
});
这会带来一些问题。
- HttpContext在子线程中为null,用于context的key
- 即使我能够通过 httpcontext 或 null 检查它,如果子线程 运行 比请求本身花费的时间更长,它会在线程完成之前被处理掉,这将是有问题的。
有什么解决办法吗?
我不确定您使用的 ASP.NET 是哪个版本。无论如何,ASP.NET MVC(也是 WebAPI)有支持那些 'per-request' 实例的 DependencyResolver。
http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection
此外,我建议您将 DI 框架与 DependencyResolver 一起使用,而不是实现每个请求的实例工厂(或类似的东西)。大多数知名的 DI 框架都支持与 ASP.NET.
的集成
例如;
- Unity
- Autofac
- SimpleInjector
- 和许多其他人
我找到了一个侵入性较小的解决方案。 (我知道,Gongdo Gong 解决方案要好得多,但需要在正在进行的项目中进行大量更改)
当我调用异步任务时,我通过 HttpContext 传递,最后我处理上下文。
像这样:
System.Web.HttpContext htcont = System.Web.HttpContext.Current;
Task.Factory.StartNew(() => {
System.Web.HttpContext.Current = htcont;
DoSomething();
ContextPerRequest.DisposeDbContextPerRequest();
});
这样 HttpContext 就可以在子线程中使用,并且上下文会在作业结束时被释放。
我的应用程序在 ASP.NET MVC 4.
我在每个请求中使用 BDContext,正如此处许多问题中所推荐的那样。
我有:
public static class ContextPerRequest {
private const string myDbPerRequestContext = "dbGeTraining_";
public static DbGesForma_v2 db {
get {
if (!HttpContext.Current.Items.Contains(myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString())) {
HttpContext.Current.Items.Add(myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString(), new DbGesForma_v2());
}
return HttpContext.Current.Items[myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString()] as DbGesForma_v2;
}
}
/// <summary>
/// Called automatically on Application_EndRequest()
/// </summary>
public static void DisposeDbContextPerRequest() {
// Getting dbContext directly to avoid creating it in case it was not already created.
var entityContext = HttpContext.Current.Items[myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString()] as DbGesForma_v2;
if (entityContext != null) {
entityContext.Dispose();
HttpContext.Current.Items.Remove(myDbPerRequestContext + HttpContext.Current.GetHashCode().ToString("x") + Thread.CurrentContext.ContextID.ToString());
}
}
}
我用 Application_EndRequest() 方法处理它。这种方法长期有效。
现在我正在尝试用这样的异步任务来实现一些东西:
Task.Factory.StartNew(() => {
DoSomething();
});
这会带来一些问题。
- HttpContext在子线程中为null,用于context的key
- 即使我能够通过 httpcontext 或 null 检查它,如果子线程 运行 比请求本身花费的时间更长,它会在线程完成之前被处理掉,这将是有问题的。
有什么解决办法吗?
我不确定您使用的 ASP.NET 是哪个版本。无论如何,ASP.NET MVC(也是 WebAPI)有支持那些 'per-request' 实例的 DependencyResolver。
http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection
此外,我建议您将 DI 框架与 DependencyResolver 一起使用,而不是实现每个请求的实例工厂(或类似的东西)。大多数知名的 DI 框架都支持与 ASP.NET.
的集成例如;
- Unity
- Autofac
- SimpleInjector
- 和许多其他人
我找到了一个侵入性较小的解决方案。 (我知道,Gongdo Gong 解决方案要好得多,但需要在正在进行的项目中进行大量更改)
当我调用异步任务时,我通过 HttpContext 传递,最后我处理上下文。
像这样:
System.Web.HttpContext htcont = System.Web.HttpContext.Current;
Task.Factory.StartNew(() => {
System.Web.HttpContext.Current = htcont;
DoSomething();
ContextPerRequest.DisposeDbContextPerRequest();
});
这样 HttpContext 就可以在子线程中使用,并且上下文会在作业结束时被释放。