Ну-с, для разнообразия сугубо технический пост. Да-да, знаю, тривиально. Не нравится - не ешьте. Просто, кому-то умному, но кому это было на фиг не нужно, будет приятно увидеть что-то готовое, а не вычислять и разбираться. Или, кому-то умному, кому это пару лет не нужно было. Скажем, мне самому через пару лет. В общем, не придирайтесь, вещь тривиальная, но полезная. Даже просто для чисто бытовых потребностей, скажем там, какую онлайн библиотеку книжек скачать...
Итак, для HTTP в .Net и Silverlight есть два главных класса, которые делают примерно одно и то же: HttpWebRequest и WebClient. Пример ниже показывает как использовать их оба (есть мелкие косметические отличия).
Итак, сначала тестовая программа, которая их будет выполнять:
using System;
namespace
HttpCalls{
class Program
{
static void Main(string[] args)
{
HttpWebRequestBased r1 = new HttpWebRequestBased();
r1.Get("http://blogs.technet.com/eldar/default.aspx");
Console.ReadLine();
WebClientBased r2 = new WebClientBased();
r2.Get("http://blogs.technet.com/eldar/default.aspx");
Console.ReadLine();
HttpRequestBasedSync r3 = new HttpRequestBasedSync();
r3.Get("http://blogs.technet.com/eldar/default.aspx");
Console.ReadLine();
}
}
}
Теперь начнем с последнего - синхронного использования HttpWebRequest:
using
System;using System.Net;
using System.IO;
namespace
HttpCalls{
class HttpRequestBasedSync
{
public void Get(string URL)
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(URL);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream stream = resp.GetResponseStream();
StreamReader sr = new StreamReader(stream);
string res = sr.ReadToEnd();
sr.Close();
Console.WriteLine("Success. Press any key to see the result:");
Console.ReadLine();
Console.WriteLine(res.Substring(0, 500));
}
}
}
Простенько и со вкусом... хм-м-м... ну, ладно, о вкусах не спорят! По крайней мере вполне компактно. Кстати, в Silverlight это дело не сработает, там синхронного GetResponseStream нету, чтобы не блокировать UI thread, на котором в Silverlight выполняется почти все интересное. Так что же делать? А делать то же самое асинхронно:
using
System;using System.Net;
using System.IO;
namespace
HttpCalls{
class HttpWebRequestBased
{
public void Get(string URL)
{
req = (HttpWebRequest)HttpWebRequest.Create(URL);
req.BeginGetResponse(new AsyncCallback(callback), null);
} private void callback(IAsyncResult ar)
{
if (ar.IsCompleted)
{
HttpWebResponse resp = (HttpWebResponse) req.GetResponse();
Stream stream = resp.GetResponseStream();
StreamReader sr = new StreamReader(stream);
string res = sr.ReadToEnd();
sr.Close();
Console.WriteLine("Success. Result:");
//Console.ReadLine();
Console.WriteLine(res.Substring(0,500));
}
} private HttpWebRequest req;
}
}
К слову, callback вызывается на самом деле ровно один раз, так что не раскатывайте губу на то, чтобы показывать всякие progress bars в процессе. В Silverlight callback вызывается на UI thread, но опять же, учтите, что это может измениться, так что менять UI элементы в этом вызове лучше избегать. Так... на всякий случай.
Ну и наконец, то же самое асинхронно с WebClient. Этот класс предполагается самым "продвинутым" и "удобынм", так что не удивляйтесь, что он требует больше всего кода.
using
System;using System.Net;
using System.IO;
namespace HttpCalls
{
class WebClientBased
{
public void Get(string URL)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
client.OpenReadAsync(new Uri(URL));
}
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Cancelled || e.Error != null)
{
Console.WriteLine("Error reading the file");
}
else
{
Stream stream = e.Result;
StreamReader sr = new StreamReader(stream);
string res = sr.ReadToEnd();
sr.Close();
Console.WriteLine("Success. Result:");
//Console.ReadLine();
Console.WriteLine(res.Substring(0, 500));
}
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
Console.WriteLine("Progress is {0}, {1}% out of {2} bytes.", e.BytesReceived, e.ProgressPercentage, e.TotalBytesToReceive);
}
}
}
Вызывается callback в Silverlight тоже на UI thread, по крайней мере пока что. В Silverlight у вас может случиться вызов client_DownloadProgressChanged с промежуточным прогрессом, в обычном .Net я этого не видел. Впрочем, даже если вызов и случается, вы только узнаете, сколько прочитано, доступа к реальным данным (Stream) у вас все равно нет до тех пор, пока чтение Http ответа не закончится.
В Silverlight во всех трех случаях Stream это по сути wrapper вокруг куска памяти, выделенного в native коде, так что всякие Seek() работают как часы. Очень удобно.
Заметьте, что это все на основании опубликованной информации на данный момент. Когда выйдет бета 2 Silverlight v.2, я опубликую подправленный вариант с изменениями и новыми интересными деталями.
No comments:
Post a Comment