Серверная сторона AsyncPattern для вызова SQL Server - PullRequest
2 голосов
/ 04 апреля 2011

Я пытаюсь реализовать 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

Ответы [ 2 ]

1 голос
/ 04 апреля 2011

Сегодня WCF Data Services не поддерживает асинхронную обработку на сервере. Пожалуйста, проголосуйте / добавьте запрос функции здесь: http://data.uservoice.com/forums/72027-wcf-data-services-feature-suggestions/topics/72603-wcf-data-services-feature-suggestions

1 голос
/ 04 апреля 2011

Если вы используете C # 4.0.Это может быть проще, используя Task<T> для достижения.Task<T> - выполнить Func<T>, где T - возвращаемое значение.Вы можете определить задачу продолжения, которая выбирает Parent.Result.Я знаю, что этот ответ может быть не тем, что вы ищете.Но, пожалуйста, рассмотрите это как альтернативу.Код будет чище, проще в обслуживании и отладке (с помощью параллельного окна задач, параллельных стеков и т. Д.).

...