在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变量被填充,但它从未真正返回填充过的对象。
我哪里错了?
提前谢谢你!
我这里没有你确切的代码库,但像这样的东西会接近你需要的:
在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()
等方法。这个建议被认为是值得的,因此在这里添加了答案。