C# 这是在MVC中使用服务/存储库层的async/await的正确用法吗?

C# 这是在MVC中使用服务/存储库层的async/await的正确用法吗?,c#,.net,asp.net-mvc,entity-framework,async-await,C#,.net,Asp.net Mvc,Entity Framework,Async Await,使用VS2013、EF6.1.1、MVC5、.net 4.5 我刚刚开始第一次研究async/Wait,我不确定这是否正确。这似乎是可行的,但能简单一点吗?我似乎在很多地方坚持异步/等待一个方法调用多个层 为简洁起见,所有代码都已简化 在我的MVC控制器操作方法中,我有: public async Task<ActionResult> TestAction1() { var testResponse = await _testService.TestMethod1(1);

使用VS2013、EF6.1.1、MVC5、.net 4.5

我刚刚开始第一次研究async/Wait,我不确定这是否正确。这似乎是可行的,但能简单一点吗?我似乎在很多地方坚持异步/等待一个方法调用多个层

为简洁起见,所有代码都已简化

在我的MVC控制器操作方法中,我有:

public async Task<ActionResult> TestAction1()
{
    var testResponse = await _testService.TestMethod1(1);

    if (testResponse != null)
    {
        _unitOfWork.CommitAsync();
        return View(testResponse);
    }

    return RedirectToAction("TestAction2");
}
公共异步任务TestAction1()
{
var testResponse=wait_testService.TestMethod1(1);
if(testResponse!=null)
{
_unitOfWork.CommitAsync();
返回视图(testResponse);
}
返回重定向操作(“测试操作2”);
}
我的服务级别如下:

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();
    }
}
公共类测试服务:ITestService
{
公共异步任务TestMethod1()
{
var testObject1=await privateMethod1Async();
if(testObject1!=null)返回testObject1;
testObject1=等待privateMethod2Async();
返回testObject1;
}
专用异步任务privateMethod1Async()
{
返回wait_testRepository.FirstOrDefaultAsync();
}
专用异步任务privateMethod2Async()
{
返回wait_testRepository.FirstOrDefaultAsync();
}
}
和我的存储库方法:

public async Task<TEntity> FirstOrDefaultAsync()
{
    return await _entitySet.FirstOrDefaultAsync();
}
public async Task FirstOrDefaultAsync()
{
返回wait _entitySet.FirstOrDefaultAsync();
}
基本上,我有一个控制器方法,它调用一个服务方法。服务方法是以异步方式调用数据库层两次。但我觉得我正在改变每一个方法和层来处理异步,我不确定这里的内容是否正确

其次,在控制器方法中,我不确定如何异步调用工作单元提交方法。具有“_unitOfWork.CommitAsync();”的行。我不能在它前面加上“等待”,因为这是一个无效的方法

有什么想法吗


编辑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);
}
public async Task FirstOrDefaultAsync(表达式
谓词,参数
表达式[]
包括不动产)
{
IQueryable query=EntitySet;
if(includeProperties!=null&&includeProperties.Any())
{
查询=IncludeProperty(查询,IncludeProperty);
}
返回wait query.FirstOrDefaultAsync(谓词);
}

async await
在您的代码库中确实有向上爬行的趋势,这很好。您应该尽可能让它上升(在UI事件处理程序中,由于
async void
和UI
SynchronizationContext
的组合,它有可能一直上升到顶部)

当不再可能时(例如控制台应用程序的根目录),您可以简单地
等待
返回的任务:

var task = RunAsync();
task.Wait();
或者更好,您可以使用:


我在您的代码中看到了一种反复出现的模式:

private async Task<TestObject> privateMethod2Async()
{
    return await _testRepository.FirstOrDefaultAsync();
}
请注意,
asyncwait
将使您“一路异步”,这就是异步的本质。请确保使用
Task对可以同时运行的任务进行分组。例如,如果可能的话(不确定这是否是最好的示例):

假设其中一个方法可用作返回类型

编辑:

添加async/await的一般经验法则是什么?是 它是为一个在其中进行其他处理的方法而设计的吗?正如你所说的 出,这个方法没有

当您希望对返回的
任务执行更多处理时,可以使用
wait
。如果您只想返回实际的
任务
,则无需等待,只需返回热任务即可。这是我使用的一般规则。还请注意,当您使用
returnawait
与简单地使用
return
时,异常处理是不同的


您可以在和

包含“_unitOfWork.CommitAsync();”的行中阅读更多关于这方面的内容。我不能在它前面加上“等待”,因为这是一个无效的方法
public async Task CommitAsync(){…}
。啊,好吧,我想我对它的返回无能为力。所以没有办法用等待来填补我所缺少的空白?我想我对它的回归无能为力。不,您可以等待它。好的,谢谢。剩下的呢?我似乎在向每个methodf和层添加相同的async/await内容,是吗?将其一直放在DB层中,这是正确的方法吗?“考虑到这将是阻碍吗?”眼球保罗:是的。否则它就不会是异步的。好的,谢谢。我已经接受了另一个答案,因为它指出了一些事情,一件事是我不需要在较低级别上异步等待,只返回一个任务。@eyeballpaul这是真的。。。但无关紧要。在上一个示例中是否需要
async
。然而,你确实说到了一点。添加同步/等待的一般经验法则是什么?它是否用于在其中执行其他处理的方法?正如你所指出的,这个方法没有?YuvalItzchakov我已经用底部的编辑更新了我的问题,以显示该方法的完整版本。你还会说它不需要等待异步吗?另外,这两个方法调用需要一个接一个地完成。只有当第一个为空时,一个才会运行。@eyeballpaul关于第二个部分,这就是为什么我说它可能不是最好的例子,但我只是想说明可以做什么。关于您的编辑,是的,您肯定可以
返回query.FirstOrDefaultAsync(谓词)
并删除
async
修饰符。感谢您的帮助。我已将较低级别简化为仅返回“任务”,并将异步等待留给执行更多实际工作的服务级别。
private async Task<TestObject> privateMethod2Async()
{
    return await _testRepository.FirstOrDefaultAsync();
}
private Task<TestObject> privateMethod2Async()
{
    return _testRepository.FirstOrDefaultAsync();
}
public async Task<TestObject> TestMethod1()
{
    var testObject1 = await privateMethod1Async();
    if (testObject1 != null) return testObject1;

    testObject1 = await privateMethod2Async();

    return testObject1;
}
return Task.WhenAny(privateMethod1Async(), privateMethod2Async());