在c#中用BeginExecuteReader设计一个异步数据提供程序

本文关键字:异步 一个 数据 程序 中用 BeginExecuteReader | 更新日期: 2023-09-27 18:04:12

我是c# 5中async/await模型的新手,所以您必须耐心等待我的无知/缺乏理解。

我想升级我的Singleton设计的数据提供程序,以执行异步调用存储过程,然后使用系统中的BeginDataReader和EndDataReader方法返回数据。数据名称空间。

下面是一个结构的例子,我试图建立,但它不是等待数据返回:

public class DataProvider{
    private static DataProvider instance;
    public static DataProvider Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (typeof(DataProvider))
                    {
                        instance = new DataProvider();
                    }
                }
                return instance;
            }
        }
    public virtual async void ExecuteDataReaderAsync(string StoredProcedureName, AsyncCallback callback, params object[] Parameters)
        {
            InitDatabase();
            var connection = new SqlConnection(databaseControllers[connectionStringName].ConnectionString);
            var cmd = new SqlCommand();
            cmd.Connection = connection;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = dbPrefixName + StoredProcedureName;
            await connection.OpenAsync();
            SqlCommandBuilder.DeriveParameters(cmd);
            if (cmd.Parameters.Count - 1 > Parameters.Count())
                throw new InvalidOperationException("The number of parameters provided does not match the number of parameters in the stored procedure. There are " + Parameters.Count().ToString() + " parameters provided, however the stored procedure requires " + cmd.Parameters.Count.ToString() + " parameters.");
            for (int i = 0; i < Parameters.Count(); i++)
            {
                cmd.Parameters[i + 1].Value = Parameters[i];
            }
            cmd.BeginExecuteReader(new AsyncCallback(callback), cmd);
        }
}
public class SubDataProvider : DataProvider
{
    private static volatile SubDataProvider instance = new SubDataProvider();
        public static SubDataProvider Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (typeof(SubDataProvider))
                    {
                        if (instance == null)
                            instance = new SubDataProvider();
                    }
                }
                return instance;
            }
        }
    ////
    //// THIS IS WHERE I GET LOST
    ////
        public async Task<List<Models.MyData>> GetDataAsync(bool IncludeDeleted = false)
        {
            List<Models.MyData> temp = new List<MyData>();
            ExecuteDataReaderAsync("GetData", delegate (IAsyncResult result)
            {
                var database = (SqlCommand)result.AsyncState;
                using (IDataReader reader = database.EndExecuteReader(result))
                {
                    while (reader.Read())
                    {
                        temp.Add(FillData(reader));
                    }
                }
                if (database.Connection.State == ConnectionState.Open)
                    database.Connection.Close();
            }, false);
            return temp;
        }
}

public class BusinessController
{
        private static volatile  BusinessController _instance = new BusinessController();
        public static BusinessController Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (typeof (BusinessController))
                    {
                        _instance = new BusinessController();
                    }
                }
                return _instance;
            }
        }
        public async Task<List<Models.MyData>> GetAllAsync(bool IncludeDeleted = false)
        {
            return await SubDataProvider.Instance.GetDataAsync(IncludeDeleted);;
        }
}

// DEMO
internal class Program
{
        private static void Main(string[] args)
        {
            var x = BusinessController.Instance.GetAllAsync(false);
        }
}

我的最终目标是将这些数据返回到异步WebApi,但我目前无法获得任何数据。temp变量被填充,但它从未真正返回填充过的对象。

我哪里错了?

提前谢谢你!

在c#中用BeginExecuteReader设计一个异步数据提供程序

我这里没有你确切的代码库,但像这样的东西会接近你需要的:

DataProvider类中,我将ExecuteDataReaderAsync重命名为GetDataReaderAsync

public virtual async Task<IDataReader> GetReaderAsync(string StoredProcedureName, params object[] Parameters)
{
    InitDatabase();
    var connection = new SqlConnection(databaseControllers[connectionStringName].ConnectionString);
    var cmd = new SqlCommand
    {
        Connection = connection,
        CommandType = CommandType.StoredProcedure,
        CommandText = dbPrefixName + StoredProcedureName
    };
    await connection.OpenAsync();
    SqlCommandBuilder.DeriveParameters(cmd);
    if (cmd.Parameters.Count - 1 > Parameters.Count())
        throw new InvalidOperationException("The number of parameters provided does not match the number of parameters in the stored procedure. There are " + Parameters.Count().ToString() + " parameters provided, however the stored procedure requires " + cmd.Parameters.Count.ToString() + " parameters.");
    for (int i = 0; i < Parameters.Count(); i++)
    {
        cmd.Parameters[i + 1].Value = Parameters[i];
    }
    var reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection);
    return reader;
}

SubDataProvider类中使用GetDataAsync读卡器

public async Task<List<MyData>> GetDataAsync(bool IncludeDeleted = false)
{
    List<MyData> temp = new List<MyData>();
    using (var reader = await GetReaderAsync("GetData"))
    {
        while (reader.Read())
        {
            temp.Add(FillData(reader));
        }
    }
    return temp;
}

我不能用我在这里的东西测试解决方案,但是如果你选择返回SqlDataReader而不是IDataReader,你也会有一个ReadAsync()方法可供你使用。但是既然现在已经有了async方法,那么使用reader.Read()就可以了。我放弃了回调,因为在这里使用任务-异步范式会更好。

希望这对你有帮助。:)

更新

来自@Scott Chamberlain的评论,另一个建议是将读者保持在DbDataReader级别而不是IDataReader级别,这样您仍然可以通用并访问ReadAsync()等方法。这个建议被认为是值得的,因此在这里添加了答案。