设置与Thread.CurrentPrincipal中异步/的await [英] Setting Thread.CurrentPrincipal with async/await
问题描述
下面是在那里我试图异步方法为自定义中设置Thread.CurrentPrincipal中UserPrincipal对象的简化版本,但留下,即使它仍然对新的threadId 10的await后自定义对象是迷路。
有没有办法到的await内变化和Thread.CurrentPrincipal中以后使用它没有传递给它或退回呢?或者这是不是安全,应该永远是异步?我知道有螺纹的变化,但认为异步/的await将处理synching这对我来说。
[TestMethod的]
公共异步任务AsyncTest()
{
VAR principalType = Thread.CurrentPrincipal.GetType()名称。
// principalType = WindowsPrincipal
// Thread.CurrentThread.ManagedThreadId = 11 等待Task.Run(()=>
{
//试图把等待Task.Yield()在这里,但没有帮助 = Thread.CurrentPrincipal中新UserPrincipal(Thread.CurrentPrincipal.Identity);
principalType = Thread.CurrentPrincipal.GetType()名称。
// principalType = UserPrincipal
// Thread.CurrentThread.ManagedThreadId = 10
});
principalType = Thread.CurrentPrincipal.GetType()名称。
// principalType = WindowsPrincipal(为什么?)
// Thread.CurrentThread.ManagedThreadId = 10
}
您可以使用自定义awaiter流动 CurrentPrincipal
(或任何线程性能,对于这个问题)。下面的例子说明它可能怎么做,由斯蒂芬Toub的<$ C $启发C> CultureAwaiter 。它采用 TaskAwaiter
内部,所以同步上下文(如果有的话)将被捕获了。
用法:
Console.WriteLine(Thread.CurrentPrincipal.GetType()名称。);等待TaskExt.RunAndFlowPrincipal(()=&GT;
{
= Thread.CurrentPrincipal中新UserPrincipal(Thread.CurrentPrincipal.Identity);
Console.WriteLine(Thread.CurrentPrincipal.GetType()名称。);
返回42;
});Console.WriteLine(Thread.CurrentPrincipal.GetType()名称。);
code(只有非常轻微的测试):
公共静态类TaskExt
{
//流动Thread.CurrentPrincipal中
公共静态FlowingAwaitable&LT; TResult,IPrincipal的&GT; RunAndFlowPrincipal&LT; TResult&GT;(
FUNC&LT; TResult&GT; FUNC,
的CancellationToken令牌=默认(的CancellationToken))
{
返回RunAndFlow(
FUNC,
()=&GT; Thread.CurrentPrincipal中,
S =&GT; = Thread.CurrentPrincipal中S,
令牌);
} //任何流动
公共静态FlowingAwaitable&LT; TResult,TSTATE&GT; RunAndFlow&LT; TResult,TSTATE&GT;(
FUNC&LT; TResult&GT; FUNC,
FUNC&LT;&TSTATE GT; saveState和,
动作&LT;&TSTATE GT; restoreState,
的CancellationToken令牌=默认(的CancellationToken))
{
//与FUNC2包FUNC捕捉和传播异常
FUNC&LT元组LT; FUNC&LT; TResult&gt;中TSTATE&GT;&GT; FUNC2 =()=&GT;
{
FUNC&LT; TResult&GT;的getResult;
尝试
{
VAR的结果= FUNC();
的getResult =()=&GT;结果;
}
赶上(异常前)
{
//捕捉异常
VAR EDI = ExceptionDispatchInfo.Capture(除息);
的getResult =()=&GT;
{
//重新抛出异常捕获
edi.Throw();
//不应该达到这一点,
//但是没有它编译什么我们
//此处返回一个虚拟TResult值
抛出新AggregateException(edi.SourceException);
};
}
返回新行&LT;&Func键LT; TResult&gt;中TSTATE&GT;(的getResult,saveState和());
}; 返回新FlowingAwaitable&LT; TResult,TSTATE&GT;(
Task.Run(FUNC2,令牌)
restoreState);
} 公共类FlowingAwaitable&LT; TResult,TSTATE&GT; :
ICriticalNotifyCompletion
{
只读TaskAwaiter&LT元组LT; Func键&LT; TResult&gt;中TSTATE&GT;&GT; _服务员;
只读动作&LT;&TSTATE GT; _restoreState; 公共FlowingAwaitable(
任务&LT元组LT; Func键&LT; TResult&gt;中TSTATE&GT;&GT;任务,
动作&LT;&TSTATE GT; restoreState)
{
_awaiter = task.GetAwaiter();
_restoreState = restoreState;
} 公共FlowingAwaitable&LT; TResult,TSTATE&GT; GetAwaiter()
{
返回此;
} 公共BOOL IsCompleted
{
{返回_awaiter.IsCompleted; }
} 公共TResult调用getResult()
{
VAR的结果= _awaiter.GetResult();
_restoreState(result.Item2);
返回result.Item1();
} 公共无效OnCompleted(动作续)
{
_awaiter.OnCompleted(续)
} 公共无效UnsafeOnCompleted(动作续)
{
_awaiter.UnsafeOnCompleted(续)
}
}
}
Below is a simplified version of where I am trying to set Thread.CurrentPrincipal within an async method to a custom UserPrincipal object but the custom object is getting lost after leaving the await even though it's still on the new threadID 10.
Is there a way to change Thread.CurrentPrincipal within an await and use it later without passing it in or returning it? Or is this not safe and should never be async? I know there are thread changes but thought async/await would handle synching this for me.
[TestMethod]
public async Task AsyncTest()
{
var principalType = Thread.CurrentPrincipal.GetType().Name;
// principalType = WindowsPrincipal
// Thread.CurrentThread.ManagedThreadId = 11
await Task.Run(() =>
{
// Tried putting await Task.Yield() here but didn't help
Thread.CurrentPrincipal = new UserPrincipal(Thread.CurrentPrincipal.Identity);
principalType = Thread.CurrentPrincipal.GetType().Name;
// principalType = UserPrincipal
// Thread.CurrentThread.ManagedThreadId = 10
});
principalType = Thread.CurrentPrincipal.GetType().Name;
// principalType = WindowsPrincipal (WHY??)
// Thread.CurrentThread.ManagedThreadId = 10
}
You could use a custom awaiter to flow CurrentPrincipal
(or any thread properties, for that matter). The below example shows how it might be done, inspired by Stephen Toub's CultureAwaiter
. It uses TaskAwaiter
internally, so synchronization context (if any) will be captured, too.
Usage:
Console.WriteLine(Thread.CurrentPrincipal.GetType().Name);
await TaskExt.RunAndFlowPrincipal(() =>
{
Thread.CurrentPrincipal = new UserPrincipal(Thread.CurrentPrincipal.Identity);
Console.WriteLine(Thread.CurrentPrincipal.GetType().Name);
return 42;
});
Console.WriteLine(Thread.CurrentPrincipal.GetType().Name);
Code (only very slightly tested):
public static class TaskExt
{
// flowing Thread.CurrentPrincipal
public static FlowingAwaitable<TResult, IPrincipal> RunAndFlowPrincipal<TResult>(
Func<TResult> func,
CancellationToken token = default(CancellationToken))
{
return RunAndFlow(
func,
() => Thread.CurrentPrincipal,
s => Thread.CurrentPrincipal = s,
token);
}
// flowing anything
public static FlowingAwaitable<TResult, TState> RunAndFlow<TResult, TState>(
Func<TResult> func,
Func<TState> saveState,
Action<TState> restoreState,
CancellationToken token = default(CancellationToken))
{
// wrap func with func2 to capture and propagate exceptions
Func<Tuple<Func<TResult>, TState>> func2 = () =>
{
Func<TResult> getResult;
try
{
var result = func();
getResult = () => result;
}
catch (Exception ex)
{
// capture the exception
var edi = ExceptionDispatchInfo.Capture(ex);
getResult = () =>
{
// re-throw the captured exception
edi.Throw();
// should never be reaching this point,
// but without it the compiler whats us to
// return a dummy TResult value here
throw new AggregateException(edi.SourceException);
};
}
return new Tuple<Func<TResult>, TState>(getResult, saveState());
};
return new FlowingAwaitable<TResult, TState>(
Task.Run(func2, token),
restoreState);
}
public class FlowingAwaitable<TResult, TState> :
ICriticalNotifyCompletion
{
readonly TaskAwaiter<Tuple<Func<TResult>, TState>> _awaiter;
readonly Action<TState> _restoreState;
public FlowingAwaitable(
Task<Tuple<Func<TResult>, TState>> task,
Action<TState> restoreState)
{
_awaiter = task.GetAwaiter();
_restoreState = restoreState;
}
public FlowingAwaitable<TResult, TState> GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get { return _awaiter.IsCompleted; }
}
public TResult GetResult()
{
var result = _awaiter.GetResult();
_restoreState(result.Item2);
return result.Item1();
}
public void OnCompleted(Action continuation)
{
_awaiter.OnCompleted(continuation);
}
public void UnsafeOnCompleted(Action continuation)
{
_awaiter.UnsafeOnCompleted(continuation);
}
}
}
这篇关于设置与Thread.CurrentPrincipal中异步/的await的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!