有效地使用ASP.NET Web API的async/await

arp*_*arp 104 c# asp.net-mvc async-await asp.net-web-api

我试图async/await在我的Web API项目中使用ASP.NET 的功能.我不确定它是否会对我的Web API服务的性能产生任何影响.请在下面找到我的应用程序中的工作流程和示例代码.

工作流程:

UI应用程序→Web API端点(控制器)→Web API服务层中的调用方法→调用另一个外部Web服务.(这里我们有数据库交互等)

控制器:

public async Task<IHttpActionResult> GetCountries()
{
    var allCountrys = await CountryDataService.ReturnAllCountries();

    if (allCountrys.Success)
    {
        return Ok(allCountrys.Domain);
    }

    return InternalServerError();
}
Run Code Online (Sandbox Code Playgroud)

服务层:

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
    var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");

    return Task.FromResult(response);
}
Run Code Online (Sandbox Code Playgroud)

我测试了上面的代码并且正在运行.但我不确定它是否正确用法async/await.请分享你的想法.

Ste*_*ary 182

我不确定它是否会对我的API性能产生任何影响.

请记住,服务器端异步代码的主要好处是可伸缩性.它不会神奇地使您的请求运行得更快.我ASP.NET上的文章中介绍了几个"我应该使用async"的注意事项.async

我认为你的用例(调用其他API)非常适合异步代码,请记住"异步"并不意味着"更快".最好的方法是首先使您的UI响应和异步; 这将使您的应用程序感觉更快,即使它稍微慢一点.

就代码而言,这不是异步的:

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
  var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
  return Task.FromResult(response);
}
Run Code Online (Sandbox Code Playgroud)

您需要一个真正的异步实现来获得以下的可伸缩性优势async:

public async Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
  return await _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
Run Code Online (Sandbox Code Playgroud)

或者(如果你在这个方法中的逻辑真的只是一个传递):

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
  return _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
Run Code Online (Sandbox Code Playgroud)

请注意,从内到外工作更容易,而不是像这样"外在".换句话说,不要以异步控制器操作开始,然后强制下游方法是异步的.相反,识别自然异步操作(调用外部API,数据库查询等),并在最低级别(= Service.ProcessAsync)进行异步操作.然后让async涓涓细流,使控制器操作异步作为最后一步.

在任何情况下都不应该Task.Run在这种情况下使用.

  • 你能解释为什么你不在这里使用Task.Run吗? (5认同)
  • 感谢Stephen的宝贵意见.我确实将所有服务层方法都更改为异步,现在我使用ExecuteTaskAsync方法调用外部REST调用,并按预期工作.还要感谢您关于异步和任务的博文.获得初步了解对我帮助很大. (4认同)

Ric*_*ard 11

这是正确的,但可能没用.

由于没有什么可以等待 - 没有调用阻止可以异步操作的API - 然后你正在设置结构来跟踪异步操作(有开销)但后来没有使用该功能.

例如,如果服务层使用支持异步调用的Entity Framework执行数据库操作:

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
    using (db = myDBContext.Get()) {
      var list = await db.Countries.Where(condition).ToListAsync();

       return list;
    }
}
Run Code Online (Sandbox Code Playgroud)

在查询数据库时,您将允许工作线程执行其他操作(从而能够处理另一个请求).

Await往往需要一直向下:很难适应现有系统.