Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否异步设置Thread.CurrentPrincipal?_C#_Asp.net Web Api_Async Await - Fatal编程技术网

C# 是否异步设置Thread.CurrentPrincipal?

C# 是否异步设置Thread.CurrentPrincipal?,c#,asp.net-web-api,async-await,C#,Asp.net Web Api,Async Await,使用ASP.NET WebAPI,在身份验证期间,设置Thread.CurrentPrincipal,以便控制器以后可以使用ApiController.User属性 如果认证步骤变为异步(咨询另一个系统),则CurrentPrincipal的任何变异都将丢失(当调用方的wait恢复同步上下文时) 下面是一个非常简化的示例(在实际代码中,身份验证发生在动作过滤器中): 使用系统诊断; 使用System.Security.Principal; 使用系统线程; 使用System.Threading.T

使用ASP.NET WebAPI,在身份验证期间,设置
Thread.CurrentPrincipal
,以便控制器以后可以使用
ApiController.User
属性

如果认证步骤变为异步(咨询另一个系统),则
CurrentPrincipal
的任何变异都将丢失(当调用方的
wait
恢复同步上下文时)

下面是一个非常简化的示例(在实际代码中,身份验证发生在动作过滤器中):

使用系统诊断;
使用System.Security.Principal;
使用系统线程;
使用System.Threading.Tasks;
公共类示例AsyncController:System.Web.Http.ApicController
{
公共异步任务GetAsync()
{
等待验证同步();
//上面的等待保存/恢复了当前同步
//上下文,从而撤消AuthenticateTasync()中的赋值。
Assert(用户是GenericPrincipal);
}
私有静态异步任务AuthenticateTasync()
{
//保存当前HttpContext,因为它在等待后为null。
var currentHttpContext=System.Web.HttpContext.Current;
//异步确定身份。
等待任务。延迟(1000);
var标识=新的GenericEntity(“”);
var roles=新字符串[]{};
Thread.CurrentPrincipal=新的GenericPrincipal(标识、角色);
currentHttpContext.User=Thread.CurrentPrincipal;
}
}

如何在异步函数中设置
Thread.CurrentPrincipal
,使调用方的
wait
在恢复同步上下文时不会放弃该变异?

您还必须设置
HttpContext.Current.User
。有关更多信息,请参阅和


更新:还要确保您在.NET 4.5上运行,并且将
UserTaskFriendlySynchronizationContext
设置为
true

我不确定您的问题,但理想情况下,最好在调用控制器之前对它们进行身份验证。在我的WebAPI项目中,我喜欢设置一个
DelegatingHandler
,它在到达控制器之前进行身份验证。@Matthew,我同意,这就是真实代码的工作方式,在调用控制器方法之前,一个动作过滤器处理身份验证。为了简化我的示例,我排除了操作筛选器,但这两种情况下的问题都是一样的。从这个stackoverflow答案来看,如果您设置CurrentPrincipal,它似乎会一直存在于调用线程中:,否则我不确定如何解决您的问题。可能重复感谢您的帮助Stephen。我添加了
HttpContext.Current.User
的设置(并更新了我问题中的代码),但没有帮助。这个问题没有改变。它对我来说确实有效。我用上面的代码在ValuesController中创建了一个新的WebAPI项目,它工作得很好。后续问题:您是否在.NET 4.5上运行,并且是否已将
UseTaskFriendlySynchronizationContext
设置为true?将
UseTaskFriendlySynchronizationContext
设置为true修复了此问题!感谢您花时间进行调查!不客气!我把答案编辑得更完整了。奇怪的是,在我的机器上,无论
UTFSC
设置为
true
还是
false
,它都能工作。我不确定
UTFSC
的确切情况会有什么不同,但我很高兴它起到了作用!Stephen,经过进一步的调查,我的示例似乎只适用于
等待任务。存在延迟(1000)
。我专门问过这件事。如果您有时间,我将非常感谢您的任何意见。
using System.Diagnostics;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;

public class ExampleAsyncController : System.Web.Http.ApiController
{
    public async Task GetAsync()
    {
        await AuthenticateAsync();

        // The await above saved/restored the current synchronization
        // context, thus undoing the assignment in AuthenticateAsync(). 
        Debug.Assert(User is GenericPrincipal);
    }

    private static async Task AuthenticateAsync()
    {
        // Save the current HttpContext because it's null after await.
        var currentHttpContext = System.Web.HttpContext.Current;

        // Asynchronously determine identity.
        await Task.Delay(1000);
        var identity = new GenericIdentity("<name>");

        var roles = new string[] { };
        Thread.CurrentPrincipal = new GenericPrincipal(identity, roles);
        currentHttpContext.User = Thread.CurrentPrincipal;
    }
}