Асинхронный WCF-запрос Последний шаг - PullRequest
0 голосов
/ 26 марта 2011

Я пытаюсь узнать, как реализовать асинхронный шаблон для одновременного запроса нескольких служб wcf, но не знаю, как проверить, что все одновременные вызовы завершены. У меня есть класс, который выполняет асинхронные операции, а затем добавляет в список по мере выполнения операций:

   public static class ODataAsync
    {
        static DataServiceContext ServiceContext;
        static List<DynamicEntity> Results = new List<DynamicEntity>(); 

        private static void GetAsync(string serviceUri, NameValueCollection queryOptions, IAuthenticationScheme authenticationScheme)
        {
            string baseUri;
            string entitySet;
            string entityKey;
            string queryString;
            ValidateServiceUri(serviceUri, out baseUri, out entitySet, out entityKey, out queryString);
            string resource = !string.IsNullOrEmpty(entityKey) ? entitySet + "(" + entityKey + ")" : entitySet;

            DataServiceContext context = new DataServiceContext(new Uri(baseUri));
            context.IgnoreMissingProperties = true;

            ServiceContext = context; 

            DataServiceContextHandler handler = new DataServiceContextHandler(authenticationScheme);
            handler.HandleGet(context);

            DataServiceQuery<EntryProxyObject> query = context.CreateQuery<EntryProxyObject>(resource);

            NameValueCollection options = HttpUtility.ParseQueryString(queryString);
            options.Add(queryOptions);

            foreach (string key in options.AllKeys)
            {
                query = query.AddQueryOption(key, options[key]);
            }

            try
            {
                query.BeginExecute(GetAsyncComplete, query);
            }
            catch (DataServiceQueryException ex)
            {
                throw new ApplicationException("An error occurred during query execution.", ex); 
            }
        }

        private static void GetAsyncComplete(IAsyncResult result)
        {
            QueryOperationResponse<EntryProxyObject> response = 
                ((DataServiceQuery<EntryProxyObject>)result).EndExecute(result) as QueryOperationResponse<EntryProxyObject>; 

            IList<dynamic> list = new List<dynamic>(); 

            foreach (EntryProxyObject proxy in response)
            {
                DynamicEntity entity = new DynamicEntity(proxy.Properties);
                Results.Add(entity);
            }

            while (response.GetContinuation() != null)
            {
                Uri uri = response.GetContinuation().NextLinkUri;

                response = ServiceContext.Execute<EntryProxyObject>(uri) as QueryOperationResponse<EntryProxyObject>;

                foreach (EntryProxyObject proxy in response)
                {
                    DynamicEntity entity = new DynamicEntity(proxy.Properties);
                    Results.Add(entity);
                }
            }
        }    
    }

Мои 2 вопроса:

1) Как я могу гарантировать, что получаю результаты списка только после завершения всех одновременных вызовов? Например, если вызов GetAsync () в цикле, запускающий несколько параллельных процессов, мне нужно убедиться, что все они завершены, прежде чем извлекать данные из списка результатов.

2) Могу ли я использовать BeginExecute () внутри вызова GetContinuation () и рекурсивно использовать тот же метод GetAsyncComplete (), что и функция обратного вызова? Или это создало бы тонну потоков и фактически замедлило бы вещи.

Спасибо.

1 Ответ

1 голос
/ 26 марта 2011

Взгляните на статический WaitHandle.WaitAll (WaitHandle [] waitHandles) метод.На этой странице есть отличный пример кода.

Как правило, любой класс, реализующий асинхронный шаблон, будет определять методы в форме:

IAsyncResult BeginXXX(AsyncCallback callback, Object state);

Result EndXXX(IAsyncResult asyncResult);

Вызов BeginXXX вызывает метод асинхронно и вызываетEndXXX заставляет текущий поток ждать завершения асинхронного метода.

Чтобы сделать несколько асинхронных вызовов, все, что вам нужно сделать, это вызвать BeginXXX столько раз, сколько необходимо, а затем вызвать WaitHandle.WaitAll(...), передаваяв IAsyncResult.AsyncWaitHandle для всех вызовов, которые вы хотите ждать.

Чтобы ответить на второй вопрос, да, вы можете использовать GetAsynComplete рекурсивно.Параметр state, передаваемый вызову BeginXXX, используется для идентификации запроса и доступен через свойство IAsyncResult.UserState, так что вы можете сопоставить запрос с ответом.

Является ли это хорошей вещью, немного более субъективно.Обычно асинхронные вызовы проходят через пул потоков, поэтому их одновременное создание может исчерпать доступные потоки, и после этого новые вызовы помещаются в очередь до тех пор, пока поток не станет доступным.Существуют некоторые издержки при переключении между потоками, но это, вероятно, не будет значительным (если у вас не очень большое количество потоков) по сравнению со временем, затрачиваемым на это синхронно.

...