C# DelegatingHandler应该如何进行异步调用(ASP.NET MVC Web API)?
在调用内部处理程序的sendsync()之前执行同步工作,以及在内部处理程序通过完成完成后执行同步工作,我对此感到满意。e、 g: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
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
。我想知道是否可以在处理程序中重新使用当前的一个,但似乎我不能