这是 async/await 在具有 service/repository 层的 MVC 中的正确用法吗?
Is this the correct usage of async/await in MVC with service/repository layer?
使用 VS2013、EF6.1.1、MVC5、.net 4.5。
我刚刚开始研究 async/await,这是第一次,我不确定这样做是否正确。它似乎有效,但它能更简单吗?我似乎在很多地方坚持 async/await 一个方法调用多个层。
为简洁起见,所有代码都已简化。
在我的 MVC 控制器操作方法中,我有:
public async Task<ActionResult> TestAction1()
{
var testResponse = await _testService.TestMethod1(1);
if (testResponse != null)
{
_unitOfWork.CommitAsync();
return View(testResponse);
}
return RedirectToAction("TestAction2");
}
我的服务class如下:
public class TestService : ITestService
{
public async Task<TestObject> TestMethod1()
{
var testObject1 = await privateMethod1Async();
if (testObject1 != null) return testObject1;
testObject1 = await privateMethod2Async();
return testObject1;
}
private async Task<TestObject> privateMethod1Async()
{
return await _testRepository.FirstOrDefaultAsync();
}
private async Task<TestObject> privateMethod2Async()
{
return await _testRepository.FirstOrDefaultAsync();
}
}
以及我的存储库方法:
public async Task<TEntity> FirstOrDefaultAsync()
{
return await _entitySet.FirstOrDefaultAsync();
}
基本上,我有一个调用服务方法的控制器方法。服务方法是以异步方式调用数据库层两次。但我觉得我正在改变每一个方法和层来处理异步,我不确定我这里的内容是否正确。
其次,在控制器方法中我不确定如何异步调用工作单元提交方法。具有“_unitOfWork.CommitAsync();”的行。我不能在它前面加上 "await",因为它是一个无效的方法。
有什么想法吗?
编辑 1
这是对 EF 的存储库方法调用的完整版本:
public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>>
predicate, params
Expression<Func<TEntity, object>>[]
includeProperties)
{
IQueryable<TEntity> query = EntitySet;
if (includeProperties != null && includeProperties.Any())
{
query = IncludeProperties(query, includeProperties);
}
return await query.FirstOrDefaultAsync(predicate);
}
async-await
确实有在您的代码库中向上爬行的倾向,这完全没问题。你应该尽可能让它上升(在 UI 事件处理程序中,由于 async-void
和 UI SynchronizationContext
)
当它不再可能时(例如控制台应用程序的根目录),您可以简单地 Wait
返回的任务:
var task = RunAsync();
task.Wait();
或者更好,您可以使用 Stephen Cleary's AsyncContext
:
AsyncContext.Run(RunAsync);
我在您的代码中看到一个重复出现的模式:
private async Task<TestObject> privateMethod2Async()
{
return await _testRepository.FirstOrDefaultAsync();
}
当你有一个简单地查询你的数据库以获得 Task<T>
的单行程序时,你可以避免 await
导致的状态机分配,并且只需 return 热调用者的任务(因为他可能会在调用链的更高层等待它):
private Task<TestObject> privateMethod2Async()
{
return _testRepository.FirstOrDefaultAsync();
}
请注意 async-await
会让你走 "async all the way",这就是异步的本质。确保将可以 运行 并发使用 Task.WhenAll
的任务分组,例如(不确定这可能是最好的例子):
public async Task<TestObject> TestMethod1()
{
var testObject1 = await privateMethod1Async();
if (testObject1 != null) return testObject1;
testObject1 = await privateMethod2Async();
return testObject1;
}
也许可以变成:
return Task.WhenAny(privateMethod1Async(), privateMethod2Async());
鉴于其中一种方法适用于 return 类型。
编辑:
What is the general rule rule of thumb for adding the async/await? is
it for a method that does other processing in it? Which, as you point
out, this method doesn't?
如果您想对 returned Task
进行更多处理,您可能会想使用 await
。如果只想return实际Task
,没必要等待,直接return热点任务即可。这是我使用的一般规则。另请注意,当您使用 return await
与简单 return
.
时,异常处理是不同的
您可以在 At the end of an async method, should I return or await? and Any difference between "await Task.Run(); return;" and "return Task.Run()"?
中阅读更多相关信息
使用 VS2013、EF6.1.1、MVC5、.net 4.5。
我刚刚开始研究 async/await,这是第一次,我不确定这样做是否正确。它似乎有效,但它能更简单吗?我似乎在很多地方坚持 async/await 一个方法调用多个层。
为简洁起见,所有代码都已简化。
在我的 MVC 控制器操作方法中,我有:
public async Task<ActionResult> TestAction1()
{
var testResponse = await _testService.TestMethod1(1);
if (testResponse != null)
{
_unitOfWork.CommitAsync();
return View(testResponse);
}
return RedirectToAction("TestAction2");
}
我的服务class如下:
public class TestService : ITestService
{
public async Task<TestObject> TestMethod1()
{
var testObject1 = await privateMethod1Async();
if (testObject1 != null) return testObject1;
testObject1 = await privateMethod2Async();
return testObject1;
}
private async Task<TestObject> privateMethod1Async()
{
return await _testRepository.FirstOrDefaultAsync();
}
private async Task<TestObject> privateMethod2Async()
{
return await _testRepository.FirstOrDefaultAsync();
}
}
以及我的存储库方法:
public async Task<TEntity> FirstOrDefaultAsync()
{
return await _entitySet.FirstOrDefaultAsync();
}
基本上,我有一个调用服务方法的控制器方法。服务方法是以异步方式调用数据库层两次。但我觉得我正在改变每一个方法和层来处理异步,我不确定我这里的内容是否正确。
其次,在控制器方法中我不确定如何异步调用工作单元提交方法。具有“_unitOfWork.CommitAsync();”的行。我不能在它前面加上 "await",因为它是一个无效的方法。
有什么想法吗?
编辑 1
这是对 EF 的存储库方法调用的完整版本:
public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>>
predicate, params
Expression<Func<TEntity, object>>[]
includeProperties)
{
IQueryable<TEntity> query = EntitySet;
if (includeProperties != null && includeProperties.Any())
{
query = IncludeProperties(query, includeProperties);
}
return await query.FirstOrDefaultAsync(predicate);
}
async-await
确实有在您的代码库中向上爬行的倾向,这完全没问题。你应该尽可能让它上升(在 UI 事件处理程序中,由于 async-void
和 UI SynchronizationContext
)
当它不再可能时(例如控制台应用程序的根目录),您可以简单地 Wait
返回的任务:
var task = RunAsync();
task.Wait();
或者更好,您可以使用 Stephen Cleary's AsyncContext
:
AsyncContext.Run(RunAsync);
我在您的代码中看到一个重复出现的模式:
private async Task<TestObject> privateMethod2Async()
{
return await _testRepository.FirstOrDefaultAsync();
}
当你有一个简单地查询你的数据库以获得 Task<T>
的单行程序时,你可以避免 await
导致的状态机分配,并且只需 return 热调用者的任务(因为他可能会在调用链的更高层等待它):
private Task<TestObject> privateMethod2Async()
{
return _testRepository.FirstOrDefaultAsync();
}
请注意 async-await
会让你走 "async all the way",这就是异步的本质。确保将可以 运行 并发使用 Task.WhenAll
的任务分组,例如(不确定这可能是最好的例子):
public async Task<TestObject> TestMethod1()
{
var testObject1 = await privateMethod1Async();
if (testObject1 != null) return testObject1;
testObject1 = await privateMethod2Async();
return testObject1;
}
也许可以变成:
return Task.WhenAny(privateMethod1Async(), privateMethod2Async());
鉴于其中一种方法适用于 return 类型。
编辑:
What is the general rule rule of thumb for adding the async/await? is it for a method that does other processing in it? Which, as you point out, this method doesn't?
如果您想对 returned Task
进行更多处理,您可能会想使用 await
。如果只想return实际Task
,没必要等待,直接return热点任务即可。这是我使用的一般规则。另请注意,当您使用 return await
与简单 return
.
您可以在 At the end of an async method, should I return or await? and Any difference between "await Task.Run(); return;" and "return Task.Run()"?
中阅读更多相关信息