224 lines
6.8 KiB
C#
224 lines
6.8 KiB
C#
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Threading;
|
||
|
using System.Reflection;
|
||
|
using System.Web;
|
||
|
using System.Runtime.Remoting.Messaging;
|
||
|
|
||
|
|
||
|
namespace Amib.Threading
|
||
|
{
|
||
|
#region CallerThreadContext class
|
||
|
|
||
|
/// <summary>
|
||
|
/// This class stores the caller call context in order to restore
|
||
|
/// it when the work item is executed in the thread pool environment.
|
||
|
/// </summary>
|
||
|
internal class CallerThreadContext
|
||
|
{
|
||
|
#region Prepare reflection information
|
||
|
|
||
|
// Cached type information.
|
||
|
private static MethodInfo getLogicalCallContextMethodInfo =
|
||
|
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||
|
|
||
|
private static MethodInfo setLogicalCallContextMethodInfo =
|
||
|
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||
|
|
||
|
private static string HttpContextSlotName = GetHttpContextSlotName();
|
||
|
|
||
|
private static string GetHttpContextSlotName()
|
||
|
{
|
||
|
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
|
||
|
|
||
|
if( fi != null )
|
||
|
return (string)fi.GetValue(null);
|
||
|
else // Use the default "HttpContext" slot name
|
||
|
return "HttpContext";
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Private fields
|
||
|
|
||
|
private HttpContext _httpContext = null;
|
||
|
private LogicalCallContext _callContext = null;
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
private CallerThreadContext()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public bool CapturedCallContext
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return (null != _callContext);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool CapturedHttpContext
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return (null != _httpContext);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Captures the current thread context
|
||
|
/// </summary>
|
||
|
/// <returns></returns>
|
||
|
public static CallerThreadContext Capture(
|
||
|
bool captureCallContext,
|
||
|
bool captureHttpContext)
|
||
|
{
|
||
|
Debug.Assert(captureCallContext || captureHttpContext);
|
||
|
|
||
|
CallerThreadContext callerThreadContext = new CallerThreadContext();
|
||
|
|
||
|
// TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
|
||
|
// Capture Call Context
|
||
|
if(captureCallContext && (getLogicalCallContextMethodInfo != null))
|
||
|
{
|
||
|
callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
|
||
|
if (callerThreadContext._callContext != null)
|
||
|
{
|
||
|
callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Capture httpContext
|
||
|
if (captureHttpContext && (null != HttpContext.Current))
|
||
|
{
|
||
|
callerThreadContext._httpContext = HttpContext.Current;
|
||
|
}
|
||
|
|
||
|
return callerThreadContext;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Applies the thread context stored earlier
|
||
|
/// </summary>
|
||
|
/// <param name="callerThreadContext"></param>
|
||
|
public static void Apply(CallerThreadContext callerThreadContext)
|
||
|
{
|
||
|
if (null == callerThreadContext)
|
||
|
{
|
||
|
throw new ArgumentNullException("callerThreadContext");
|
||
|
}
|
||
|
|
||
|
// Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
|
||
|
// Restore call context
|
||
|
if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
|
||
|
{
|
||
|
setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
|
||
|
}
|
||
|
|
||
|
// Restore HttpContext
|
||
|
if (callerThreadContext._httpContext != null)
|
||
|
{
|
||
|
CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
// Ami Bar
|
||
|
// amibar@gmail.com
|
||
|
|
||
|
using System;
|
||
|
using System.Threading;
|
||
|
using System.Globalization;
|
||
|
using System.Security.Principal;
|
||
|
using System.Reflection;
|
||
|
using System.Runtime.Remoting.Contexts;
|
||
|
|
||
|
namespace Amib.Threading.Internal
|
||
|
{
|
||
|
#region CallerThreadContext class
|
||
|
|
||
|
/// <summary>
|
||
|
/// This class stores the caller thread context in order to restore
|
||
|
/// it when the work item is executed in the context of the thread
|
||
|
/// from the pool.
|
||
|
/// Note that we can't store the thread's CompressedStack, because
|
||
|
/// it throws a security exception
|
||
|
/// </summary>
|
||
|
public class CallerThreadContext
|
||
|
{
|
||
|
private CultureInfo _culture = null;
|
||
|
private CultureInfo _cultureUI = null;
|
||
|
private IPrincipal _principal;
|
||
|
private System.Runtime.Remoting.Contexts.Context _context;
|
||
|
|
||
|
private static FieldInfo _fieldInfo = GetFieldInfo();
|
||
|
|
||
|
private static FieldInfo GetFieldInfo()
|
||
|
{
|
||
|
Type threadType = typeof(Thread);
|
||
|
return threadType.GetField(
|
||
|
"m_Context",
|
||
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
private CallerThreadContext()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Captures the current thread context
|
||
|
/// </summary>
|
||
|
/// <returns></returns>
|
||
|
public static CallerThreadContext Capture()
|
||
|
{
|
||
|
CallerThreadContext callerThreadContext = new CallerThreadContext();
|
||
|
|
||
|
Thread thread = Thread.CurrentThread;
|
||
|
callerThreadContext._culture = thread.CurrentCulture;
|
||
|
callerThreadContext._cultureUI = thread.CurrentUICulture;
|
||
|
callerThreadContext._principal = Thread.CurrentPrincipal;
|
||
|
callerThreadContext._context = Thread.CurrentContext;
|
||
|
return callerThreadContext;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Applies the thread context stored earlier
|
||
|
/// </summary>
|
||
|
/// <param name="callerThreadContext"></param>
|
||
|
public static void Apply(CallerThreadContext callerThreadContext)
|
||
|
{
|
||
|
Thread thread = Thread.CurrentThread;
|
||
|
thread.CurrentCulture = callerThreadContext._culture;
|
||
|
thread.CurrentUICulture = callerThreadContext._cultureUI;
|
||
|
Thread.CurrentPrincipal = callerThreadContext._principal;
|
||
|
|
||
|
// Uncomment the following block to enable the Thread.CurrentThread
|
||
|
/*
|
||
|
if (null != _fieldInfo)
|
||
|
{
|
||
|
_fieldInfo.SetValue(
|
||
|
Thread.CurrentThread,
|
||
|
callerThreadContext._context);
|
||
|
}
|
||
|
* /
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
}
|
||
|
*/
|
||
|
|