我有一个类,它以异步和递归方式处理n个http请求/ repsonses。我很满意我的班级,直到我意识到我可能把自己编成了一个洞。基本上我想在读取每个响应之后提出一个事件,以确认应用程序是否已进入下一个或因任何原因提前完成。我承认我是异步编程的新手,所以我使用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);
}
}
}
编辑:此编辑是为了解释我要做的事情:
我基本上使用HttpWebRequest发出5(这可能是n个)请求。我正在递归地执行此操作,因为每个新请求都取决于从先前请求获得的响应。此功能目前有效。
我遇到的问题是,由于响应是异步回来的,我无法回到UI线程让UI知道我有多远。如果任何响应失败,请求集合将作为一个整体失败,因此最好知道哪个请求失败以及原因。
我还想让另一个异步操作工作,可以接收这些数据并使用不确定的进度条显示它。这样,用户就可以从UI获取关于操作的距离以及是否失败的实时数据。我在这里尝试了一个背景工作者但是因为第一个请求是异步的而且DO_WORK是一个同步方法,所以在工作实际完成之前调用了一个backround worker的WORK_Completed事件。
AsyncEnumerator。它本质上使用枚举器来指定yield之后要做什么(当HttpEndGetResponse准备就绪时,它调用next。这提升了一些问题,因为我可以将事件编组回UI线程与进度工作者交谈,但它仍然很混乱,所以我还没有实现它。
我想要做的是在SENDER对象上触发SEND方法,然后使用PROGRESSDISPLAY对象在不同的异步调用上触发SHOW_PROGRESS方法。因为Send方法的每次迭代都会将发送数据发送回UI,后者将其从PROGRESSDISPLAY对象发送出去并允许它更新,直到最终调用将告诉PROGRESSDISPLAY关闭。
答案 0 :(得分:0)
最后,重写似乎是最好的选择。新类具有将被触发回UI线程的方法。并不是说这堂课错了。事实上它工作正常。问题在于我从未允许任何回应机制。一旦完成,我将用新课程更新这篇文章。