如何使用await使我的控制器的方法异步?

问题描述 投票:0回答:1

我正在开发一个 ASP.NET MVC 项目,我想让我的控制器及其方法异步,但我不知道在哪里放置“await”。

在我的控制器的方法中,我调用了服务层的方法,该方法使用 linq 查询从数据库获取数据:

public class MyController: Controller
{
    private MyEntities db = new MyEntities();

    public MyController()
    {
         this.service = new MyService(db);
    }

    public List<dynamic> myMethod(FormCollection post)
    {
        var x = post["itemOne"];
        List<dynamic> myVar = service.getFromdb(x);
        return var;
    }
}

Linq 查询需要很多时间,我想把

await
放在这一行的开头。

我的 Linq 查询是这样的:

public MyService : IMyService 
{
    public List<dynamic> getFromdb(string x)
    {
        var query = (from dum in db.TableOne 
                     where dum.colOne == x
                     select new
                            {
                                col1 = dum.colOne,
                                col2 = dum.colTwo,
                                col3 = dum.colThree,
                            })
                   .Union(from dum2 in db.TableOne 
                          where dum.colTwo == x
                          select new
                                 {
                                     col1 = dum2.colOne,
                                     col2 = dum2.colTwo,
                                     col3 = dum2.colThree,
                                 })
                   .GroupBy(g => new 
                                 {
                                     myG1 = g.colOne,
                                     myG2 = g.colTwo,
                                 })
                   .Select(s => new 
                                {
                                    col1 = s.Key.myG1,
                                    col2 = s.Key.myG2,
                                    col3 = s.Count()
                                })
                   .Join(db.TableTwo,
                         g => new { g.col1, g.col2 },
                         t => new { t.col1, t.col2 },
                         (g,t) => new 
                                  {
                                      finalCol1 = g.col1,
                                      finalCol2 = g.col2,
                                      finalCol3 = g.col3,
                                      finalCol4 = t.colX,
                                      finalCol5 = t.colY,
                                  })
                  .OrderByDescenging(y => new { mycol1 = y.finalCol1 , mycol2 = y.finalCol2 })
                  .Select(s => s);

        if (SOMETHING TRUE)
        {
            return query.Skip(1000)
                        .Take(500)
                        .Select(s => s)
                        .ToList();
        }
        else
        {
             return query.Skip(2000)
                         .Take(100)
                         .Select(s => s)
                        .ToList();
        }
    }
}

我尝试将我的方法

myMethod
更改为:

public class MyController: Controller
{
    public async List<dynamic> myMethod(FormCollection post)
    {
        var x = post["itemOne"];
        List<dynamic> myVar = await service.getFromdb(x);
        return var;
    }
}

但在服务中我尝试更改

query
并使用await:

public async List<dynamic> getFromdb(string x)
{
      var query = await (from dum in db.TableOne 
        .......
}

但我不知道如何将 Linq 查询更改为异步。

我想将异步添加到我的方法中,但我很困惑该怎么做

entity-framework linq asynchronous asp.net-mvc-4 async-await
1个回答
0
投票

异步方法不会使您的查询更快或调用查询的方法更快。事实上,它会使调用查询的方法稍微慢一些。它将做的是允许像 Web 服务器这样的东西更快地响应,因为它将 Web 请求交给后台工作人员并恢复响应其他用户请求。 (只要该查询持续,等待的原始请求仍将等待响应,直到超时)

因此,考虑到这一点,缺少的一点是异步方法返回任务:

public async Task<List<dynamic>> myMethodAsync(FormCollection post)
{
    var x = post["itemOne"];
    List<dynamic> myVar = await service.getFromdb(x);
    return var;
}

public async Task<List<dynamic>> getFromDbAsync(string x, int page, int pageSize)
{
    var query = ... 

    return await query.Skip(page*pageSize)
                    .Take(pageSize)
                    .ToListAsync();
}

对于方法(除了控制器操作之类的东西),您应该在异步声明后加上“Async”后缀,特别是当您混合使用异步和同步变体时。如果您要在没有

getFromDbAsync()
的情况下调用
await
,您将返回
Task
,它本身可以等待或使用 WaitAll 等待。请注意,EF 的 DbContext 不是线程安全的,因此不要尝试并行化查询,例如如果使用常见的注入
DbContext
实例,则会出现此情况。当您添加
await
时,任务将自动给出一个恢复点,并且等待调用之后的代码将处理返回的数据类型。 IE。
List<dynamic>

var results = getFromDbAsync(someValue, 0, 500); // results = Task<List<dynamic>>

var results = await getFromDbAsync(someValue, 0, 500); // results = List<dynamic>

至于提升性能?一些简单的提示。不要试图在编码时变得聪明或懒惰。对于这样的事情来说,

dynamic
是一个巨大的危险信号。使用具体的 DTO 来预测每个特定场景。此外,当涉及到从用户输入读取操作时,仅基于他们实际需要的内容,而不是您认为他们可能想要的内容,甚至是他们所说的想要的内容。给用户过于灵活的查询能力肯定会导致项目沉没。当他们告诉你他们有老鼠问题时,它会给他们一个没有说明书的克莱莫地雷,而不是一个捕鼠器。如果 95% 的情况下更简单,具有合理数量参数的索引查询就可以完成工作,然后为这些查询构建并建立索引。构建复杂的、动态的结果和标准将导致代码速度变慢、错误较多,并且您正在追逐剩下的 5% 来满足查询结果,这实际上会使您的系统陷入困境。非索引、昂贵的查询涉及太多表,创建行锁会减慢其他所有操作的速度。然后用户发现它花费的时间太长,因此他们关闭选项卡并打开一个新选项卡,或者认为他们会在后台启动几个选项卡。

© www.soinside.com 2019 - 2024. All rights reserved.