Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/29.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# DelegatingHandler应该如何进行异步调用(ASP.NET MVC Web API)?_C#_Asp.net_Asp.net Web Api - Fatal编程技术网

C# DelegatingHandler应该如何进行异步调用(ASP.NET MVC Web API)?

C# DelegatingHandler应该如何进行异步调用(ASP.NET MVC Web API)?,c#,asp.net,asp.net-web-api,C#,Asp.net,Asp.net Web Api,在调用内部处理程序的sendsync()之前执行同步工作,以及在内部处理程序通过完成完成后执行同步工作,我对此感到满意。e、 g: protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { // do some sync work before inner handler he

在调用内部处理程序的sendsync()之前执行同步工作,以及在内部处理程序通过完成完成后执行同步工作,我对此感到满意。e、 g:

protected override Task<HttpResponseMessage> SendAsync( 
    HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    // do some sync work before inner handler here 

    var sendTask = base.SendAsync(request, cancellationToken); 
    return sendTask.ContinueWith( 
        task => { // do some sync work afterwards here }); 
} 
受保护的覆盖任务SendAsync(
HttpRequestMessage请求,CancellationToken CancellationToken)
{ 
//在内部处理程序之前执行一些同步工作
var sendTask=base.sendsync(请求、取消令牌);
返回sendTask。继续使用(
task=>{//在此之后执行一些同步工作});
} 
但是,我现在需要从委托处理程序中调用IO绑定的操作。IO绑定操作已包装为
任务
。我需要使用结果来确定是否继续内部处理程序

例如,进行网络呼叫以授权请求。我必须这样做才能与现有系统集成。总的来说,我认为这个问题有一些有效的场景,应该有一个可行的解决方案

在这种情况下,实现SendAsync的正确方法是什么,以便异步执行IO绑定任务,然后继续异步执行内部处理程序


关键的一点是,我想确保请求线程在任何时候都不会被阻塞。

好的,我想我已经破解了这个问题。我用一个身份验证场景来说明这一点:我想异步地对用户进行身份验证,并使用结果来决定是返回401还是继续使用消息处理程序链

核心问题是,在获得异步身份验证的结果之前,无法调用内部处理程序SendAsync()

我的主要见解是使用TaskCompletionSource(TCS)来控制执行流。这使我能够从TCS返回任务,并在我喜欢的时候对其设置一个结果——最重要的是延迟调用SendAsync(),直到我知道我需要它

因此,我设置了TCS,然后启动了一项任务来进行授权。在接下来的部分中,我将看到结果。如果获得授权,我将调用内部处理程序链,并在此链上附加一个完成TCS的延续(避免任何线程阻塞)。如果身份验证失败,我只需在那里完成TCS,然后使用401

这样做的结果是,两个异步任务轮流执行,没有任何线程阻塞。我对它进行了负载测试,它似乎工作得很好

不过,在.NET4.5中使用异步/等待语法会更好。。。尽管使用TCS的方法基本上仍在幕后进行,但代码要简单得多

享受吧

第一个代码段是在.NET 4.0和Web API测试版上构建的,第二个代码段是在.NET 4.5/Web API RC上构建的

protected override Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
{
    var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();

    // Authorize() returns a started
    // task that authenticates the user
    // if the result is false we should
    // return a 401 immediately
    // otherwise we can invoke the inner handler
    Task<bool> authenticationTask = Authorize(request);

    // attach a continuation...
    authenticationTask.ContinueWith(_ =>
    {
        if (authenticationTask.Result)
        {
            // authentication succeeded
            // so start the inner handler chain
            // and write the result to the
            // task completion source when done
            base.SendAsync(request, cancellationToken)
                .ContinueWith(t => taskCompletionSource.SetResult(t.Result));
        }
        else
        {
            // authentication failed
            // so complete the TCS immediately
            taskCompletionSource.SetResult(
                new HttpResponseMessage(HttpStatusCode.Unauthorized));
        }
    });

    return taskCompletionSource.Task;
}
受保护的覆盖任务SendAsync(
HttpRequestMessage请求,CancellationToken CancellationToken)
{
var taskCompletionSource=新的taskCompletionSource();
//Authorize()返回已启动的
//对用户进行身份验证的任务
//如果结果是假的,我们应该
//立即返回401
//否则,我们可以调用内部处理程序
任务身份验证任务=授权(请求);
//附上一个延续。。。
authenticationTask.ContinueWith(\u=>
{
if(authenticationTask.Result)
{
//身份验证成功
//因此,启动内部处理程序链
//并将结果写入
//完成时的任务完成源
base.sendaync(请求、取消令牌)
.ContinueWith(t=>taskCompletionSource.SetResult(t.Result));
}
其他的
{
//身份验证失败
//因此,请立即完成TCS
taskCompletionSource.SetResult(
新的HttpResponseMessage(HttpStatusCode.Unauthorized));
}
});
返回taskCompletionSource.Task;
}
下面是一个.NET 4.5/Web API发行候选版本,它使用了新的async/await语法,更加性感:

protected override async Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
{
    // Authorize still has a Task<bool> return type
    // but await allows this nicer inline syntax
    var authorized = await Authorize(request);

    if (!authorized)
    {
        return new HttpResponseMessage(HttpStatusCode.Unauthorized)
        {
            Content = new StringContent("Unauthorized.")
        };
    }

    return await base.SendAsync(request, cancellationToken);
}
受保护的覆盖异步任务SendAsync(
HttpRequestMessage请求,CancellationToken CancellationToken)
{
//Authorize仍然具有任务返回类型
//但是wait允许这种更好的内联语法
var授权=等待授权(请求);
如果(!授权)
{
返回新的HttpResponseMessage(HttpStatusCode.Unauthorized)
{
内容=新的字符串内容(“未经授权”)
};
}
返回wait base.sendaync(请求、取消令牌);
}

您是如何实施
授权的
?您是否实例化了一个新的
HttpClient
?授权的实现与此无关-它只是一个异步函数,用于确定请求是否被允许-如何实现它取决于您自己。例如,可以进行数据库检查,以查看当前用户是否有权根据某些定制的业务规则发出当前请求。我只是想知道您是否发出另一个http请求,仅此而已……在我的场景中,我需要在当前http调用之前再发出一个http调用,并且我被实例化了另一个
HttpClient
。我想知道是否可以在处理程序中重新使用当前的一个,但似乎我不能