从同步控制器方法到异步控制器方法的正确转换(使用void时)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从同步控制器方法到异步控制器方法的正确转换(使用void时)相关的知识,希望对你有一定的参考价值。

使用Entity Framework Core 2.0和.NET Core 2.0 Web API控制器我试图将它们从同步方法重写为异步方法。

这实际上对于我的控制器方法只是查询数据很容易。

不幸的是,我将DbContext方法SaveChanges包装到一些辅助方法中,用于集中记录数据库更改。

在这里,我开始努力如何在异步上下文中正确使用void的组合。

代码说明:MyController是一个web api控制器。 PostMethod是一个(当前)同步post方法,接收请求模型,处理它,进行更改然后保存更改。

控制器中的SaveChangesWithLogs调用扩展方法并打印返回的日志。

扩展方法SaveChangesWithLogs生成日志条目(一些在保存之前,一些在保存之后),执行实际保存并返回日志。


  public class MyController : BaseController 
  {

    [HttpPost]
    public IActionResult PostMethod([FromBody]PostRequestModel request)
    {
        //do something
        SaveChangesWithLogs();
        //return created at
    }

    protected void SaveChangesWithLogs()
    {
      List logs = DbContext.SaveChangesWithLogs();
      foreach (string log in logs)
      {
        LogInfo(log); //just prints the generated logs
      }
    }

  }

  public static class MyExtensionMethod 
  {

    public static List SaveChangesWithLogs(this DbContext dbContext)
    {
      List logs = null;
      //pre-save prepare logs
      dbContext.SaveChanges();
      //post-save modifications of logs
      return logs;
    }
  }

在关于异步编程的教程中,他们提到方法应该一直是异步的。

所以我的问题是:SaveChangesWithLogs方法的(方法签名)如何?


  public class MyController2 : BaseController 
  {

    [HttpPost]
    public async Task PostMethod([FromBody]PostRequestModel request)
    {
        //do something
        await SaveChangesWithLogs();
        //return created at
    }

    //does a correct implementation need async here too?
    protected void SaveChangesWithLogs()
    {
      List logs = await DbContext.SaveChangesWithLogs();
      foreach (string log in logs)
      {
        LogInfo(log); //just prints the generated logs
      }

      //return what???
    }

  }

  public static class MyExtensionMethod2 
  {

    public static async Task> SaveChangesWithLogs(this DbContext dbContext)
    {
      List logs = null;
      //pre-save prepare logs
      await dbContext.SaveChanges();
      //post-save modifications of logs
      return logs;
    }
  }
答案

您只需像以前一样使用返回类型并围绕它包装Task。没有比这更神奇了。

我猜你的List类型是某种类型,并添加它用于显示目的。

protected async Task<bool> SaveChangesWithLogs()
    {
      List logs = await DbContext.SaveChangesWithLogs();
      foreach (string log in logs)
      {
        LogInfo(log); //just prints the generated logs
      }      
      return true;
    }

public static async Task<List<myLogType>> SaveChangesWithLogs(this DbContext dbContext)
{
    List<myLogType> logs = null;
    //pre-save prepare logs
    await dbContext.SaveChanges();
    //post-save modifications of logs
    return logs;
}

以上是关于从同步控制器方法到异步控制器方法的正确转换(使用void时)的主要内容,如果未能解决你的问题,请参考以下文章

为啥异步控制器方法像同步方法一样执行?

从同步代码调用异步方法并阻塞直到任务完成的正确方法是啥? [复制]

Spring boot:使用异步方法作为同步方法

java CountDownLatch 控制异步和同步

即使使用 ConfigureAwait(false) 在 WebAPI 死锁中同步调用异步方法

AJAX中同步和异步的区别和使用场景