[英]Can I call a 'normal' static method from an Async API Controller method
对WebAPI和Async来说相对较新,所以请耐心等待...。
我有一个WebAPI应用程序,其中包含许多操作。 从本质上讲,这些调用SQL Server存储过程。
它一直运行良好,但是我希望通过将方法转换为异步来使其更加有效和健壮。
让我展示一种方法-因为它们都是相似的...
[System.Web.Http.HttpGet]
public A_Class MyAPIMethod(Guid b)
{
using (SqlConnection DB = new SqlConnection(this.dbConnString))
{
return MyStaticHelper.A_Static_Method(DB, b);
}
}
[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();
}
}
不,这种方法是错误的。 通常,应避免在ASP.NET上使用Task.Run
(以及将工作排队到线程池的任何其他方法)。
而不是从控制器启动并“向下”工作,您应该从最低级别开始并进行升级 。 即,首先检查您的静态方法并确定是否存在任何自然异步操作。 这些通常是I / O。 我马上跳了两个: 打开数据库连接并从查询中检索结果 ( StaticFunctionToGetInstanceOfClassFromResults
可能还有更多)。 您应该先用await
调用它们,然后让async
自然地朝您的控制器增长(编译器将指导您)。
另外,正如@StephenBrickner所说,您可能想退后一步,确定async
是否会对您有所帮助。 我在async
ASP.NET上有一篇文章介绍了主要注意事项。 特别是,如果您的后端无法扩展(例如,如果它是单个SQL Server实例,而不是Azure SQL之类的东西),那么(通常)毫无意义地进行Web服务器扩展。
var结果=等待Task.Run(()=> MyStaticHelper.A_Static_Method(db,b));
将工作传递到新线程。 释放旧线程。 在新线程中等待结果。 现在,一个线程可以继续执行此操作。
如果您同时运行多个此类任务,这可能会很有用,但是您正在花精力通过让线程做事来减轻线程负担。 那都是成本,没有收益。
异步获胜的地方是:
第二点更重要,尤其是在网络方面。
让我们首先考虑您的“助手”方法。 其中的调用具有真正的异步等效项,因此我们可以创建一个真正的异步版本:
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);
}
}
两个注意事项:
using
代替了try…finally
的使用, try…finally
在SqlDataReader
周围。 StaticFunctionToGetInstanceOfClassFromResults
Read()
上调用Read()
,然后基于该对象构建一个对象。 您可以添加一个异步版本,该版本调用await ReadAsync()
,然后在此处使用var A_Class = await StaticFunctionToGetInstanceOfClassFromResultsAsync(reader)
以获得更好的异步行为。 现在我们有了一个异步方法,您的控制器可以是:
[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);
}
}
它确实得益于异步行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.