2015-12-02 33 views
0

相对较新的WebAPI和异步所以请容忍我所说的“正常”的静态方法....我可以从一个异步API控制方法

我有一些在其操作的应用程序的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(); 
    }    
} 
+4

为什么你认为在另一个线程上运行该方法并等待结果比同步运行更“高效且健壮”?想象一下,我克隆了你并要求你做一些事情。为什么要让克隆人完成任务并等待它完成比只是自己完成任务更好? –

+0

@Daniel Kelley说得很好。 AntDC,异步编程有开销,应该根据需要使用,而不仅仅是使用它。在这种情况下,因为你在这里所做的只是运行一个存储过程,所以没有必要。如果这是一个长期运行的程序,我会从那里开始,并考虑让它更有效率。我也不建议在静态类中有任何保持状态的数据库连接。 –

+0

我没有明说我们这个相对较新的给我.... 我想不会阻塞线程作为我的API可能有大量的并发请求的.... 无论如何,所以怎么样,如果我不得不从我的API调用外部API。 异步操作会更适用吗? 此外,dbConnString是我的BaseController类的一个属性,我将它传递给我的静态方法。 – AntDC

回答

1

var Result = await Task.Run(()=> MyStaticHelper.A_Static_Method(db,b));

通行证的工作到一个新的线程。释放旧线程。在新线程中等待结果。现在一个线程可以继续在这里停止。

如果你同时运行几个这样的任务,但是你花精力由具有螺纹,以减轻线程做的东西,这非常有用。这是所有成本和收益。

哪里异步胜是:

  1. 您在同一时间有一个以上的异步操作。
  2. 您有一个使用异步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); 
    } 
} 

有两点需要注意:

  1. 我换成你的try…finally使用SqlDataReader有一个比较正常的周围using
  2. 推测StaticFunctionToGetInstanceOfClassFromResults呼吁的DataReader 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); 
    } 
} 

它真正从异步行为的好处。

+0

谢谢乔恩。 你已经改变了我对此的理解。 顺便说一句 - 我的捕获不是最优雅的,但在这种情况下做的工作。发回响应代码为“API错误”的对象。 谢谢收获。 – AntDC

+0

我强烈地考虑看看我是否可以将它变成捕获异常的东西,并且如果我是你的话,它会更接近API表面返回“API错误”响应。 –

1

没有,做法是错误的。一般来说,你应该避免在ASP.NET上使用Task.Run(以及任何其他的队列工作到线程池的方法)。

而不是从控制程序启动和“下”的工作,你应该开始在最低水平和工作。也就是说,首先检查你的静态方法,并确定是否有任何自然异步操作。这些通常是I/O。两跳立即跳出来给我:opening the database connectionretrieving results from a query(很可能StaticFunctionToGetInstanceOfClassFromResults有更多)。你应该叫那些await第一,然后让async来对你的控制器自然生长(编译器会引导你)。

而且,@StephenBrickner评论,你可能要退后一步,并确定是否async会帮助你。我有一个article on async ASP.NET涵盖了主要考虑因素。特别是,如果您的后端不能扩展(例如,如果它是单个SQL服务器实例,而不是Azure SQL),那么通常无法扩展您的Web服务器。

+0

谢谢斯蒂芬, 是的 - 我已经采取了所有的答复,并在我真正需要异步时“加载我的枪”。 也就是说 - 当我有多个任务可以同时独立运行时运行。 作为一个自己的练习,我已经使我的一个简单的方法有一个异步选项,只是为了练习。 谢谢 – AntDC