我正在开发一个异步Http抓取工具,它从各种服务中收集数据,目前,我正在处理执行串行HttpWebRequest调用的线程池,以便从服务中发布/获取数据。
我想转换到异步Web调用(BeginGetRequestStream和BeginGetResponse),我需要某种方式获取响应数据和POST统计信息(%完成写入,完成时(完成时更重要)等)。我目前有一个从产生/包含线程的对象调用的事件,已收到信号HTTP数据。我可以附加的WebRequests中是否有一个事件来调用已经实现的事件?这对过渡来说是最无缝的。
感谢您的帮助!!
答案 0 :(得分:4)
以下代码我只是从this article复制/粘贴(和编辑)有关异步Web请求的代码。它显示了如何以一种有条理的方式编写异步代码的基本模式,同时跟踪哪些响应与请求等有关。当您完成响应时,只需触发一个通知UI的事件回应完了。
private void ScanSites ()
{
// for each URL in the collection...
WebRequest request = HttpWebRequest.Create(uri);
// RequestState is a custom class to pass info
RequestState state = new RequestState(request, data);
IAsyncResult result = request.BeginGetResponse(
new AsyncCallback(UpdateItem),state);
}
private void UpdateItem (IAsyncResult result)
{
// grab the custom state object
RequestState state = (RequestState)result.AsyncState;
WebRequest request = (WebRequest)state.request;
// get the Response
HttpWebResponse response =
(HttpWebResponse )request.EndGetResponse(result);
// fire the event that notifies the UI that data has been retrieved...
}
请注意,您可以将RequestState对象替换为您想要的任何类型的对象,以帮助您跟踪事物。
你可能已经这样做了,但如果没有,我相信这是一个完全可以接受和干净的方法来解决这个问题。如果这不是您想要的,请告诉我。
答案 1 :(得分:3)
您可以传递需要调用的委托(作为异步“状态”参数的一部分)。然后在您的EndGetResponseStream执行您需要的操作之后,然后使用您需要的任何参数调用此委托。
就个人而言,既然你正在转向aysnc编程模型(我假设要获得更好的性能),我强烈建议你将工作流程转移到异步。此模型允许您在结果进入时尽可能快地处理结果,而不会发生任何阻塞。
修改强>
在我的博客上有一篇文章
HttpWebRequest - Asynchronous Programming Model/Task.Factory.FromAsyc
关于这个问题。我目前正在编写它,但我已经提出了一个我认为你可以在你的情况下使用的课程。根据您的需要,查看GetAsync方法或PostAsync方法。
public static void GetAsyncTask(string url, Action<HttpWebRequestCallbackState> responseCallback,
string contentType = "application/x-www-form-urlencoded")
注意responseCallback参数?那是我之前谈过的代表。
以下是您如何调用它的示例(我正在显示PostAsyn()方法
var iterations = 100;
for (int i = 0; i < iterations; i++)
{
var postParameters = new NameValueCollection();
postParameters.Add("data", i.ToString());
HttpSocket.PostAsync(url, postParameters, callbackState =>
{
if (callbackState.Exception != null)
throw callbackState.Exception;
Console.WriteLine(HttpSocket.GetResponseText(callbackState.ResponseStream));
});
}
循环可以是您的网址集合。在GET的情况下,您不需要发送任何(POST)参数,回调是您在我写入控制台的位置看到的lambda。在这里你可以做你需要的,你可以发送一个代表,以便响应处理在“其他地方”完成。
回调方法也是
Action<HttpWebRequestCallbackState>
HttpWebRequestCallbackState
是自定义类,您可以修改以包含您出于此目的所需的任何信息。或者您可以将签名修改为Action。
答案 2 :(得分:2)
您可以使用System.Net.WebClient类:
var client = new WebClient();
client.DownloadDataCompleted += (s, args) => { /* do stuff here */ };
client.DownloadDataAsync(new Uri("http://someuri.com/"));
答案 3 :(得分:0)
第二种方法是我结束回应的主要方式。
public string GetResponse()
{
// Get the original response.
var response = _request.GetResponse();
Status = ((HttpWebResponse) response).StatusDescription;
// Get the stream containing all content returned by the requested server.
_dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
var reader = new StreamReader(_dataStream);
// Read the content fully up to the end.
var responseFromServer = reader.ReadToEnd();
// Clean up the streams.
reader.Close();
if (_dataStream != null)
_dataStream.Close();
response.Close();
return responseFromServer;
}
/// <summary>
/// Custom timeout on responses
/// </summary>
/// <param name="millisec"></param>
/// <returns></returns>
public string GetResponse(int millisec)
{
//Spin off a new thread that's safe for an ASP.NET application pool.
var responseFromServer = "";
var resetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(arg =>
{
try
{
responseFromServer = GetResponse();
}
catch (Exception ex)
{
throw ex;
}
finally
{
resetEvent.Set();//end of thread
}
});
//handle a timeout with a asp.net thread safe method
WaitHandle.WaitAll(new WaitHandle[] { resetEvent }, millisec);
return responseFromServer;
}