【问题标题】:EntityFramework (6) and async ( waitingForActivation)?EntityFramework(6)和异步(waitForActivation)?
【发布时间】:2013-07-11 07:12:16
【问题描述】:

我已经下载了EF6(为了使用async

所以我写了这个简单的方法:

  public async Task<List<int>> MyasyncMethod()
      {
          var locations = await MyDumpEntities.AgeGroups.Select(f=>f.endYear).ToListAsync();
          return locations;
       }

   ...Later...


  DumpEntities1 MyDumpEntities = new DumpEntities1();
  var data = MyDumpEntities.AgeGroups.ToListAsync();
  MyasyncMethod().ContinueWith(s => { Response.Write("f"); });
  MyDumpEntities.Dispose();

但我在屏幕上看不到任何东西,当我检查 data 时,我看到了这个:

附言这是ToListAsync 签名

我错过了什么?

【问题讨论】:

  • 你不是await这个电话,你应该去var data = await MyDumpEntities.AgeGroups.ToListAsync();...
  • 他不是在等待返回任务的 MyasyncMethod() 调用吗?
  • @PatrykĆwiek noope i.stack.imgur.com/WqdZb.png
  • @RoyiNamir 您的方法 (Page_Load) 未标记为 async,所以这并不奇怪 :) 您必须将方法标记为 asyncawait 调用或等待以某种方式执行(继续,阻塞等待)

标签: c# entity-framework .net-4.5 async-await entity-framework-6


【解决方案1】:

基于 cmets 和您遇到问题的行:

var data = MyDumpEntities.AgeGroups.ToListAsync();

data 类型是什么? Task&lt;List&lt;AgeGroup&gt;&gt;。没错,不是List&lt;AgeGroup&gt;。 因此,您要么必须将Page_Load 标记为异步(如果可能):

public async void Page_Load(object sender, EventArgs e)
{
    using(var MyDumpEntities = new DumpEntities1())
    {
       var data = await MyDumpEntities.AgeGroups.ToListAsync();
    }     
}

或者以某种方式等待执行(继续,阻塞等待)。

另一件事(如果我错了,其他人可能想要更正),但由于您在第二次调用中使用延续,所以我会非常小心地在延续之外处理上下文。结果可能是您先发制人地处置了上下文。在这种特殊情况下,您没有在延续中使用上下文,但它看起来很可疑......

所以我要么

MyasyncMethod().ContinueWith(s => { Response.Write("f"); MyDumpEntities.Dispose();});

或者也可以在那里使用async

var result = await MyasyncMethod();
Response.Write("f");
MyDumpEntities.Dispose();

并在页面指令中添加Async="True"

【讨论】:

  • 我认为如果 MyasyncMethod 已经被标记为 async ,我也不需要在 page_load........bummer 中这样做
  • @RoyiNamir 好吧,如果您想在方法中使用await,则必须将该特定方法标记为async。当然,“一直向下异步”是个好主意,即使在辅助方法中也是如此......
  • async all the way down - 说得好。不知道我应该这样做。
【解决方案2】:

其他人已经指出正确的解决方案是使用await,但我没有看到一个很好的解释为什么

原始代码错误的原因有两个。首先,您在使用 ContinueWith 时没有捕获 ASP.NET 应用程序中的上下文,因此延续(Response.Write 调用)没有请求上下文,因此没有可写入的响应。

await 通过捕获await 之前的上下文并使用它来恢复方法的其余部分来为您处理此问题;在这种情况下,它将捕获代表当前请求/响应的AspNetSynchronizationContext

另一个原因是异步代码会并发运行。因此,MyasyncMethod 将开始执行,到达其await,并将未完成的任务返回给Page_LoadPage_Load 然后将一个延续附加到该任务并继续执行,处理上下文。因此,可以在 ToListAsync 请求仍在运行时释放上下文。

await 也为您解决了这个问题,因为它会“暂停”Page_Load 方法,直到 MyasyncMethod 完成。

最后一点,在 ASP.NET 中使用 async 时还应考虑以下几点:

  1. 您必须以 .NET 4.5 为目标。不要使用Microsoft.Bcl.Async
  2. 您必须将targetFramework 设置为4.5,UseTaskFriendlySynchronizationContext 设置为true。
  3. (仅限 WebForms)将 Page.Async 设置为 true。
  4. 考虑使用RegisterAsyncTask 而不是await。我通常更喜欢await,因为不同的方法有更多的关注点分离,但 ASP.NET 团队更喜欢RegisterAsyncTask,因为在PreRender 之后有一个“同步”点,运行时等待所有操作完成。 See this article for how to use RegisterAsyncTask.
  5. 建立您自己的请求超时。异步 ASP.NET 请求不会自动使用内置于同步 ASP.NET 请求的正常超时。有两种选择:
    • 使用HttpRequest.TimedOut 取消令牌。
    • (仅限 WebForms/RegisterAsyncTask)您可以通过设置 Page.AsyncTimeout 并让您的 async 方法采用 CancellationToken 来添加异步超时。

【讨论】:

【解决方案3】:

ToListAsync 返回一个Task。将Page_Load标记为async,就可以在里面使用await了。

粗略的规则:如果有东西返回一个任务(方法名称中包含“Async”),你必须等待它。

另外,在使用 async/await 时,您不必使用 ContinueWith。只需等待您自己的方法并将Write 调用放在下一行即可。

DumpEntities1 MyDumpEntities = new DumpEntities1();
var data = await MyDumpEntities.AgeGroups.ToListAsync();
var dataFromMyMethod = await MyasyncMethod()
Response.Write("f");
MyDumpEntities.Dispose();

并在页面指令中添加Async="True"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 2015-03-23
    相关资源
    最近更新 更多