aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ThirdParty/SmartThreadPool/CallerThreadContext.cs
blob: 925c39b18b76033822b0a6d71c72e86852cd955e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)

using System;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Web;
using System.Runtime.Remoting.Messaging;


namespace Amib.Threading.Internal
{
#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 readonly MethodInfo getLogicalCallContextMethodInfo =
            typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);

        private static readonly 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);
            }

            return "HttpContext";
        }

        #endregion

#region Private fields

        private HttpContext _httpContext;
        private LogicalCallContext _callContext;

        #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)
            {
                HttpContext.Current = callerThreadContext._httpContext;
                //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
            }
        }
    }

    #endregion
}
#endif