У меня есть класс, который обрабатывает число запросов / ответов http асинхронно и рекурсивно.Я был довольно счастлив с моим классом, пока я не понял, что я, возможно, закодировал себя в некоторой дыре.По сути, я хотел бы поднять событие после того, как каждый ответ прочитан для подтверждения, если приложение перешло к следующему или завершилось рано по какой-либо причине.Я признаю, что я действительно новичок в асинхронном программировании, поэтому я использую класс Async Enumerator, чтобы выручить меня.Я не против переписать этот метод или весь класс, если базовая функциональность остается неизменной, то есть она принимает n запросов и последовательно их читает.
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Webtext.Implementations;
using Webtext.Interfaces;
using Wintellect.Threading.AsyncProgModel;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Webtext.Implementations
{
public class SMSSender : Interfaces.IOperator
{
private HttpWebRequest httpRequester;
private HttpWebResponse httpResponse;
private IOperatorRequestCollection requestCollection;
private IUrlBuilder urlBuilder;
private AsyncEnumerator asyncEnum;
private CookieContainer cookieContainer;
CookieCollection cookieCollection;
public SMSSender()
{
cookieContainer = new CookieContainer();
cookieCollection = new CookieCollection();
}
public void Send(string UserName, string Password, string MessageRecipient, string Message, OperatorList Operator)
{
urlBuilder = new UrlBuilder();
requestCollection = new OperatorRequestCollection { OperatorRequestList = urlBuilder.GetUrlRequests(UserName, Password, MessageRecipient, Message, Operator) };
ProcessRequests();
}
private void ProcessRequests()
{
asyncEnum = new AsyncEnumerator();
asyncEnum.BeginExecute(GetData(asyncEnum, requestCollection.GetCurrentRequest()), asyncEnum.EndExecute);
}
private IEnumerator<Int32> GetData(AsyncEnumerator asyncEnum, IOperatorRequest request)
{
httpRequester = (HttpWebRequest)WebRequest.Create(request.RequestUrl);
httpRequester.AllowAutoRedirect = true;
httpRequester.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6";
if (httpRequester.CookieContainer == null)
httpRequester.CookieContainer = cookieContainer;
httpRequester.BeginGetResponse(asyncEnum.End(), null);
yield return 1;
httpResponse = (HttpWebResponse)httpRequester.EndGetResponse(asyncEnum.DequeueAsyncResult());
if (httpResponse.StatusCode == HttpStatusCode.OK)
{
// Create the stream, encoder and reader.
Stream responseStream = httpResponse.GetResponseStream();
Encoding streamEncoder = Encoding.UTF8;
StreamReader responseReader = new StreamReader(responseStream, streamEncoder);
CheckRequest(request, responseReader.ReadToEnd());
}
}
private void CheckRequest(IOperatorRequest Request, string Response)
{
if (Response.Contains(Request.SuccessMessage))
{
AddCookiesToRequest();
bool lastCallFinished = false;
if (requestCollection.GetCurrentRequest() != requestCollection.GetLastRequest())
{
requestCollection.MoveNextToCurrent();
ProcessRequests();
}
else
{
if (lastCallFinished == false)
{
ProcessRequests();
lastCallFinished = true;
}
}
}
}
private void AddCookiesToRequest()
{
// This method is O2 specific at the moment. I do not know if this sort of methods
// will be needed for the others so for the moment it stays as is.
cookieCollection.Add(httpResponse.Cookies);
foreach (Cookie cookie in cookieCollection)
{
cookie.Path = "/";
cookie.Domain = "o2online.ie";
}
cookieContainer.Add(httpResponse.ResponseUri, cookieCollection);
}
}
}
РЕДАКТИРОВАТЬ: Это редактирование, чтобы объяснить, что я хочу сделать:
Я по сути делаю 5 (это может быть n номеров) запросов с использованием HttpWebRequest.Я делаю это рекурсивно, так как каждый новый запрос зависит от ответа, полученного от предыдущего запроса.Эта функция работает в настоящее время.
Проблема, с которой я сталкиваюсь, состоит в том, что, поскольку ответы возвращаются асинхронно, я не могу вернуться к потоку пользовательского интерфейса, чтобы сообщить пользовательскому интерфейсу, как далеко я нахожусь.Если какой-либо ответ не удастся, сбор запросов завершится неудачно в целом, поэтому было бы неплохо узнать, какой запрос не удался, а также почему.
Я также хотел бы, чтобы работала еще одна асинхронная операция, которая может принять этоданные и отображать их с неопределенным индикатором выполнения.Таким образом, пользователь получает данные в реальном времени из пользовательского интерфейса о том, как далеко продвигается операция и почему она не удалась.Я попытался использовать фоновый рабочий, но поскольку первый запрос является асинхронным, а DO_WORK является синхронным методом, событие WORK_Completed рабочего фонового вызова вызывается до того, как работа фактически завершена.
Что касается AsyncEnumerator.Он по существу использует перечислитель, чтобы указать, что делать после yield (он вызывает move next, когда HttpEndGetResponse готов).Это устраняет некоторые проблемы, связанные с тем, что я могу перенаправить событие обратно в поток пользовательского интерфейса, чтобы поговорить с работником процесса, но оно все еще грязное, поэтому я еще не реализовал его.
Я хотел бы сделать этозапустите метод SEND для объекта SENDER, затем запустите метод SHOW_PROGRESS для другого асинхронного вызова с использованием объекта PROGRESSDISPLAY.Поскольку каждая итерация метода Send приводит к отправке данных обратно в пользовательский интерфейс, который отправляет их из объекта PROGRESSDISPLAY и позволяет ему обновляться до последнего вызова, который сообщит PROGRESSDISPLAY о закрытии.