解決Asp.net Mvc中使用異步的時候HttpContext.Current為null的方法
在項目中使用異步(async await)的時候發現一個現象,HttpContext.Current為null,導致一系列的問題
.
上網查了一些資料后找到了一個對象: System.Threading.SynchronizationContext (提供在各種同步模型中傳播同步上下文的基本功能。), 跟蹤代碼后發現 SynchronizationContext.Current 返回的是一個叫 System.Web.LegacyAspNetSynchronizationContext 的內部類對象,這個對象中有個字段叫 _application,類型為 System.Web.HttpApplication. 有了 System.Web.HttpApplication 對象就好辦多了,直接使用 Context 屬性即可. (當然 SynchronizationContext.Current 不一定只可能返回 System.Web.LegacyAspNetSynchronizationContext ,具體沒有研究了)
代碼:
class Test
{
void Test1()
{
SynchronizationContext context = SynchronizationContext.Current;
Delegate factory = null;
Type type = context.GetType();
if (!type.FullName.Equals("System.Web.LegacyAspNetSynchronizationContext"))
{
//目前只研究了這個
return;
}
//找到字段
ParameterExpression sourceExpression = Expression.Parameter(typeof(System.Threading.SynchronizationContext), "context");
//目前支持 System.Web.LegacyAspNetSynchronizationContext 內部類
//查找 private HttpApplication _application 字段
Expression sourceInstance = Expression.Convert(sourceExpression, type);
FieldInfo applicationFieldInfo = type.GetField("_application", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
Expression fieldExpression = Expression.Field(sourceInstance, applicationFieldInfo);
factory = Expression.Lambda<Func<System.Threading.SynchronizationContext, System.Web.HttpApplication>>(fieldExpression, sourceExpression).Compile();
//拿到了這個委托就好辦了
System.Web.HttpApplication httpApplication = ((Func<System.Threading.SynchronizationContext, System.Web.HttpApplication>)factory)(context);
//直接使用屬性
System.Web.HttpContext httpContext = httpApplication.Context;
}
} 封裝一下:
/// <summary>
/// 在同步上下文中查找當前會話<see cref="System.Web.HttpContext" />對象
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static HttpContext FindHttpContext(this SynchronizationContext context)
{
if (context == null)
{
return null;
}
var factory = GetFindApplicationDelegate(context);
if (factory == null)
{
return null;
}
return factory(context).Context;
} 接下來再為HttpContext對象添加一個System.Web命名空間的擴展方法:
/// <summary>
/// 確定異步狀態的上下文可用
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static HttpContext Check(this HttpContext context)
{
if (context==null)
{
context = SynchronizationContext.Current.FindHttpContext();
}
return context;
} 為了性能考慮,把factory緩存起來即可.
完了之后,使用HttpContext對象就可以這么做:
HttpContext context=HttpContext.Current.Check(); //這時候context還為null的話,就是姿勢不對了(包括 websocket ,沒有在會話中使用等等)
以后就可以愉快的使用異步控制器啦!
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!