web-dev-qa-db-ja.com

非同期Task <IActionResult>を使用するにはどうすればよいですか?または私のAsp.Net Core Web APIで非同期に実行する方法

コントローラアクションを非同期で実行しようとしています。非同期タスクを使用するにはどうすればよいですか?または非同期に実行する方法

// 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);

//そして私のリポジトリクラス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);


    }

コントローラを非同期に取得するにはどうすればよいですか。待機する場所とToListAsync()がわからない。前もって感謝します!

4
Helen Tekie

意図をよりよく示すために、インターフェースの名前を変更する必要があります。

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);
}
0
Nkosi

あなたのコードから私が言うことができないことは、GetDepartmentsが返すもののデータ型です。私の推測では、EF Coreを使用していて、GetDepartmentsはDbSetまたはDbSetに対するLINQクエリを返します。その場合、depEntities変数が設定されている行の後、その変数は据え置きオブジェクト(まだ評価されていない式ツリー)を指します。つまり、実際のクエリはまだデータベースに送信されていません。 (foreachループを使用して)depEntitiesをループすると、実際に長時間かかる可能性のある作業が発生します(データベースアクセス)。それがあなたが待ち望んでいることです。したがって、はい、GetDepartmentsの非同期バージョンを作成することも、コードを次のように変更することもできます。

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

ToListAsyncの呼び出しにより、遅延オブジェクトが列挙され、データベースアクセスが実行されます。 returnステートメントは結果を返すだけです。舞台裏では、メソッドは実際にはawaitステートメントで戻り、待機している作業が完了すると再開します。

最後に、データベースの例外は、遅延オブジェクトが列挙された時点で発生します。

1
Jason

準備済みのawaitリストに対してresultsを実行しないでください。すでに必要なデータが含まれています-何を待ちますか?

GetDepartments()メソッドの新しい非同期バージョンを作成し、リポジトリからデータを取得するまで待つ必要があります。

var depEntities = await _depRepository.GetDepartmentsAsync();
0
Dmitry