【问题标题】:How do I use async Task<IActionResult> ? Or How to run in async way in my Asp.Net Core Web Api如何使用异步 Task<IActionResult> ?或者如何在我的 Asp.Net Core Web Api 中以异步方式运行
【发布时间】:2017-07-01 20:26:33
【问题描述】:

我正在尝试以异步方式运行我的控制器操作。 如何使用异步任务?或者如何以异步方式运行

// Db context
public class DeptContext : DbContext
{
    public LagerContext(DbContextOptions<LagerContext> options)
        : base(options)
    {

        Database.Migrate();
    }

    public DbSet<Department> Departments { get; set; }
    public DbSet<Product> Products { get; set; }


}

// 这是我的接口 IDepRepository

Task<Department> GetDepartmentWithOrWithoutProducts(int deptId, bool includeProducts);

//还有我的Repository类DepRepository

public class DepRepository : IDepRepository
{
   private DeptContext db;
    public DepRepository(DeptContext context)
    {
        db = context;
    }

    // I'am geting Department name with products or Without products

    public async Task<Department> GetDepartmentWithOrWithoutProducts(int deptId, bool includeProducts)
     {
       if(includeProductss)
        {
          return await db.Departments.Include(c => c.Products).Where(s => s.deptId == deptId).SingleAsync();
        }
                return await db.Departments.Where(s => s.deptId == deptId).SingleAsync();
    }
}

那么我现在应该如何在我的控制器中以异步方式进行操作:我尝试如下但我不知道这样做是否正确: 我没有收到任何错误,但如果它是正确的方式我不会...

using System.Threading.Tasks;
using System.Net;
using Microsoft.Data.Entity;
using Microsoft.EntityFrameworkCore;

[Route("api/departments")]
public class DepartmentsController : Controller
{
    private IDeptRepository _deptInfoRepository;

    public DepartmentsController(IDeptRepository deptInfoRepository)
    {
        _deptInfoRepository = deptInfoRepository;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetDepatment(int id, bool includeProducts = false)
    {
        var dept = _deptInfoRepository.GetDepartmentWithOrWithoutProducts(id, includeComputers);
        if(dept == null)
        {
            return BadRequest();
        }

        if(includeProducts)
        {
            var depResult =  new DepartmentDto() { deptId = dept.deptId, deptName = dept.deptName };
            foreach(var department in dept.Products)
            {
                depResult.Products.Add(new ProductDto() { productId = department.productId, deptId = department.deptId, ProductName =                     department.ProductName });
            } 

            return Ok(depResult);
        }

        var departmentWithoutProductResult = new DepartmentsWithoutProductsDto() { DeptId = dept.deptId, DeptName = dept.DeptName};
        return Ok(departmentWithoutProductResult);


    }

如何以异步方式获取我的控制器.. 我不知道将这些 await 和 ToListAsync() 放在哪里。提前谢谢!

【问题讨论】:

  • ToListAsync 作为IQueryable 扩展存在,而不是IEnumerable 扩展。而且 List 没有实现IQueryable。你有GetDepartments 的异步版本吗?如果是这样,你可以等待那个电话。
  • @R.Richards 感谢您的回复。你的意思是如果我的 GetDepartments 中有 async 和 await 就足够了吗?
  • 并非如此。您需要的是 GetDepartments 的异步版本。这里的答案暗示了这一点。 GetDepartmentsAsync 将返回 GetDepartments 现在返回的任何内容的 Task。这是必需的,因为如果没有基于任务的功能,您将无法有效地使用 async/await。 See this.
  • @R.Richards 再次感谢您,现在我已经更新了类似的详细代码,请您检查我的完整代码吗?

标签: c# asp.net-core asp.net-core-webapi


【解决方案1】:

应该重命名界面以更好地显示意图。

public interface IDepRepository {
    Task<Department> GetDepartmentWithOrWithoutProductsAsync(int deptId, bool includeProducts);
    //...
}

这将相应地更新实现。由于该方法在异步调用之后实际上并没有使用任何东西,因此没有任何理由将该方法标记为异步。只需返回任务。

public Task<Department> GetDepartmentWithOrWithoutProductsAsync(int deptId, bool includeProducts) {
    if(includeProductss) {
        return db.Departments.Include(c => c.Products).Where(s => s.deptId == deptId).SingleAsync();
    }
    return db.Departments.Where(s => s.deptId == deptId).SingleAsync();
}

但是,控制器操作需要等待任务,然后在任务完成后继续,因此该方法将被标记为异步。

[HttpGet("{id}")]
public async Task<IActionResult> GetDepatment(int id, bool includeProducts = false) {
    var dept = await _deptInfoRepository.GetDepartmentWithOrWithoutProductsAsync(id, includeComputers);
    if (dept == null) {
        return BadRequest();
    }
    if (includeProducts) {
        var depResult =  new DepartmentDto() { deptId = dept.deptId, deptName = dept.deptName };
        foreach (var department in dept.Products) {
            depResult.Products.Add(new ProductDto() { 
                productId = department.productId, 
                deptId = department.deptId, 
                ProductName = department.ProductName 
            });
        } 
        return Ok(depResult);
    }
    var departmentWithoutProductResult = new DepartmentsWithoutProductsDto() { DeptId = dept.deptId, DeptName = dept.DeptName};
    return Ok(departmentWithoutProductResult);
}

【讨论】:

    【解决方案2】:

    我无法从您的代码中看出 GetDepartments 返回的数据类型。我的猜测是您使用的是 EF Core,而 GetDepartments 返回一个 DbSet 或针对 DbSet 的 LINQ 查询。如果是这种情况,那么在设置 depEntities 变量的行之后,该变量指向一个延迟对象(尚未评估的表达式树)。或者换句话说,实际的查询还没有发送到数据库。当您遍历 depEntities(使用您的 foreach 循环)时,您正在导致实际可能长时间运行的工作发生(数据库访问)。这就是你想要等待的。所以,是的,您可以制作 GetDepartments 的异步版本,或者您也可以将代码更改为:

    var depEntities = await _depRepository.GetDepartments().ToListAsync();
    

    对 ToListAsync 的调用将枚举延迟对象并执行数据库访问。您的 return 语句只会返回结果。在幕后,该方法实际上在您的 await 语句上返回,并在您等待的工作完成后恢复。

    最后一点.. 任何数据库异常都将在枚举延迟对象时发生。

    【讨论】:

    • 感谢您的回复。现在我已经更新了类似的详细代码,请您检查我的完整代码吗?
    【解决方案3】:

    你不应该在已经准备好的results 列表上做任何await。它已经包含所需的数据 - 您还想等什么?

    您应该创建 GetDepartments() 方法的新异步版本并在从存储库获取数据时等待:

    var depEntities = await _depRepository.GetDepartmentsAsync();
    

    【讨论】:

    • 感谢您的回复。现在我已经更新了类似的详细代码,请您检查我的完整代码吗?
    • 现在您应该在 var dept = await _deptInfoRepository.GetDepartmentWithOrWithout... 中等待,否则您的代码将无法编译/工作(deptTask,而不是 Department)。并在方法名称中添加Async 后缀(如果可能)以明确它是异步的。
    猜你喜欢
    • 2011-07-02
    • 2015-06-04
    相关资源
    最近更新 更多