设置与Thread.CurrentPrincipal中异步/的await [英] Setting Thread.CurrentPrincipal with async/await

查看:280
本文介绍了设置与Thread.CurrentPrincipal中异步/的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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆