繁体   English   中英

我可以从Async API Controller方法调用“常规”静态方法吗?

[英]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));

将工作传递到新线程。 释放旧线程。 在新线程中等待结果。 现在,一个线程可以继续执行此操作。

如果您同时运行多个此类任务,这可能会很有用,但是您正在花精力通过让线程做事来减轻线程负担。 那都是成本,没有收益。

异步获胜的地方是:

  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. 我用更普通的using代替了try…finally的使用, try…finallySqlDataReader周围。
  2. 大概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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM