我现在已经把头撞到墙上两天了,坦率地说,我对自己很生气,因为我似乎无法得到它。
我在webapi
上下文中。在此请求期间,我需要将一些数据发送到我们的其他系统之一,由于计算量大和多次数据库保存等原因,此系统返回速度很慢。我需要记录此操作的结果,无论它是否成功或不。但我不想等待它完成。
我read我应该从上到下一直async await
。如果我决定这样做的话,我将不得不转换很多方法,因为我已经深入了3或4种方法,我担心这种方法会更加突出。
我有什么选择?如果我一直向下等待异步,我怎么处理堆栈上方的方法,比如我的WebApi控制器?
这是我的代码,我试图尽可能地减少它。现在我在方法Task.Result()
中使用PushResult()
。我的理解是阻止异步?此代码的工作原理是请求被发送。但TestLog始终是最后的,而不是第一个。因此不是异步。
//I'm in a public service and referenced twice
private void MyEndProcess()
{
// other stuff
_vendorPushService.PushResult(); // This could take a while and I have to wait for it!
_logService.PostLog(LogType.TestLog, "Test");
}
//I'm referenced above and somewhere else in the code base
public void PushResult()
{
ExternalResultModel externalResultModel = _resultService.GetExternalResultModel();
PushedResultModel pushedResult = new PushedResultModel();
try
{
pushedResult = _vendorRequestService.PushResultAsync(externalResultModel).Result;
}
catch (Exception ex)
{
pushedResult.Success = false;
}
if (pushedResult.Success)
{
_logService.PostLog(LogType.SuccessLog, pushedResult.Message);
}
else
{
_logService.PostLog(LogType.FailedLog, pushedResult.Message);
}
}
public async Task<PushedResultModel> PushResultAsync(ExternalResultModel externalResultModel)
{
// setup the requestMessage
HttpResponseMessage responseMessage = await _httpRequestService
.SendRequest(requestMessage)
.ConfigureAwait(false);
return new PushedResultModel
{
Success = responseMessage.IsSuccessStatusCode,
Message = await responseMessage.Content.ReadAsStringAsync()
};
}
public class HttpRequestService : IHttpRequestService
{
private readonly HttpClient _httpClient;
public HttpRequestService(IHttpClientAccessor httpClientAccessor)
{
_httpClient = httpClientAccessor.HttpClient;
}
public async Task<HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage)
{
HttpResponseMessage httpResponseMessage = await _httpClient.SendAsync(requestMessage).ConfigureAwait(false);
return httpResponseMessage;
}
}
答案 0 :(得分:0)
你应该从上到下一直实现异步等待。
如果我一直等待async,我该如何处理堆栈上方的方法,比如我的WebApi控制器?
让你的控制器动作像这样异步:
[RoutePrefix("api")]
public class PresidentsController : ApiController
{
[Route("presidents")]
public async Task<IHttpActionResult> GetPresidents()
{
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
return Ok();
}
}
这是实现异步方法的最简单方法。即使它会添加一些工作来将所有内容更改为异步,它将在未来受益,因为您将避免使用异步代码的许多问题。
如果你绝对必须在同步方法中使用异步方法,请将其阻塞在一个地方,如下所示:
public void MySyncMethod()
{
try
{
this.MyAsyncMethod().Wait();
}
catch (Exception exception)
{
//omited
}
}
private async Task MyAsyncMethod()
{
await AsyncLogic().ConfigureAwait(false);
}
但我不推荐它。你应该只使用异步等待一直到控制器动作。
答案 1 :(得分:-1)
在您的评论中,您说您希望在后台处理任务,而不是让客户端调用您的API等待。要做到这一点,你真的不需要使用async / await。
试试这个:
private void MyEndProcess()
{
// other stuff
Task.Run(_vendorPushService.PushResult()).ConfigureAwait(false); //fire and forget
_logService.PostLog(LogType.TestLog, "Test");
}
Task.Run
将启动任务,ConfigureAwait(false)
告诉它它不需要在我们当前所在的相同上下文中恢复(意味着上下文可以在任务之前关闭)已完成 - 即可以在不等待任务完成的情况下发回响应。
您将收到编译器警告,表示您没有等待Task.Run
,但这就是您想要的。
请注意,当您执行此操作时,HttpContext.Current
内将无法使用PushResult
。