【问题标题】:Asynchronous Controllers in Web ApiWeb Api 中的异步控制器
【发布时间】:2016-08-02 13:54:11
【问题描述】:

我对异步 Web API 编程有非常基本的基本疑问。我想在我的控制器中异步调用 SaveCaseSearch。但是调用会经过DAL的各个层,最终调用DB。

这些连续调用也应该异步进行吗?

我对异步世界很陌生,所以我可能已经犯了一些错误。如果有任何问题,请纠正我。

所以对于控制器,我正在做类似下面的事情:

/*Create API for Case*/
[HttpPost]
[Route("createcase")]
public IHttpActionResult PostCreateCase([FromBody]  ARC.Donor.Business.Case.CreateCaseInput CreateCaseInput)
{
    ARC.Donor.Service.Case.CaseServices cs = new ARC.Donor.Service.Case.CaseServices();
    var searchResults = cs.createCase(CreateCaseInput);
    List<CreateCaseOutput> searchOutputResults = (List<CreateCaseOutput>)searchResults;
    if (!string.IsNullOrEmpty(searchOutputResults.ElementAt(0).o_case_seq.ToString()))
       SaveCaseSearchDetails(SaveSearchInput); /*This should be called asynchronously*/
    return Ok(searchResults);
}

这个

SaveCaseSearchDetails

现在需要在异步模式下调用。所以我写了:

[HttpPost]
public async Task<IHttpActionResult> SaveCaseSearchDetails([FromBody]  ARC.Donor.Business.SaveSearchInput SaveSearchInput)
{
    ARC.Donor.Service.Case.CaseServices cs = new ARC.Donor.Service.Case.CaseServices();
    var searchResults = await cs.saveCaseSearchDetails(SaveSearchInput);
}

如果正确的话

连续调用也应该异步吗?

现在他们是

public IList<Entities.Case.SaveCaseSearchOutput> saveCaseSearch(ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput)
{
    Repository rep = new Repository();
    string strSPQuery = string.Empty;
    List<object> listParam = new List<object>();
    SQL.CaseSQL.getCreateCaseParameters(SaveCaseSearchInput, out strSPQuery, out listParam);
    var AcctLst = rep.ExecuteStoredProcedure<Entities.Case.SaveCaseSearchOutput>(strSPQuery, listParam).ToList();
    return AcctLst;
}

SQL.CaseSQL.getCreateCaseParameters

方法需要以异步方式调用吗? 但在这种情况下,紧接着的下一行

rep.ExecuteStoredProcedure

不能成功执行吧?因为 strSPQuery 来自上一行本身?

我想错了?请纠正我。

【问题讨论】:

  • Should those consecutive calls also be made asynchronous ? 是的,如果你想要“真正的”异步功能。
  • 但是在那种情况下,就像我描述的最后一种情况一样,它会坏吗?
  • 你期望“异步”做什么?除非阻塞操作是它们自己异步的,否则你仍然需要阻塞一个线程来运行它们。

标签: c# asynchronous asp.net-web-api async-await


【解决方案1】:

您不能以异步方式(使用 await)调用 SQL.CaseSQL.getCreateCaseParameters,因为它使用了不适用于异步方法的 out 关键字。

如果您希望您的数据库调用异步发生,您必须找到一个可以await 的数据库方法。然后您可以将 saveCaseSearch 方法更改为异步并从您的控制器方法中等待它。

【讨论】:

  • 现在我不想破坏我现有的服务和 DAL 层功能。那么我可以让它们保持同步吗?还是它反对异步拓扑并会导致我的应用程序出现性能问题?
  • 如果异步方法中没有“等待”,它将同步运行,因此不会发生任何意外。您的 IDE 可能会警告您,但仅此而已。 (请注意,在这种情况下,使您的控制器方法异步是没有意义的,您不妨使其同步)
  • @StrugglingCoder 如果你想要异步,你必须打破你的同步 DAL 并添加 asynchronous 方法最终使 real i> 异步数据库调用,例如调用 ExecuteReaderAsync 而不是 ExecuteReader。否则,您最终会阻塞一个线程——无论是原始线程还是其他从 Task.Run 开始的线程。你不会得到任何好处,但你会支付额外的开销
  • 不,您面临的问题是您有一个想要“异步”调用的 同步 层。但这甚至没有意义——如果你要阻塞 另一个 线程,那么释放原始线程有什么意义呢?您仍然浪费了一个线程,但增加了切换的开销。但是,异步 DAL 调用会在等待数据库响应时完全释放原始线程而不使用新线程。
  • @StrugglingCoder 如果您不想将阻塞操作转换为异步操作,您希望从控制器异步中获得什么?也许您误解了 Web 应用程序(不仅仅是 Web API)中“异步”的含义?
【解决方案2】:

这些连续调用也应该异步进行吗?

是的。

SaveCaseSearchDetails 现在需要在异步模式下调用

这是很难做到的。

更自然的方法是从另一端开始。您的代码的任何部分实际上都在执行数据库查询,first 应该是异步的。然后你使用await 调用它,这使得这些方法成为async,所以它们应该使用await 等调用,直到你最终到达你的控制器操作,这是最后的事情异步。

实际上我面临的问题是 PostCaseCreate 方法中的 SaveCaseSearchDetails(SaveSearchInput) 需要在某种程度上异步调用,因为我们不想等待返回 Ok(searchResults)

啊,这是一个完全不同的问题。你想早点回来Async 不会帮你做到这一点;正如我在我的博客(和MSDN article on async ASP.NET)中解释的那样,async does not change the HTTP protocol

我在博客中描述了returning early or "fire and forget" on ASP.NET 的几种方法。但是,ASP.NET 不是为这种情况设计的,因此您需要谨慎行事。唯一完全可靠的解决方案是正确分布的架构。

【讨论】:

  • 感谢您的洞察力。但是 SQL.CaseSQL.getCreateCaseParameters(SaveCaseSearchInput, out strSPQuery, out listParam); var AcctLst = rep.ExecuteStoredProcedure(strSPQuery, listParam).ToList();第一行包含我认为等待不支持的 out 关键字。直接行使用 out 关键字结果。如何使用 async/await 方法来实现?
  • @StrugglingCoder:你仍然从错误的方向接近这个。如果getCreateCaseParameters 不与数据库通信(很可能),那么您将永远不需要使其成为async。如果是这样,那么您只需要返回两个值。
猜你喜欢
  • 2013-04-22
  • 2011-10-03
  • 1970-01-01
  • 2021-09-19
  • 2018-03-31
  • 2015-01-01
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多