首页 > 解决方案 > 如何在 ASP.NET CORE 上将同步结构转换为异步

问题描述

我有一个类的树层来从数据库中获取数据并在一个动作中提供它。SqlParameter我使用类从数据库旧方式获取数据。

我需要/想要将此方法重构为异步方法。我真正想要的是学习如何将这些同步方法变为异步。并让它们在不同的线程中工作,并在整个应用程序中使用它们。

我不想做的是使用 Ado.Net 或使用现成的方法,如HttpClient.GetAsync

我读到了这个问题:Calling async methods from non-async code but could not apply to my structure and cannot be sure it is working normal, Avoids deadlocks。

我的旧结构是这样的:

我在我的行动BlockController

public ActionResult Index()
{
    return View(new BlockDb().Select());
}

课堂上的Select方法BlockDb

    public List<Block> Select()
        {
            SqlDataReader dr = DbJobs.ExecuteReader("BlockSelect");
            List<Block> list = new List<Block>();
            Block cs;
            while (dr.Read())
            {
                cs = new Block();
                cs.ID = Convert.ToInt32(dr["ID"]);
                cs.Name= Convert.ToString(dr["Name"]);
                cs.Dt = Convert.ToDateTime(dr["Dt"]);
                cs.Ok = Convert.ToBoolean(dr["Ok"]);
                list.Add(cs);
            }

            dr.Close();
            dr.Dispose();
            return list;
        }

静态类中的最后一个ExecuteReader方法:DbJobs

    public static SqlDataReader ExecuteReader(string ProcName, params SqlParameter[] prmtr)
    {
        SqlDataReader Result = null;
        SqlConnection connect = new SqlConnection(cnn);
        try
        {
            SqlCommand command = new SqlCommand(ProcName, connect);
            command.CommandType = CommandType.StoredProcedure;

            foreach (SqlParameter item in prmtr)
                command.Parameters.Add(item);

            if (connect.State == ConnectionState.Closed)
                connect.Open();

            Result = command.ExecuteReader(CommandBehavior.CloseConnection);
            //connect.Close();
            //connect.Dispose();
        }
        catch { }

        return Result;
    }

我不能确定一个动作的结果可能是这样的:

public async Task<ActionResult> Index()
{
    return View(await new BlockDb().SelectAsync());
}

我怎样才能做到这一点?

标签: multithreadingasynchronousasp.net-coreasync-awaittask

解决方案


要将代码转换为异步,最好从最低级别开始,然后逐步向上。因此,从 开始DbJobs,将每个方法更改为其异步等效方法和await结果:

public static SqlDataReader ExecuteReader(string ProcName, params SqlParameter[] prmtr)
{
  SqlDataReader Result = null;
  SqlConnection connect = new SqlConnection(cnn);
  try
  {
    SqlCommand command = new SqlCommand(ProcName, connect);
    command.CommandType = CommandType.StoredProcedure;

    foreach (SqlParameter item in prmtr)
      command.Parameters.Add(item);

    if (connect.State == ConnectionState.Closed)
      await connect.OpenAsync(CancellationToken.None);

    Result = await command.ExecuteReaderAsync(CommandBehavior.CloseConnection);
  }
  catch { }

  return Result;
}

这会给你一个编译器错误,告诉你改变你的DbJobs.ExecuteReader签名。所以,如果你按照编译器错误告诉你的去做,你最终会得到:

public static async Task<SqlDataReader> ExecuteReaderAsync(string ProcName, params SqlParameter[] prmtr)

现在,您将得到所有调用 . 的旧代码的编译器错误DbJobs.ExecuteReader,例如BlockDb.Select. 因此,也将它们更改为使用异步方法:

public List<Block> Select()
{
  SqlDataReader dr = await DbJobs.ExecuteReaderAsync("BlockSelect");
  List<Block> list = new List<Block>();
  Block cs;
  while (await dr.ReadAsync(CancellationToken.None))
  {
    cs = new Block();
    cs.ID = Convert.ToInt32(dr["ID"]);
    cs.Name= Convert.ToString(dr["Name"]);
    cs.Dt = Convert.ToDateTime(dr["Dt"]);
    cs.Ok = Convert.ToBoolean(dr["Ok"]);
    list.Add(cs);
  }

  dr.Close();
  dr.Dispose();
  return list;
}

同样,您将收到一个编译器错误,告诉您如何更改BlockDb.Select

public async Task<List<Block>> SelectAsync()

最后,您将对Index:

public async Task<ActionResult> Index()
{
  return View(await new BlockDb().SelectAsync());
}

推荐阅读