CallerThreadContext.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using System.Reflection;
  5. using System.Web;
  6. using System.Runtime.Remoting.Messaging;
  7. namespace Amib.Threading
  8. {
  9. #region CallerThreadContext class
  10. /// <summary>
  11. /// This class stores the caller call context in order to restore
  12. /// it when the work item is executed in the thread pool environment.
  13. /// </summary>
  14. internal class CallerThreadContext
  15. {
  16. #region Prepare reflection information
  17. // Cached type information.
  18. private static MethodInfo getLogicalCallContextMethodInfo =
  19. typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
  20. private static MethodInfo setLogicalCallContextMethodInfo =
  21. typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
  22. private static string HttpContextSlotName = GetHttpContextSlotName();
  23. private static string GetHttpContextSlotName()
  24. {
  25. FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
  26. if( fi != null )
  27. return (string)fi.GetValue(null);
  28. else // Use the default "HttpContext" slot name
  29. return "HttpContext";
  30. }
  31. #endregion
  32. #region Private fields
  33. private HttpContext _httpContext = null;
  34. private LogicalCallContext _callContext = null;
  35. #endregion
  36. /// <summary>
  37. /// Constructor
  38. /// </summary>
  39. private CallerThreadContext()
  40. {
  41. }
  42. public bool CapturedCallContext
  43. {
  44. get
  45. {
  46. return (null != _callContext);
  47. }
  48. }
  49. public bool CapturedHttpContext
  50. {
  51. get
  52. {
  53. return (null != _httpContext);
  54. }
  55. }
  56. /// <summary>
  57. /// Captures the current thread context
  58. /// </summary>
  59. /// <returns></returns>
  60. public static CallerThreadContext Capture(
  61. bool captureCallContext,
  62. bool captureHttpContext)
  63. {
  64. Debug.Assert(captureCallContext || captureHttpContext);
  65. CallerThreadContext callerThreadContext = new CallerThreadContext();
  66. // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
  67. // Capture Call Context
  68. if(captureCallContext && (getLogicalCallContextMethodInfo != null))
  69. {
  70. callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
  71. if (callerThreadContext._callContext != null)
  72. {
  73. callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
  74. }
  75. }
  76. // Capture httpContext
  77. if (captureHttpContext && (null != HttpContext.Current))
  78. {
  79. callerThreadContext._httpContext = HttpContext.Current;
  80. }
  81. return callerThreadContext;
  82. }
  83. /// <summary>
  84. /// Applies the thread context stored earlier
  85. /// </summary>
  86. /// <param name="callerThreadContext"></param>
  87. public static void Apply(CallerThreadContext callerThreadContext)
  88. {
  89. if (null == callerThreadContext)
  90. {
  91. throw new ArgumentNullException("callerThreadContext");
  92. }
  93. // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
  94. // Restore call context
  95. if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
  96. {
  97. setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
  98. }
  99. // Restore HttpContext
  100. if (callerThreadContext._httpContext != null)
  101. {
  102. CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
  103. }
  104. }
  105. }
  106. #endregion
  107. }
  108. /*
  109. // Ami Bar
  110. // [email protected]
  111. using System;
  112. using System.Threading;
  113. using System.Globalization;
  114. using System.Security.Principal;
  115. using System.Reflection;
  116. using System.Runtime.Remoting.Contexts;
  117. namespace Amib.Threading.Internal
  118. {
  119. #region CallerThreadContext class
  120. /// <summary>
  121. /// This class stores the caller thread context in order to restore
  122. /// it when the work item is executed in the context of the thread
  123. /// from the pool.
  124. /// Note that we can't store the thread's CompressedStack, because
  125. /// it throws a security exception
  126. /// </summary>
  127. public class CallerThreadContext
  128. {
  129. private CultureInfo _culture = null;
  130. private CultureInfo _cultureUI = null;
  131. private IPrincipal _principal;
  132. private System.Runtime.Remoting.Contexts.Context _context;
  133. private static FieldInfo _fieldInfo = GetFieldInfo();
  134. private static FieldInfo GetFieldInfo()
  135. {
  136. Type threadType = typeof(Thread);
  137. return threadType.GetField(
  138. "m_Context",
  139. BindingFlags.Instance | BindingFlags.NonPublic);
  140. }
  141. /// <summary>
  142. /// Constructor
  143. /// </summary>
  144. private CallerThreadContext()
  145. {
  146. }
  147. /// <summary>
  148. /// Captures the current thread context
  149. /// </summary>
  150. /// <returns></returns>
  151. public static CallerThreadContext Capture()
  152. {
  153. CallerThreadContext callerThreadContext = new CallerThreadContext();
  154. Thread thread = Thread.CurrentThread;
  155. callerThreadContext._culture = thread.CurrentCulture;
  156. callerThreadContext._cultureUI = thread.CurrentUICulture;
  157. callerThreadContext._principal = Thread.CurrentPrincipal;
  158. callerThreadContext._context = Thread.CurrentContext;
  159. return callerThreadContext;
  160. }
  161. /// <summary>
  162. /// Applies the thread context stored earlier
  163. /// </summary>
  164. /// <param name="callerThreadContext"></param>
  165. public static void Apply(CallerThreadContext callerThreadContext)
  166. {
  167. Thread thread = Thread.CurrentThread;
  168. thread.CurrentCulture = callerThreadContext._culture;
  169. thread.CurrentUICulture = callerThreadContext._cultureUI;
  170. Thread.CurrentPrincipal = callerThreadContext._principal;
  171. // Uncomment the following block to enable the Thread.CurrentThread
  172. /*
  173. if (null != _fieldInfo)
  174. {
  175. _fieldInfo.SetValue(
  176. Thread.CurrentThread,
  177. callerThreadContext._context);
  178. }
  179. * /
  180. }
  181. }
  182. #endregion
  183. }
  184. */