サービスレイヤーとして.NETコアWeb APIがあります。サービス層にはすべてのEFコードがあります。
このコードのベースコントローラーがある場合
protected Task<IActionResult> NewTask(Func<IActionResult> callback)
{
return Task.Factory.StartNew(() =>
{
try
{
return callback();
}
catch (Exception ex)
{
Logger.LogError(ex.ToString());
throw;
}
});
}
コントローラーアクションでは、上記のメソッドでサービスへのすべての呼び出しをラップします。 :
[HttpGet("something")]
public async Task<IActionResult> GetSomething(int somethingId)
{
return await NewTask(() =>
{
var result = _somethingService.GetSomething(somethingId);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
});
}
明日を考えると、これは正しいパターンですか?複数のサービス呼び出しが実行されているか、他のWebサービスを呼び出すことがありますお知らせ下さい。
私は私のAPIに非同期待機の恩恵を受けたいです。上記のパターンはこれらのニーズに応えます
いいえ、違います。スレッドプールで同期作業を実行すると、同期and非同期コードの欠点が得られますが、どちらもメリットはありません。
何かのサービスには、entityframeworkコアを使用するいくつかのcrud操作があります
現在、あなたのアクションメソッドは私が「偽の非同期」と呼んでいるものです-それは非同期に見えますが(例えば、await
を使用して)、実際にはバックグラウンドスレッドでブロッキングコードを実行しています。 ASP.NETでは、真の非同期が必要です。whcnは、常に非同期でなければならないことを意味します。 ASP.NETでこれが悪い理由の詳細については、ASP.NETのasync
の イントロの前半を参照してください (ほとんどASP.NETを扱っています)非コアですが、同期リクエストと非同期リクエストについての最初の部分は、あらゆる種類のサーバーに有効です)。
これを完全に非同期にするには、最低レベルで開始する必要があります-この場合、EFCoreを呼び出します。それらはすべて非同期をサポートします。したがって、x.FirstOrDefault()
のようなAPI呼び出しをawait x.FirstOrDefaultAsync()
に置き換えてください(すべての作成/更新/削除などでも同じです)。
次に、async
/await
がそこから自然に成長できるようにします。コンパイラーがガイドします。 somethingService
で非同期メソッドを使用すると、次のように使用できます。
[HttpGet("something")]
public async Task<IActionResult> GetSomething(int somethingId)
{
var result = await _somethingService.GetSomethingAsync(somethingId);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
}
さて、まず第一に、スレッドプールスレッドで実行したいCPUバウンドの重い作業がある場合にのみ、Task.Factory.StartNew
の使用を停止し、Task.Run
を使用する必要があります。あなたの場合、あなたは本当にそれをまったく必要としません。また、メソッドの実装ではなく、メソッドを呼び出すときにのみTask.Run
を使用する必要があることに注意してください。詳細については、こちらをご覧ください こちら 。
あなたが本当に必要なのは、実際にデータベースを呼び出してasync/awaitを使用したいときに、サービス内で非同期の作業をすることです(あなたのケースでサービスが必要かどうかは本当にわかりません)バックグラウンドスレッドで何かを実行するだけではありません。
基本的に、サービスは次のようになります(サービスが必要なことが確実な場合)。
class PeopleService
{
public async Task<Person> GetPersonByIdAsync(int id)
{
Person randomPerson = await DataContext.People.FirstOrDefaultAsync(x => x.Id == id);
return randomPerson;
}
}
ご覧のとおり、サービスがデータベースに対して非同期呼び出しを行うようになりました。これが基本的なパターンです。これをすべての操作(追加/削除/など)に適用できます。
サービスを非同期にすると、アクションでデータを簡単に消費できるようになります。
アクションは次のようになります。
[HttpGet("something")]
public async Task<IActionResult> GetPerson(int id)
{
var result = await PeopleService.GetPersonByIdAsync(id);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
}