#if net45 using System.Collections; using System.Runtime.Remoting; using System.Runtime.Remoting.Messaging; using System.Linq.Expressions; using System.Reflection; namespace System.Threading { /// /// Polyfill for AsyncLocal functionality added in NETSTANDARD1.3 and .NET 4.6 /// /// /// The type of the value to encapsulate and follow. /// internal class AsyncLocal { private readonly string _name = Guid.NewGuid().ToString("N"); /// /// Gets or set the value to flow with . /// public T Value { get { if (CallContext.LogicalGetData(_name) is ObjectHandle slot) return (T)slot.Unwrap(); return default(T); } set { // Mimic the implementation of AsyncLocal var executionContext = Thread.CurrentThread.GetMutableExecutionContext(); var logicalCallContext = executionContext.GetLogicalCallContext(); var datastore = logicalCallContext.GetDatastore(); var datastoreCopy = datastore == null ? new Hashtable() : new Hashtable(datastore); var slot = new ObjectHandle(value); datastoreCopy[_name] = slot; logicalCallContext.SetDatastore(datastoreCopy); } } } internal static class ThreadExtensions { private static readonly Func _getMutableExecutionContextFunc; static ThreadExtensions() { var getMutableExecutionContextMethodInfo = typeof(Thread).GetMethod("GetMutableExecutionContext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var instanceParameterExpression = Expression.Parameter(typeof(Thread)); var functionCallExpression = Expression.Call(instanceParameterExpression, getMutableExecutionContextMethodInfo); var lambdaExpression = Expression.Lambda>(functionCallExpression, instanceParameterExpression); _getMutableExecutionContextFunc = lambdaExpression.Compile(); } private static MethodInfo GetMutableExecutionContextMethodInfo = typeof(Thread).GetMethod("GetMutableExecutionContext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static ExecutionContext GetMutableExecutionContext(this Thread thread) => _getMutableExecutionContextFunc(thread); } internal static class LogicalCallContextExtensions { private static readonly Func _getDatastoreFunc; private static readonly Func _setDatastoreFunc; static LogicalCallContextExtensions() { var datastoreFieldInfo = typeof(LogicalCallContext).GetField("m_Datastore", BindingFlags.Instance | BindingFlags.NonPublic); var instanceParameterExpression = Expression.Parameter(typeof(LogicalCallContext)); var memberAccessExpression = Expression.MakeMemberAccess(instanceParameterExpression, datastoreFieldInfo); var getLambdaExpression = Expression.Lambda>(memberAccessExpression, instanceParameterExpression); _getDatastoreFunc = getLambdaExpression.Compile(); var valueParameterExpression = Expression.Parameter(typeof(Hashtable)); var assignmentExpression = Expression.Assign(memberAccessExpression, valueParameterExpression); var setFunctionBody = Expression.Block(assignmentExpression, Expression.Constant(true)); var setLambdaExpression = Expression.Lambda>(setFunctionBody, instanceParameterExpression, valueParameterExpression); _setDatastoreFunc = setLambdaExpression.Compile(); } public static Hashtable GetDatastore(this LogicalCallContext context) => _getDatastoreFunc(context); public static void SetDatastore(this LogicalCallContext context, Hashtable datastore) => _setDatastoreFunc(context, datastore); } internal static class ExecutionContextExtensions { private static readonly Func _getLogicalCallContextFunc; static ExecutionContextExtensions() { var logicalCallContextPropertyInfo = typeof(ExecutionContext).GetProperty("LogicalCallContext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var instanceParameterExpression = Expression.Parameter(typeof(ExecutionContext)); var memberAccessExpression = Expression.MakeMemberAccess(instanceParameterExpression, logicalCallContextPropertyInfo); var lambdaExpression = Expression.Lambda>(memberAccessExpression, instanceParameterExpression); _getLogicalCallContextFunc = lambdaExpression.Compile(); } public static LogicalCallContext GetLogicalCallContext(this ExecutionContext executionContext) => _getLogicalCallContextFunc(executionContext); } } #endif