Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在webapi中使用异步等待的最佳实践_C#_Asp.net Web Api_Asp.net Core_Async Await - Fatal编程技术网

C# 在webapi中使用异步等待的最佳实践

C# 在webapi中使用异步等待的最佳实践,c#,asp.net-web-api,asp.net-core,async-await,C#,Asp.net Web Api,Asp.net Core,Async Await,我有.NET核心Web API作为服务层。服务层具有所有EF代码 如果您有此代码的basecontroller protected Task<IActionResult> NewTask(Func<IActionResult> callback) { return Task.Factory.StartNew(() => { try { return callback(); }

我有.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;
        }
    });
}
受保护的任务NewTask(Func回调)
{
返回Task.Factory.StartNew(()=>
{
尝试
{
返回回调();
}
捕获(例外情况除外)
{
Logger.LogError(例如ToString());
投掷;
}
});
}
在控制器操作中,我用上述方法包装所有服务调用,例如:

[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");
    });
}
[HttpGet(“某物”)]
公共异步任务GetSomething(int-somethingId)
{
返回等待新任务(()=>
{
var result=\u somethingService.GetSomething(somethingId);
如果(结果!=null)
返回Ok(结果);
其他的
返回NotFound(“未找到角色”);
});
}
考虑到明天我可能会有多个服务调用在运行或调用其他Web服务,这是正确的模式吗。请告知

我希望我的api能从异步等待中获益。上述模式是否能满足这些需求

不,没有。在线程池上运行同步工作会带来同步代码和异步代码的缺点,两者都没有好处


something服务具有一些使用entityframework核心的crud操作

目前,您的操作方法是我所说的“伪异步”——它看起来是异步的(例如,使用
wait
),但实际上只是在后台线程上运行阻塞代码。在ASP.NET上,您需要真正的异步,这意味着您必须始终保持异步。有关为什么这在ASP.NET上不好的更多信息,请参阅我的上半部分(它主要涉及ASP.NET非核心,但第一部分讨论的同步与异步请求适用于任何类型的服务器)

为了实现真正的异步,您应该从最低级别开始—在本例中,您的EFCore调用。它们都支持异步。因此,将像
x.FirstOrDefault()
这样的API调用替换为
wait x.FirstOrDefaultAsync()
(对于所有的创建/更新/删除操作都是如此)

然后让
async
/
等待
从那里自然增长;编译器将指导您。您将在
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");
}
[HttpGet(“某物”)]
公共异步任务GetSomething(int-somethingId)
{
var result=await\u somethingService.getsomethingsync(somethingId);
如果(结果!=null)
返回Ok(结果);
其他的
返回NotFound(“未找到角色”);
}

好的,首先,您应该停止使用
Task.Factory.StartNew
并使用
Task.Run
仅当您有大量CPU限制的工作要在线程池线程上运行时才使用。在你的情况下,你根本不需要。另外,您应该记住,在调用方法时,只应使用
Task.Run
,而不应在方法的实现中使用。你可以阅读更多关于这方面的内容

在您的案例中,您真正想要的是在您的服务中使用异步工作(我不确定您的案例中是否需要一个服务),而您实际上是在调用数据库,并且希望使用async/Wait,而不仅仅是在后台线程上运行一些东西

基本上,您的服务应该是这样的(如果您确定需要服务):

class PeopleService
{
公共异步任务GetPersonByIdAsync(int id)
{
Person randomPerson=wait DataContext.People.FirstOrDefaultAsync(x=>x.Id==Id);
返回人员;
}
}
正如您所看到的,您的服务现在对数据库进行异步调用,这基本上就是您的模式应该是什么。您可以将其应用于所有操作(添加/删除/等…)

在使服务异步之后,您应该能够轻松地使用操作中的数据

您的操作应该如下所示:

[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");
}
[HttpGet(“某物”)]
公共异步任务GetPerson(int-id)
{
var result=await PeopleService.GetPersonByIdAsync(id);
如果(结果!=null)
返回Ok(结果);
其他的
返回NotFound(“未找到角色”);
}

您能否提供更多信息,说明您在这里要完成的工作?您的代码现在基本上通过在后台线程上执行同步工作来伪造异步工作。更不用说使用Task.Factory.StartNew是非常危险的,您应该使用Task.Run,但您甚至不需要Task.Run here.something服务有一些使用entityframework core的crud操作。明天我可能会有一个名为feedService的服务,它将调用httpclient从外部web获取提要。我希望我的api能从异步等待中受益。上述模式是否能满足这些需求+任何关注点或改进?我对ef核心异步方法做了一些研究,据说它们比同步ef方法慢。。请告知。@kirshna异步方法速度较慢。当同步运行它们时,它们的开销是不可避免的。但它们可以提高吞吐量。因此,在吞吐量和性能之间有一个平衡点,这是您应该考虑的。性能问题总是如此,它是复杂的。听一听,你就会明白我在说什么。ef核心异步调用比同步调用慢,请告知。@user1603828:差异应该可以忽略不计。如果这不是你看到的,我建议联系EF团队。我浏览你的博客有很多有趣的信息。EF 6在异步调用和同步调用之间的差异可以忽略不计,但是EF Core中异步调用和同步调用之间的差异相当大。我相信他们会在不久的将来解决这个问题,但我的建议是考虑一下你是否真的关心性能,并与异步电话联系。您可以看到一些关于异步调用和同步调用之间的差异有多大的测试
[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");
}