提问人:Abbas Farahani 提问时间:10/17/2023 最后编辑:marc_sAbbas Farahani 更新时间:10/18/2023 访问量:65
如何使用 await 使控制器的方法异步?
How to use await for making my controller's method asynchronous?
问:
我正在处理一个 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 查询更改为异步。
我想将异步添加到我的方法中,但我不知道该怎么做
答:
异步方法不会使查询速度更快,也不会使调用查询的方法更快。事实上,它将使调用查询的方法稍微慢一些。它的作用是允许像 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()
await
Task
DbContext
await
List<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
评论
await
var results=query.ToList()
var results=await query.ToListAsync()
dynamic
new MyEntities();
<-- 如果这样做,则意味着程序代码中有一个硬编码的连接字符串,这意味着代码在不同的计算机或环境中运行时将不起作用。请学习如何正确使用DI。async / await