簡體   English   中英

在webapi中使用async await的最佳實踐

[英]best practice for using async await in webapi

我有.NET核心Web API作為服務層。 服務層具有所有EF代碼。

如果有basecontroller與此代碼

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能夠從異步等待事物中獲益。以上模式將滿足這些需求

不,不是的。 在線程池上運行同步工作會給你帶來同步異步代碼的缺點,但兩者都沒有好處。

某些服務有一些使用entityframework核心的crud操作

目前,您的操作方法是我稱之為“假異步” - 它看起來是異步的(例如,使用await ),但實際上只是在后台線程上運行阻塞代碼。 在ASP.NET上,您需要真正的異步,這意味着您必須始終保持異步。 有關為何在ASP.NET上出現問題的更多信息,請參閱我在ASP.NET上的async介紹的前半部分(它主要處理ASP.NET非核心,但第一部分討論同步和異步請求是有效的對於任何類型的服務器)。

要使這真正異步,您應該從最低級別開始 - 在這種情況下,您的EFCore調用。 他們都支持異步。 因此,使用await x.FirstOrDefaultAsync()替換x.FirstOrDefault()等API調用x.FirstOrDefault()對於所有創建/更新/刪除等都是相同的)。

然后讓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");
}

好的,首先,你應該停止使用Task.Factory.StartNew並且只有當你想在線程池線程上運行大量的CPU工作時才使用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");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM