这是异步的正确用法/等待在MVC与服务中心/存储库层? [英] Is this the correct usage of async/await in MVC with service/repository layer?

查看:249
本文介绍了这是异步的正确用法/等待在MVC与服务中心/存储库层?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用VS2013,EF6.1.1,MVC5,.NET 4.5。

我刚刚开始寻找到异步/等待是第一次,我不知道这是正确的做这件事。它似乎工作,但会不会是简单?我似乎是坚持异步/等待在很多地方的一种方法叫下来多层。

所有code已被简化为简洁起见。

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

 公共异步任务<的ActionResult> TestAction1()
{
    变种testResponse =等待_testService.TestMethod1(1);

    如果(testResponse!= NULL)
    {
        _unitOfWork.CommitAsync();
        返回查看(testResponse);
    }

    返回RedirectToAction(TestAction2);
}
 

我的服务类如下:

 公共类TestService的:ITestService
{
    公共异步任务<的TestObject> TestMethod1()
    {
        VAR testObject1 =等待privateMethod1Async();
        如果(!testObject1 = NULL)返回testObject1;

        testObject1 =等待privateMethod2Async();

        返回testObject1;
    }

    私人异步任务<的TestObject> privateMethod1Async()
    {
        返回等待_testRepository.FirstOrDefaultAsync();
    }

    私人异步任务<的TestObject> privateMethod2Async()
    {
        返回等待_testRepository.FirstOrDefaultAsync();
    }
}
 

和我的仓库方式:

 公共异步任务< TEntity> FirstOrDefaultAsync()
{
    返回等待_entitySet.FirstOrDefaultAsync();
}
 

基本上,我有一个控制器方法,调用服务的方法。该服务方法是调用数据库层两次,异步的方式。但我觉得我改变每一个方法和层来处理异步,我不知道如果我在这里是正确的。

其次,在控制器方法我不能确定如何调用工作单位提交方法以异步方式。有行_unitOfWork.CommitAsync();。我不能坚持一个等待之前,因为它是一种无效的方法。

有什么想法?


编辑1

下面是完整版的库方法调用EF的:

 公共异步任务< TEntity> FirstOrDefaultAsync(前pression< Func键< TEntity,布尔>>
                                               predicate,PARAMS
                                               [];防爆pression< Func键< TEntity,对象>&GT
                                               includeProperties)
{
    IQueryable的< TEntity>查询= EntitySet的;
    如果(includeProperties = NULL和放大器;!&安培; includeProperties.Any())
    {
        查询= IncludeProperties(查询,includeProperties);
    }
    返回等待query.FirstOrDefaultAsync(predicate);
}
 

解决方案

我看到你的code中反复出现的模式:

 专用异步任务<的TestObject> privateMethod2Async()
{
    返回等待_testRepository.FirstOrDefaultAsync();
}
 

当你有一个衬垫,它简单地查询您的数据库为任务< T> ,可以避开状态机的分配而等待的原因,并简单地返回炎热的任务给调用者(因为他可能会在其上等待反正越往上调用链):

 私人任务<的TestObject> privateMethod2Async()
{
    返回_testRepository.FirstOrDefaultAsync();
}
 

注意异步等待会让你走的异步一路的,这是异步的本质。请确保您组的任务,可以通过同时运行 Task.WhenAll 如果可能的话,例如(不知道这可能是最好的例子):

 公共异步任务<的TestObject> TestMethod1()
{
    VAR testObject1 =等待privateMethod1Async();
    如果(!testObject1 = NULL)返回testObject1;

    testObject1 =等待privateMethod2Async();

    返回testObject1;
}
 

也许可以变成:

 返回Task.WhenAny(privateMethod1Async(),privateMethod2Async());
 

鉴于其中的一种方法是适用作为返回类型

编辑:

  

什么是拇指添加异步/计谋的一般规则的规则?是   它,做其他处理它的方法?其中,作为你点   出,这种方法不?

您可能需要使用等待当你想要对返回工作在做更多的处理。如果你想要的是返回实际工作,也没有必要等待它,你可以简单地返回炎热的任务。这是一般规则我使用。另外还要注意,当您使用异常处理是不同的返回待机 VS只需返回

您可以了解更多关于在<一个href="http://stackoverflow.com/questions/17886992/at-the-end-of-an-async-method-should-i-return-or-await">At异步方法结束后,我要退货或等待?和<一href="http://stackoverflow.com/questions/21033150/any-difference-between-await-task-run-return-and-return-task-run">Any间和QUOT差异;等待Task.Run();返回;&QUOT;和&QUOT;返回Task.Run()&QUOT;?

Using VS2013, EF6.1.1, MVC5, .net 4.5.

I have just started looking into async/await for the first time and I am not sure if this is doing it properly. It appears to work, but could it be simpler? I seem to be sticking async/await in a lot of places for one method call down multiple layers.

All code has been simplified for brevity.

In my MVC controller action method I have:

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

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

    return RedirectToAction("TestAction2");
}

My service class is as follows:

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();
    }
}

And my repository method:

public async Task<TEntity> FirstOrDefaultAsync()
{
    return await _entitySet.FirstOrDefaultAsync();
}

Basically, I have a controller method, that calls a service method. The service method is to call the database layer twice, in an async fashion. But I feel that I am changing every single method and layer to deal with async and I wasn't sure if what I have here is correct.

Secondly, in the controller method I am unsure how to call the unit of work commit method asynchronously. The line that has "_unitOfWork.CommitAsync();". I cannot stick an "await" before it as it is a void method.

Any thoughts?


EDIT 1

Here is the full version of the repository method call to 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);
}

解决方案

I see a reoccurring pattern in your code:

private async Task<TestObject> privateMethod2Async()
{
    return await _testRepository.FirstOrDefaultAsync();
}

When you have a single-liner which simply queries your DB for a Task<T>, you can avoid the state-machine allocation which await causes, and simply return the hot task to the caller (as he'll probably await on it anyway higher up the call-chain):

private Task<TestObject> privateMethod2Async()
{
    return _testRepository.FirstOrDefaultAsync();
}

Note that async-await will make you go "async all the way", that's the nature of async. Make sure that you group tasks that can run concurrently using Task.WhenAll if possible, for example (not sure this might be the best example):

public async Task<TestObject> TestMethod1()
{
    var testObject1 = await privateMethod1Async();
    if (testObject1 != null) return testObject1;

    testObject1 = await privateMethod2Async();

    return testObject1;
}

Might be able to turn into:

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

given that one of the methods is applicable as a return type.

Edit:

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?

You would want to use await when you'd want to be doing more processing on the returned Task. If all you want is to return the actual Task, there is no need to await it, you can simply return the hot task. That's the general rule i use. Also note that exception handling is different when you use return await vs simply return.

You can read more on that in At the end of an async method, should I return or await? and Any difference between "await Task.Run(); return;" and "return Task.Run()"?

这篇关于这是异步的正确用法/等待在MVC与服务中心/存储库层?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆