C# asp.net web API中沿异步任务丢失标头

C# asp.net web API中沿异步任务丢失标头,c#,multithreading,asp.net-web-api,async-await,C#,Multithreading,Asp.net Web Api,Async Await,我正在为API使用异步端点,并在请求中发送令牌。 但是,如果令牌在那里,它似乎是命中或未命中的,它感觉授权有时会被放到一个单独的线程上,而不会传递到它所处理的头和原始上下文上: 这就是我举的例子: public async override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) {

我正在为API使用异步端点,并在请求中发送令牌。 但是,如果令牌在那里,它似乎是命中或未命中的,它感觉授权有时会被放到一个单独的线程上,而不会传递到它所处理的头和原始上下文上:

这就是我举的例子:

public async override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
    {
        using (Session = WebApiApplication.Store.OpenAsyncSession())
        {

            try
            {
                var ctr = controllerContext.Controller.ToString();

                if (ctr.Contains("Authorise") || ctr.Contains("ScheduledTask"))
                {
                    var result = await base.ExecuteAsync(controllerContext, cancellationToken);
                    return result;
                }

                AuthUser = await GetAuthAsync();

                if (AuthUser == null)
                {
                    var r = new HttpResponseMessage { Content = new StringContent(@"Access is denied to this resource, Unable to read a valid access token!"), StatusCode = HttpStatusCode.Forbidden };
                    return r;
                }

                curUser = await GetCurUser(AuthUser);

                if (curUser != null)
                {
                    if (curUser.Id != null)
                    {
                        var user = await Session.LoadAsync<Users>(curUser.Id, cancellationToken);

                        if (user == null || !user.Login.UserEnabled)
                        {
                            var r = new HttpResponseMessage {Content = new StringContent(@"Access is denied to this resource, please pass a valid authorisation token!"), StatusCode = HttpStatusCode.Forbidden};
                            return r;
                        }

                        var result = await base.ExecuteAsync(controllerContext, cancellationToken);

                        await Session.SaveChangesAsync();
                        return result;
                    }

                    var rs1 = new HttpResponseMessage { Content = new StringContent(@"Access is denied to this resource, please pass a valid authorisation token!"), StatusCode = HttpStatusCode.Forbidden };
                    return rs1;
                }

                var rs = new HttpResponseMessage { Content = new StringContent(@"Access is denied to this resource, no current user can be found!"), StatusCode = HttpStatusCode.Forbidden };
                return rs;
            }
            catch (Exception ex)
            {
                var rs = new HttpResponseMessage { Content = new StringContent(@"Access is denied to this resource, an error happened when trying to validate: " + ex.Message), StatusCode = HttpStatusCode.Forbidden };
                return rs;
            }
        }
    }
尽管发送了头,并且这段代码90%的时间都在工作,但有时头不是,因此我认为代码被抛出到另一个线程,而没有这些信息,但只有在某些时候(比如堆栈感觉像是创建了一个新线程)

我可能完全错了,我只是不知道,我尝试了很多东西,但似乎永远都无法回避这个问题

请审阅并提出建议

我认为也包括这一点可能有用

public AuthedUser(string token)
    {
        ProcessToken(token);
    }

    public void ProcessToken(string token)
    {
        try
        {
           // AuthorisedUser = new AuthModel {Details = new AuthExtended(), UserId = ""};

            if (string.IsNullOrEmpty(token))
            {
                AuthorisedUser = new AuthModel
                {
                    Details = new AuthExtended { FingerPrint = null, User = new Users() },
                    UserId = null
                };
            }


            //decrypt token to normal base
            var preAuth = JsonConvert.DeserializeObject<PreAuthModel>(_secure.Decrypt(token));

            //now we need to create the authorised user
            AuthorisedUser = new AuthModel
            {
                UserId = preAuth.UserId
            };

            //need to get the secret from user
            if (!string.IsNullOrEmpty(preAuth.UserId))
            {
                using (Session = WebApiApplication.Store.OpenSession())
                {
                    // get the user, incase any changes have happened like de-authed, roles changed / created
                    var user = Session.Load<Users>(preAuth.UserId);

                    // populate user from token
                    AuthorisedUser.Details = JsonConvert.DeserializeObject<AuthExtended>(Security.DecryptToken(preAuth.EncryptedUser, user.Login.SecurityKey));

                    //check that the user in token, is the user we collected
                    if (AuthorisedUser.Details.User.Login.SecurityKey == user.Login.SecurityKey && AuthorisedUser.Details.User.Login.Id == user.Login.Id)
                    {
                        AuthorisedUser.Details.User = user;
                        WebApiApplication.AuthorisedUser = AuthorisedUser;
                    }
                    else
                    {
                        AuthorisedUser.Details = new AuthExtended { FingerPrint = null, User = new Users() };
                    }

                }
            }

        }
        catch (Exception e)
        {
            AuthorisedUser = new AuthModel
            {
                Details = new AuthExtended { FingerPrint = null, User = new Users() },
                UserId = null
            };
        }
    }
公共身份验证程序(字符串令牌)
{
进程令牌(token);
}
公共void进程令牌(字符串令牌)
{
尝试
{
//authorizeduser=newauthmodel{Details=newauthExtended(),UserId=”“};
if(string.IsNullOrEmpty(令牌))
{
authorizedUser=新的AuthModel
{
Details=new AuthExtended{FingerPrint=null,User=new Users()},
UserId=null
};
}
//将令牌解密到正常基址
var preAuth=JsonConvert.DeserializeObject(_secure.Decrypt(token));
//现在我们需要创建授权用户
authorizedUser=新的AuthModel
{
UserId=preAuth.UserId
};
//需要从用户处获取机密
如果(!string.IsNullOrEmpty(preAuth.UserId))
{
使用(Session=WebApiApplication.Store.OpenSession())
{
//获取用户,以防发生任何更改,如取消授权、更改/创建角色
var user=Session.Load(preAuth.UserId);
//从令牌填充用户
authorizedUser.Details=JsonConvert.DeserializeObject(Security.DecryptToken(preAuth.EncryptedUser,user.Login.SecurityKey));
//检查令牌中的用户是否为我们收集的用户
if(authorizedUser.Details.User.Login.SecurityKey==User.Login.SecurityKey&&authorizedUser.Details.User.Login.Id==User.Login.Id)
{
authorizedUser.Details.User=用户;
WebApiApplication.authorizedUser=authorizedUser;
}
其他的
{
authorizeUser.Details=newauthExtended{FingerPrint=null,User=newusers()};
}
}
}
}
捕获(例外e)
{
authorizedUser=新的AuthModel
{
Details=new AuthExtended{FingerPrint=null,User=new Users()},
UserId=null
};
}
}
我从来没有真正能够跨过这一步,它到处反弹
当头出现时返回null,似乎在自己身上循环跳跃并清除数据

为什么要在
GetAuthAsync
中调用
Task.Run
?因为auth.authorizedUser.Details.User不是一个异步方法,它是同步的,但需要是异步的,这样我就不会跳出异步方法。当我将其作为普通同步方法调用时,async函数只是返回而不等待同步方法,因此我正在包装task,使其等待我的同步方法完成
Taks。Run
将重新安排代码在线程池上运行。相同的线程池处理HTTP请求。这样做,您将强制执行线程/上下文切换,而没有任何好处,从而影响该请求和整个应用程序的性能。您的方法不需要是
异步的
就可以返回
任务
/
任务
。如果让方法同步并从
Task.FromResult返回
Task
,效果会更好。该
Task`将完成,不会导致线程/上下文切换。起初我确实尝试了同步,但API端点中的异步代码将在sync方法完成之前运行,因此也需要导入异步。老实说,起初我有currentUSer的属性,这些属性将公开给任何以baseController为基础的控制器。但正如我所说,当时是同步的,我的异步web api端点有时无法及时获取详细信息。我想我必须重新设计我的令牌处理程序,根据你的建议,在行与行之间阅读,为ExecuteAsync做同步版本,然后为其余的,在异步以某种方式失败的情况下做了回退,这允许我返回正常的同步方法并修复结果。现在一切都正常稳定,所以感谢你的建议,我认为还有一些清理工作要做,有时,尽管我尽了最大的努力,我还是丢失了数据,但现在也有一个后备方案
var header = HttpContext.Current.Request.Headers["x-access-token"];
public AuthedUser(string token)
    {
        ProcessToken(token);
    }

    public void ProcessToken(string token)
    {
        try
        {
           // AuthorisedUser = new AuthModel {Details = new AuthExtended(), UserId = ""};

            if (string.IsNullOrEmpty(token))
            {
                AuthorisedUser = new AuthModel
                {
                    Details = new AuthExtended { FingerPrint = null, User = new Users() },
                    UserId = null
                };
            }


            //decrypt token to normal base
            var preAuth = JsonConvert.DeserializeObject<PreAuthModel>(_secure.Decrypt(token));

            //now we need to create the authorised user
            AuthorisedUser = new AuthModel
            {
                UserId = preAuth.UserId
            };

            //need to get the secret from user
            if (!string.IsNullOrEmpty(preAuth.UserId))
            {
                using (Session = WebApiApplication.Store.OpenSession())
                {
                    // get the user, incase any changes have happened like de-authed, roles changed / created
                    var user = Session.Load<Users>(preAuth.UserId);

                    // populate user from token
                    AuthorisedUser.Details = JsonConvert.DeserializeObject<AuthExtended>(Security.DecryptToken(preAuth.EncryptedUser, user.Login.SecurityKey));

                    //check that the user in token, is the user we collected
                    if (AuthorisedUser.Details.User.Login.SecurityKey == user.Login.SecurityKey && AuthorisedUser.Details.User.Login.Id == user.Login.Id)
                    {
                        AuthorisedUser.Details.User = user;
                        WebApiApplication.AuthorisedUser = AuthorisedUser;
                    }
                    else
                    {
                        AuthorisedUser.Details = new AuthExtended { FingerPrint = null, User = new Users() };
                    }

                }
            }

        }
        catch (Exception e)
        {
            AuthorisedUser = new AuthModel
            {
                Details = new AuthExtended { FingerPrint = null, User = new Users() },
                UserId = null
            };
        }
    }