Я пытаюсь реализовать AsyncPattern в службе данных WCF.Я определяю 2 метода BeginGetExperiment (...) и EndGetExperiment (...) в интерфейсе и реализую методы, как показано ниже.
public class GmdProfileService : IGmdProfileService
{
IAsyncResult IGmdProfileService.BeginGetExperiments(AsyncCallback callback, object state)
{
//IAsyncResult res = Experiment.GetExperimentsAsync(callback, state, Properties.Settings.Default.gmdConnectionString);
//return res;
System.Data.SqlClient.SqlConnectionStringBuilder csb = new System.Data.SqlClient.SqlConnectionStringBuilder(Properties.Settings.Default.gmdConnectionString);
csb.AsynchronousProcessing = true;
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(csb.ConnectionString);
conn.Open();
System.Data.SqlClient.SqlCommand cmd = conn.CreateCommand();
cmd = conn.CreateCommand();
cmd.CommandText = "SELECT id, name, comment, date, doi FROM tf.TagList WITH(NOLOCK) WHERE proprietary=0;";
cmd.CommandType = System.Data.CommandType.Text;
return new SqlCommandAsyncResult(cmd, callback, state);
}
public List<Experiment> EndGetExperiments(IAsyncResult result)
{
List<Experiment> res = new List<Experiment>();
SqlCommandAsyncResult myresult = result as SqlCommandAsyncResult;
using (System.Data.SqlClient.SqlDataReader reader = myresult.cmd.EndExecuteReader(myresult.originalState as IAsyncResult))
{
try
{
while (reader.Read())
{
res.Add(new Experiment(reader));
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
// Closing the reader also closes the connection, because this reader was created using the CommandBehavior.CloseConnection value.
if (reader != null)
{
reader.Close();
}
}
}
return res;
}
BeginGetExperiment возвращает класс SqlCommandAsyncResult
, реализующий *Интерфейс 1005 * в дополнение к хранению ссылки на мой SqlCommand
для последующего доступа.
public class SqlCommandAsyncResult : IAsyncResult
{
public SqlCommand cmd { get; private set; }
public IAsyncResult originalState { get; private set; }
public SqlCommandAsyncResult(SqlCommand cmd, AsyncCallback callback, object state)
{
this.cmd = cmd;
this.originalState = cmd.BeginExecuteReader(callback,
state,
System.Data.CommandBehavior.SequentialAccess | // doesn't load whole column into memory
System.Data.CommandBehavior.CloseConnection // close connection immediately after read
);
}
public object AsyncState
{
get { return originalState.AsyncState; }
}
public WaitHandle AsyncWaitHandle
{
get { return originalState.AsyncWaitHandle; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return AsyncWaitHandle.WaitOne(0); }
}
}
Трудности, с которыми я сталкиваюсь, связаны с методом EndGetExperiments
.Я не знаю, как получить доступ к SqlCommand
для вызова EndExecuteReader(...)
.Обычно я бы использовал объект состояния в BeginExecutereader
для передачи команды.Но если я это сделаю, я получу исключение: «Состояние IAsyncResult должно быть аргументом состояния, передаваемым вашему вызову Begin».
Поэтому я пытаюсь использовать IAsyncResult для передачи SqlCommand вперед EndGetExperiments
.Здесь я не понимаю, что в EndGetExperiments
результат переменной имеет тип IAsyncResult
или тип SqlCommandAsyncResult
в зависимости от значения CompletedSynchronously
в классе SqlCommandAsyncResult
.Установка CompletedSynchronously = false
делает мой код неудачным, потому что я не могу получить доступ к SqlCommand, тогда как установка CompletedSynchronously = true
код работает как чудо, но у меня странное ощущение, что что-то может пойти не так под капотом.
Я ценюлюбая помощь, руководство и пример кода, как сделать этот код работающим и, что еще важнее, помочь мне разобраться в проблеме.
Большое спасибо.Jan