HttpContextLocal.cs 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. using Microsoft.AspNetCore.Http;
  2. using System;
  3. using System.Linq.Expressions;
  4. using System.Reflection;
  5. using System.Threading;
  6. namespace Microsoft.AspNetCore.Http
  7. {
  8. public static class HttpContextLocal
  9. {
  10. private static Func<object> _asyncLocalAccessor;
  11. private static Func<object, object> _holderAccessor;
  12. private static Func<object, HttpContext> _httpContextAccessor;
  13. /// <summary>
  14. /// 获取当前 HttpContext 对象
  15. /// </summary>
  16. /// <returns></returns>
  17. public static HttpContext Current()
  18. {
  19. var asyncLocal = (_asyncLocalAccessor ??= CreateAsyncLocalAccessor())();
  20. if (asyncLocal == null) return null;
  21. var holder = (_holderAccessor ??= CreateHolderAccessor(asyncLocal))(asyncLocal);
  22. if (holder == null) return null;
  23. return (_httpContextAccessor ??= CreateHttpContextAccessor(holder))(holder);
  24. // 创建异步本地访问器
  25. static Func<object> CreateAsyncLocalAccessor()
  26. {
  27. var fieldInfo = typeof(HttpContextAccessor).GetField("_httpContextCurrent", BindingFlags.Static | BindingFlags.NonPublic);
  28. var field = Expression.Field(null, fieldInfo);
  29. return Expression.Lambda<Func<object>>(field).Compile();
  30. }
  31. // 创建常驻 HttpContext 访问器
  32. static Func<object, object> CreateHolderAccessor(object asyncLocal)
  33. {
  34. var holderType = asyncLocal.GetType().GetGenericArguments()[0];
  35. var method = typeof(AsyncLocal<>).MakeGenericType(holderType).GetProperty("Value").GetGetMethod();
  36. var target = Expression.Parameter(typeof(object));
  37. var convert = Expression.Convert(target, asyncLocal.GetType());
  38. var getValue = Expression.Call(convert, method);
  39. return Expression.Lambda<Func<object, object>>(getValue, target).Compile();
  40. }
  41. // 获取 HttpContext 访问器
  42. static Func<object, HttpContext> CreateHttpContextAccessor(object holder)
  43. {
  44. var target = Expression.Parameter(typeof(object));
  45. var convert = Expression.Convert(target, holder.GetType());
  46. var field = Expression.Field(convert, "Context");
  47. var convertAsResult = Expression.Convert(field, typeof(HttpContext));
  48. return Expression.Lambda<Func<object, HttpContext>>(convertAsResult, target).Compile();
  49. }
  50. }
  51. }
  52. }