C# 我能打电话给';正常';来自异步API控制器方法的静态方法
WebAPI和Async相对较新,所以请耐心听我说 我有一个WebAPI应用程序,其中包含许多操作。本质上,这些调用SQL Server存储过程 它一直工作得很好,但我希望通过将方法转换为异步,使它更高效、更健壮 让我展示一种方法——因为它们都很相似 旧版本 新版本(异步我想&希望)C# 我能打电话给';正常';来自异步API控制器方法的静态方法,c#,asynchronous,asp.net-web-api,C#,Asynchronous,Asp.net Web Api,WebAPI和Async相对较新,所以请耐心听我说 我有一个WebAPI应用程序,其中包含许多操作。本质上,这些调用SQL Server存储过程 它一直工作得很好,但我希望通过将方法转换为异步,使它更高效、更健壮 让我展示一种方法——因为它们都很相似 旧版本 新版本(异步我想&希望) 不,这种方法是错误的。通常,您应该避免在ASP.NET上运行任务。运行(以及将工作队列排入线程池的任何其他方法) 不要从控制器开始“向下”工作,而应该从最低级别开始向上工作。也就是说,首先检查静态方法并确定是否存在
不,这种方法是错误的。通常,您应该避免在ASP.NET上运行
任务。运行(以及将工作队列排入线程池的任何其他方法)
不要从控制器开始“向下”工作,而应该从最低级别开始向上工作。也就是说,首先检查静态方法并确定是否存在任何自然异步操作。它们通常是I/O。两个会立即跳到我的面前:and(而且很可能staticfunctiontogetetinstanceofclassfromresults
还有更多)。你应该先用wait
调用那些,然后让async
自然地向你的控制器发展(编译器会指导你)
此外,正如@StephenBrickner所评论的,您可能需要后退一步,确定async
是否会对您有所帮助。我有一份报告,涵盖了主要考虑因素。特别是,如果您的后端无法扩展(例如,如果它是单个SQL server实例,而不是类似Azure SQL的实例),那么(通常)没有必要让您的web服务器进行扩展
var Result=wait Task.Run(()=>mystaticheper.A_Static_Method(db,b))
将工作传递给新线程。释放旧线程。等待新线程中的结果。现在,一根线可以在停止的地方继续
如果您同时运行多个这样的任务,这可能会很有用,但您需要花费精力让一个线程做一些事情来释放一个线程。这是全部成本,没有收益
其中,异步wins是:
您同时有多个异步操作
您有一个使用异步I/O的异步操作,以便完全释放调用线程
第二个更重要,尤其是在网络方面
我们先考虑一下你的“帮助者”方法。其中有些调用具有真正的异步等价物,因此我们可以创建真正的异步版本:
public static async Task<A_Class> AStaticMethodAsync(SqlConnection dbConn, Guid A_Param)
{
try
{
if (dbConn.State != ConnectionState.Closed) dbConn.Close();
using (var cmd = new SqlCommand("MyStoredProc", dbConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@sp_Param", SqlDbType.UniqueIdentifier).Value = A_PAram
await dbConn.OpenAsync();
using(SqlDataReader reader = await cmd.ExecuteReader())
{
var A_Class = StaticFunctionToGetInstanceOfClassFromResults( reader );
A_Class.rc = 1;
return A_Class
}
}
}
catch (Exception)
{
//server error
// Why are you wrapping an exception instead of just passing it up the stack? This is weird.
return new A_Class(A_ClassError.beApiError);
}
}
而且它确实受益于异步行为。为什么您认为在另一个线程上运行该方法并等待结果比同步运行更“高效和健壮”?想象一下,我克隆了你,让你做点什么。丹尼尔·凯利(Daniel Kelley)说得很好,为什么给克隆人任务并等待它完成比自己完成要好。异步编程有开销,应该根据需要使用,而不仅仅是为了使用它。在这种情况下,因为您在这里所做的只是运行一个存储过程,所以没有必要这样做。如果这是一个长期运行的程序,我会从那里开始,并研究如何使它更有效。我也不建议在静态类中使用任何保持状态的东西,比如数据库连接。。。。我在考虑不阻塞线程,因为我的API可能有很多并发请求。。。。不管怎样,如果我必须从我的API调用一个外部API呢。那么异步操作是否更适用?另外,dbConnString是我的BaseController类的一个属性,我将它传递给我的静态方法。我在考虑不阻塞线程,因为我的API可能会有很多并发请求。这当然是个好主意。问题是,因为你正在阻止另一个线程来实现这一点,所以你一无所获。谢谢Jon。你提高了我对这件事的理解。顺便说一句,我的捕获不是最优雅的,但在这种情况下,它起到了作用。发送回响应代码为“API错误”的对象。谢谢。我强烈地考虑看看我是否能把它变成一个捕捉异常的东西,如果我是你,就返回API界面上的“API错误”响应。谢谢史蒂芬,是的,我已经把所有回复都写在了板上,并且在我真正需要ASYNC的时候“加载了我的枪”。Ie-当我有多个任务要运行时,可以同时独立运行。作为我自己的练习,我让我的一个更简单的方法有一个异步选项,只是为了练习。谢谢
[System.Web.Http.HttpGet]
public async Task<A_Class> MyAPIMethodAsync(Guid b)
{
var db = new SqlConnection(this.dbConnString);
try
{
var Result = await Task.Run(() => MyStaticHelper.A_Static_Method(db, b));
return Result;
}
finally
{
db.Dispose();
}
}
public static A_Class A_Static_Method(SqlConnection dbConn, Guid A_Param)
{
SqlDataReader reader = null;
try
{
try
{
if (dbConn.State != ConnectionState.Closed) dbConn.Close();
using (var cmd = new SqlCommand("MyStoredProc", dbConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@sp_Param", SqlDbType.UniqueIdentifier).Value = A_PAram
dbConn.Open();
reader = cmd.ExecuteReader();
var A_Class = StaticFunctionToGetInstanceOfClassFromResults( reader );
A_Class.rc = 1;
return A_Class
}
}
catch (Exception)
{
//server error
return new A_Class(A_ClassError.beApiError);
}
}
finally
{
if (reader != null) reader.Close();
dbConn.Close();
}
}
public static async Task<A_Class> AStaticMethodAsync(SqlConnection dbConn, Guid A_Param)
{
try
{
if (dbConn.State != ConnectionState.Closed) dbConn.Close();
using (var cmd = new SqlCommand("MyStoredProc", dbConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@sp_Param", SqlDbType.UniqueIdentifier).Value = A_PAram
await dbConn.OpenAsync();
using(SqlDataReader reader = await cmd.ExecuteReader())
{
var A_Class = StaticFunctionToGetInstanceOfClassFromResults( reader );
A_Class.rc = 1;
return A_Class
}
}
}
catch (Exception)
{
//server error
// Why are you wrapping an exception instead of just passing it up the stack? This is weird.
return new A_Class(A_ClassError.beApiError);
}
}
[System.Web.Http.HttpGet]
public async Task<A_Class> MyAPIMethodAsync(Guid b)
{
using (SqlConnection DB = new SqlConnection(this.dbConnString))
{
return await MyStaticHelper.AStaticMethodAsync(DB, b);
}
}