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

How to use await for making my controller's method asynchronous?

提问人:Abbas Farahani 提问时间:10/17/2023 最后编辑:marc_sAbbas Farahani 更新时间:10/18/2023 访问量:65

问:

我正在处理一个 ASP.NET MVC 项目,我想使我的控制器及其方法异步,但我不知道在哪里放置“等待”。

在我的控制器方法中,我调用了一个服务层的方法,该方法使用 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;
    }
}

但在服务中,我尝试更改并使用 awawait:query

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

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

我想将异步添加到我的方法中,但我不知道该怎么做

实体框架 linq asp.net-mvc-4 异步 await

评论

4赞 Panagiotis Kanavos 10/17/2023
你不能用它来神奇地使同步方法异步。您可以使用它来等待已异步的方法。而不是使用 use .awaitvar results=query.ToList()var results=await query.ToListAsync()
2赞 Dai 10/17/2023
此外,您根本不应该在此处使用。它不会帮助你,它只会引起问题。dynamic
1赞 Dai 10/17/2023
new MyEntities();<-- 如果这样做,则意味着程序代码中有一个硬编码的连接字符串,这意味着代码在不同的计算机或环境中运行时将不起作用。请学习如何正确使用DI。
0赞 mason 10/17/2023
你期望异步代码在这里为你实际完成什么?使用异步控制器方法会如何更好?
1赞 marc_s 10/17/2023
另外,仅仅引入不会神奇地使这段代码运行得更快......async / await

答:

0赞 Steve Py 10/18/2023 #1

异步方法不会使查询速度更快,也不会使调用查询的方法更快。事实上,它将使调用查询的方法稍微慢一些。它的作用是允许像 Web 服务器这样的东西响应速度更快,因为它会将 Web 请求移交给后台工作线程并继续响应其他用户请求。(只要此查询需要,等待的原始请求仍将等待响应,直到超时)

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

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”,尤其是在混合了异步和同步变体的情况下。如果你在没有的情况下打电话,你将被退回,它本身可以等待或等待等待,等等。请注意,EF 的 DbContext 不是线程安全的,因此,如果使用常见的注入实例,请不要尝试并行化这样的查询。添加时,任务将自动给出一个恢复点,等待调用后的代码将处理返回的数据类型。即.getFromDbAsync()awaitTaskDbContextawaitList<dynamic>

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

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

至于提高性能?一些简单的提示。不要试图在编码时变得聪明或懒惰。 对于这样的事情来说,这是一个巨大的危险信号。使用具体的 DTO 针对每个特定方案进行投影。此外,当涉及到从用户的输入中读取操作时,请仅基于他们实际需要的内容,而不是您认为他们可能想要的内容,甚至是他们所说的他们想要的内容。为用户提供过于灵活的查询功能是下沉项目的必经之路。当他们告诉你他们有老鼠问题时,它给了他们一个没有说明手册的克莱莫尔地雷,而不是一个捕鼠器。如果 95% 的时间更简单、具有合理数量的参数的索引查询可以完成工作,则为这些查询生成和索引。构建复杂的动态结果和标准将导致代码速度变慢、错误,并且您追逐满足的剩余 5% 会导致查询,从而使您的系统陷入瘫痪。未编制索引、成本高昂的查询会触及太多表,从而创建行锁,从而减慢其他所有内容的速度。然后用户发现它花费的时间太长,所以他们关闭选项卡并打开一个新选项卡,或者认为他们会在后台启动几个。dynamic