Вызов веб-сервиса параллельно с использованием aysnc - PullRequest
0 голосов
/ 05 февраля 2020

Я пытаюсь написать приложение winforms, которое извлекает список идентификаторов из веб-службы SOAP, затем просматривает этот список, вызывая другой веб-сервис, чтобы получить индивидуальные сведения. Чтобы ускорить процесс, я выполняю эти запросы параллельно, партиями по 15.

Когда все вызовы веб-службы возвращаются в порядке, мое приложение работает отлично. Однако в моем тестировании, если время ожидания двух или более запросов (я отслеживаю запросы с помощью Fiddler и вижу, что получаю 408), то кажется, что процесс зависает, и я никогда не получаю сообщение о завершении, которое должны отображать мои программы.

Что бы я хотел сделать, если это возможно, это повторить эти запросы или просто попросить пользователя снова нажать кнопку, поскольку произошла ошибка.

При добавлении ссылки на службу я убедился использовалась опция генерирования операций на основе задач.

Вот код, который я получил до сих пор (некоторые детали переименованы, чтобы не выдавать компанию, с которой я взаимодействую):

 private async void btnDownload_Click(object sender, EventArgs e)
        {
            try
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();

                IProgress<string> progress = new Progress<string>(s =>
                {
                    lbinfo.Items.Insert(0, s);
                });

                await GetData(progress);

                watch.Stop();

                progress.Report("Took " + (watch.ElapsedMilliseconds / 1000f) + " seconds. All done.");
            }
            catch(Exception ex)
            {
                MessageBox.Show("Main Click: "+ex.ToString());
            }
        }

 private async Task GetData(IProgress<string> progress)
        {
            try
            {
                DownloadSoapClient client = new DownloadSoapClient();
                client.Open();

                progress.Report("Getting master list.");
                List<int> uniqueIds = await GetMasterList(client); //this always seems to work

                progress.Report("Downloaded master list. Found "+uniqueIds.Count +" unique ids.");

                var detailedData = await GetIdDataRaw(uniqueIds, client,progress);

                client.Close();

            }
            catch (Exception ex)
            {
                progress.Report("GetData: "+ex);
            }
        }

       private async Task<List<DownloadResponse>> GetIdDataRaw(List<int> ids, DownloadSoapClient client, IProgress<string> progress)
        {
            using (var throttler = new SemaphoreSlim(15))
            {
                var allTasks = ids.Select(async x =>
                    {
                        await throttler.WaitAsync();

                        try
                        {
                            progress.Report(x.ToString());
                            return await client.DownloadAsync(username, password, x);

                        }
                        catch (Exception ex)
                        {
                            progress.Report("Error getting id:" + x + " " + ex.Message);
                            return null;
                        }
                        finally
                        {
                            throttler.Release();
                        }
                    });

                return (await Task.WhenAll(allTasks)).ToList();
            }
        }

Как правило, главный список составляет около 1000 записей, и, когда он выходит только 1 раз, как и ожидалось, я получаю сообщение о том, что произошла ошибка при получении идентификатора xxxx, а затем «Прошло xx секунд. Все сделано».

До сих пор я пробовал несколько других вещей, таких как создание клиента для каждого запроса и рефакторинг для использования Task.WhenAny через некоторое время l oop, но они демонстрируют то же поведение, когда 2 или больше запросов не удается.

...