实现包含对数据库的阻塞调用的System.Web.Http.Filters.IAuthenticationFilter.AuthenticateAsync()

时间:2016-01-21 13:51:54

标签: asp.net asynchronous async-await

我已根据此Microsoft example实现了AuthenticateAsync。

根据示例,AuthenticateAsync()包含

IPrincipal principal = await AuthenticateAsync(userName, password, cancellationToken);

我已实现通过System.Data.SqlClient.SqlConnection(在I / O上阻塞)调用SQL Server数据库 - 这会导致警告

  

这种异步方法缺少'await'运算符,并且会同步运行。

docs表示AuthenticateAsync必须返回

  

执行身份验证的任务。

我考虑过

  • 忽略警告
    • 不知道微软为什么宣布IAuthenticationFilter.AuthenticateAsync async 。也许IIS想推迟执行?
  • 在Task.Run()中包装阻塞调用
    • 这会使IIS使用的昂贵线程数增加一倍吗?

应该我在做什么?

可以在AuthenticateAsync中阻止吗?

3 个答案:

答案 0 :(得分:2)

SqlConnection和相关类型支持异步操作,因此您应该使用它们。这样,您就不需要任何变通办法,也不会因阻塞而浪费线程。

如果由于某种原因,你真的不能

  

忽略警告

更好的选择是让方法非async并使用Task.FromResult()来创建您需要返回的Task。这摆脱了警告,也略微提高了效率。

  

在Task.Run()

中换行阻止调用      

这会使IIS使用的昂贵线程数增加一倍吗?

它不会使线程数加倍,await不会阻塞线程,只有你的同步IO会。但它确实会因调度,同步和上下文切换而导致一些开销,因此它并不理想。 Task.FromResult()将是更好的选择。

答案 1 :(得分:1)

我想说有两种方法可以解决这个问题。

第一种是忽略警告,如你自己所暗示的那样。这样做的唯一方法是使方法同步。这将导致IIS保持昂贵的I / O线程比它更长,但不会有其他不良影响。

第二种方法是使对数据库的调用异步并等待其结果。你没有提到你要连接的数据库,所以很难判断这是否容易。

如果可能,我会建议第二次实施。

答案 2 :(得分:1)

  

我已经实现了对数据库的调用(阻塞   I / O) - 导致警告

     

这种异步方法缺乏等待'运营商并将同步运行。

归结为AuthenticateAsync的实施。如果您在这里进行数据库调用,应该可以在您的实现中使用await运算符,假设您的Db提供程序支持它(许多包括Ado.NET for SqlClient,Entity Framework等)。在这种情况下,正确的实现就是这样做。这是解决方案,因为async / await框架可以将线程返回到线程池,直到数据库工作完成,此时代码恢复执行。这是在Web框架中运行的I / O调用的首选实现,因为线程随后被释放以提供其他传入请求,而不是被迫等待I / O完成并基本上阻塞。

编辑 根据您的上一次修改

因为您使用的是SqlClient,所以您可以在此处使用异步调用并等待它们。因此,正确的解决方案是更改AuthenticateAsync的实现,将async关键字保留在方法实现签名中,并将await数据库调用代码生成。