【问题标题】:writing async Repository methods inside my asp.net mvc5 web application在我的 asp.net mvc5 Web 应用程序中编写异步存储库方法
【发布时间】:2015-12-02 11:22:58
【问题描述】:

我正在开发一个 asp.net mvc5 Web 应用程序 + Entity Framework 6。我想在我的应用程序中拥有一个存储库模型类。目前我正在遵循这种方法来拥有异步操作方法和异步存储库模型类。

例如我有以下存储库保存方法:

public class Repository
{
    private Entities t = newEntities();

    public async Task Save()
    {
        await t.SaveChangesAsync();
    }

我从我的操作方法中调用如下:

Repository repository = new Repository();
 public async Task<ActionResult> GetResourceByName(string resourcename)
      {
         await  repository.Save();
      }

那么这是一个正确的方法吗?因为我正在执行以下操作:

  1. 我将存储库方法定义为任务,并将操作方法​​定义为任务。那么我应该将它们都作为任务吗?

  2. 我在操作方法(调用 repo 方法时)和存储库上使用了两次await?那么这些await 是多余的吗?

//请注意,这只是存储库方法的一个简单示例,它仅用于保存模型,但我询问的是方法本身,因为我将在更复杂的存储库方法中使用这种方法..

【问题讨论】:

    标签: asp.net-mvc asynchronous asp.net-mvc-5 async-await entity-framework-6


    【解决方案1】:
    1. Q1:是的,两者都应该返回 Task,应该是这样,而且完全没问题。
    2. Q2:是的,两者都应该有 await(如果你有更多层,那么所有这些层中的所有函数调用都应该有 await)。

    基本上:一旦你进入 async/await,所有的调用链都应该是 async/await 以避免线程相关的问题......

    如果您不等待,则调用:“Fire and Forget”,不推荐,因为此请求将返回给用户并显示成功消息,但稍后,您进行的调用没有await 可能会失败并抛出异常,您不会知道该异常是什么......

    【讨论】:

    • 我完全了解“一劳永逸”。但我仍然不明白为什么我需要在我的操作方法中等待。例如,如果我将这个“await repository.Save()”替换为“repository.Save()//no await”,那么默认 asp.net mvc 将不会继续执行,除非它得到结果。并且由于 repo 方法使用 await "await t.SaveChangesAsync();"那么它应该等到保存完成,这是正确的吗?换句话说,除非“await t.SaveChangesAsync();”,否则操作方法将不会继续执行。已完成,所以为什么我需要等待和已经等待的方法!
    • 这不是真的。如果你不等待它不会等待,你不会知道调用的结果......
    【解决方案2】:

    回答您的问题:

    1. 是的,它们都应该返回任务。
    2. 是的,await 有意义。不,它们不是多余的。

    要了解为什么您可能(不必要)需要await 两次,我建议您看一下这篇文章,它给出了一个非常清晰的例子来说明它的工作原理和原因:

    C# async and await: Why Do We Need Them?

    如果您想使用存储库并且可能想考虑为您的业务逻辑使用服务,我建议您检查这个易于扩展和通用的项目:

    URF - Unit of Work & Repositories Framework

    在考虑从头开始开发所有内容之前,您应该检查一下。我真的很喜欢这个项目!

    【讨论】:

    • 感谢您提到我需要使用 await 两次的回复;在操作方法和存储库上。但我不确定为什么我需要等待一个已经等待的方法。因为我正在等待存储库类上的实体.savechnagesasync(),所以为什么我需要在调用已经等待的方法时使用等待?
    【解决方案3】:

    与两个答案相反,两个awaits 是不必要的。 awaitasync 仅当您在继续之前需要来自 Task 的结果时才需要。如果您不需要该结果,则无需标记您的方法async

    这表示这个方法……

    public async Task Save()
    {
        await t.SaveChangesAsync();
    }
    

    可以简化成

    public Task Save()
    {
        return t.SaveChangesAsync();
    }
    

    尽管它们在功能上相同,但我喜欢第二个版本,因为它表明 Task 是异步工作,而 async/await 只是向编译器发出等待该工作完成的信号。

    【讨论】:

    • 请注意,如果内部出现异常,堆栈跟踪t.SaveChangesAsync() 将不会显示Save(),而如果使用await,则会显示。
    • @Shoe 感谢您的回复,您提到“如果您不需要该结果,那么您不需要将您的方法标记为异步。”但我认为你的意思是“如果你不需要那个结果,那么你不需要标记你的方法等待”??这是正确的吗,因为 await 会导致系统在继续之前等待代码完成..
    • @Shoe “与两个答案相反,两个等待是不必要的”。答案并没有说它们是“必要的”,而是说这不是多余的。这是一个主要区别。
    • @johnG 标记方法异步“解锁” await 关键字。如果您将方法标记为异步但不等待任何内容,您将收到警告。如果你没有等待任何东西,那么你不需要将你的方法标记为异步。
    • @Maxime 我阅读您的答案的方式意味着这两种方法都需要等待(因此需要异步)。
    【解决方案4】:

    不管其他答案如何,这就是您应该使用await 等的原因。

    ASP.NET 具有将在每个await 上捕获的同步上下文,并且将为该上下文发布延续(async 方法的其余部分)。这不仅意味着线程切换,还意味着使用 ASP.NET 上下文填充切换到的线程。

    如果您为异步调用添加后缀(带有await 的调用加上对ConfigureAwait(false) 的调用,则不会发生 ASP.NET 上下文切换(尽管线程切换会发生)。

    因为动作视图引擎很可能需要 ASP.NET 上下文,所以不能在 MVC 动作方法上使用 ConfigureAwait(false)。但是你应该使用它调用的所有方法。

    所以,你的代码应该是这样的:

    public class Repository
    {
        private Entities t = new Entities();
        public async Task SaveAsync()
        {
            await t.SaveChangesAsync().ConfigureAwait(false);
        }
    }
    
    
    Repository repository = new Repository();
    public async Task<ActionResult> GetResourceByName(string resourcename)
    {
        await repository.SaveAsync();
    }
    

    因为在 await 调用 ConfigureAwait(false) 之后您可能没有 ASP.NET 上下文,所以您应该从 ASP.NET 上下文中传递您需要的所有内容作为参数。

    【讨论】:

    • 感谢您的回复.. 但我不明白为什么我需要添加“ConfigureAwait(false);”在 SaveAsync 里面?在我的情况下,我没有使用它,我没有发现任何问题,所以如果我不使用它会导致什么?
    • 请阅读these articles 了解async-await 的工作原理。
    • 所以你的意思是我需要使用“ConfigureAwait(false);” ??
    • 我认为你应该这样做。但是你需要阅读文章才能知道。
    • 重新进入请求上下文是一个快速的操作。 ASP.NET 应用程序并不真正需要 ConfigureAwait。它的目的实际上是为了构建一个可以被其他类型的应用程序定位的库。
    猜你喜欢
    • 2015-03-06
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多