Asp.net mvc 如何处理空HttpContext.Current,当使用异步/等待身份验证筛选器时?

Asp.net mvc 如何处理空HttpContext.Current,当使用异步/等待身份验证筛选器时?,asp.net-mvc,asp.net-web-api,asp.net-web-api2,Asp.net Mvc,Asp.net Web Api,Asp.net Web Api2,在控制器中的一个API中,我需要引用HttpContext.Current。在我实现自定义身份验证过滤器之前,一切正常。过滤器使用异步方法和wait。但是,当过滤器就位时,HttpContext.Current在到达我的控制器时为空。我假设这是因为我的控制器由于过滤器中的async/await而在不同的线程上执行。如果是这样,我应该如何访问控制器中的“原始”上下文?这有点令人失望,因为过滤器似乎是一个很好的可插拔想法,但不幸的是,它们有一些[严重的]缺点。示例伪代码: public class

在控制器中的一个API中,我需要引用HttpContext.Current。在我实现自定义身份验证过滤器之前,一切正常。过滤器使用异步方法和wait。但是,当过滤器就位时,HttpContext.Current在到达我的控制器时为空。

我假设这是因为我的控制器由于过滤器中的async/await而在不同的线程上执行。
如果是这样,我应该如何访问控制器中的“原始”上下文?
这有点令人失望,因为过滤器似乎是一个很好的可插拔想法,但不幸的是,它们有一些[严重的]缺点。
示例伪代码:

public class TestAuthFilter : Attribute, IAuthenticationFilter
{
    private static string validationClaim = "testClaim";
    private tokenValidationUri;

    public bool AllowMultiple { get { return false; } }

    public TestAuthFilter(string tokenValidationUri)
    {
        this.tokenValidationUri = tokenValidationUri;
    }

    public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
    {
        // We are not adding any authentication challenges to the response
        return Task.FromResult(0);
    }

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        HttpRequestMessage request = context.Request;
        AuthenticationHeaderValue authorization = request.Headers.Authorization;

        if (authorization == null)
        {
            return;
        }

        if (authorization.Scheme != "Bearer")
        {
            return;
        }

        if (String.IsNullOrEmpty(authorization.Parameter))
        {
            context.ErrorResult = new AuthenticationFailureResult("Missing access token", request);
            return;
        }

        string token = authorization.Parameter;
        IPrincipal principal = await AuthenticateAsync(token, cancellationToken);
        if (principal == null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid access token", request);
        }
        else
        {
            context.Principal = principal;
        }
    }

    public async Task<IPrincipal> AuthenticateAsync(string token, CancellationToken cancellationToken)
    {
        using (HttpClient client = new HttpClient())
        {
            try
            {                    
                HttpResponseMessage response = await client.GetAsync(tokenValidationUri + token, cancellationToken);

                using (HttpContent content = response.Content)
                {
                    string result = await content.ReadAsStringAsync();
                    if (result != null)
                    {
                        if (response.IsSuccessStatusCode)
                        {
                            var success = await response.Content.ReadAsAsync<TokenValidationSuccess>();
                            if (success.audience.Equals(validationAudience, StringComparison.Ordinal))
                            {
                                TestPrincipal principal = new TestPrincipal([...]);
                                return principal;
                            }
                        }
                        else
                        {
                            var error = await response.Content.ReadAsAsync<TokenValidationError>();
                        }
                    }
                }
            }
            catch (HttpRequestException e)
            {
                Debug.WriteLine("Exception: {0}", e.Message);
            }
        }
        return null;
    }
}
公共类TestAuthFilter:属性,IAAuthenticationFilter
{
私有静态字符串validationClaim=“testClaim”;
私有令牌验证URI;
public bool AllowMultiple{get{return false;}
公共TestAuthFilter(字符串令牌验证URI)
{
this.tokenValidationUri=tokenValidationUri;
}
公共任务ChallengeAsync(HttpAuthenticationChallengeContext,CancellationToken CancellationToken)
{
//我们不会向响应添加任何身份验证挑战
返回Task.FromResult(0);
}
公共异步任务AuthenticateAsync(HttpAuthenticationContext上下文,CancellationToken CancellationToken)
{
HttpRequestMessage请求=context.request;
AuthenticationHeaderValue authorization=request.Headers.authorization;
if(授权==null)
{
返回;
}
if(authorization.Scheme!=“持票人”)
{
返回;
}
if(String.IsNullOrEmpty(authorization.Parameter))
{
context.ErrorResult=新身份验证失败结果(“缺少访问令牌”,请求);
返回;
}
string token=authorization.Parameter;
IPrincipal principal=await authenticatesync(令牌、取消令牌);
if(principal==null)
{
context.ErrorResult=新身份验证失败结果(“无效访问令牌”,请求);
}
其他的
{
context.Principal=Principal;
}
}
公共异步任务AuthenticateAsync(字符串令牌、取消令牌取消令牌)
{
使用(HttpClient=new HttpClient())
{
尝试
{                    
HttpResponseMessage response=wait client.GetAsync(tokenValidationUri+token,cancellationToken);
使用(HttpContent=response.content)
{
字符串结果=等待内容。ReadAsStringAsync();
如果(结果!=null)
{
if(响应。IsSuccessStatusCode)
{
var success=wait response.Content.ReadAsAsync();
if(success.audition.Equals(validationaudition,StringComparison.Ordinal))
{
TestPrincipal=新的TestPrincipal([…]);
返还本金;
}
}
其他的
{
var error=wait response.Content.ReadAsAsync();
}
}
}
}
捕获(HttpRequestException e)
{
WriteLine(“异常:{0}”,e.Message);
}
}
返回null;
}
}



如果有任何建议,我将不胜感激。
谢谢。

WebAPI
中有一个关于
authenticateSync
的好链接:

应将作为参数
HttpAuthenticationContext
,该参数包含
ActionContext
HttpRequestMessage
请求的线程安全版本

以下是到达该位置的继承链:

(HttpRequestMessage)System.Web.Http.Filters.HttpAuthenticationContext.ActionContext.ControllerContext.Request

解决方案是在web.config中包含“targetFramework=4.5”。积分归Stephen Cleary所有-请参阅上面的注释。

将上下文作为参数传递。如何将上下文作为参数传递给控制器?这意味着我应该能够在某个点获取“原始”上下文,然后将其传递给控制器。但是,我的控制器的方法是由框架调用的。您能详细说明一下吗?您能提交您的自定义筛选器吗?您的
AuthenticationFilter
必须具有
OnAuthentication()
方法。你也可以提交吗。还有,您在哪里调用了
HttpContext.Current
我在您的代码中找不到它。@bdristan:您的目标是.NET 4.5,并且设置了
httpRuntime@targetFramework
4.5
web.config
中?