我是C#5中async / await模型的新手,所以你必须对我的无知/缺乏理解保持耐心。
我想升级我的Singleton设计数据提供程序以执行对存储过程的异步调用,然后使用System.Data命名空间中的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变量被填充但它实际上从未返回填充的对象。
我哪里错了?
提前非常感谢你!
答案 0 :(得分:2)
我没有确切的代码库,但这样的内容将与您的需求接近:
内部课程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;
}
并在GetDataAsync
内的SubDataProvider
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
,则您有{{1}你也可以使用方法。但是既然你现在已经有了异步方法,那么使用ReadAsync()
就可以了。我抛弃了回调,因为在这里继续使用Task-Asynchronous Paradigm会更好。
希望这会有所帮助。 :)
来自@Scott张伯伦的评论中,另一个建议是让读者保持reader.Read()
级而不是DbDataReader
,这样你仍然可以是通用的,并且可以访问像{{1}这样的方法}。这个建议被认为是值得的,因此在这里添加了答案。