Опубликован: 24.03.2009 | Доступ: свободный | Студентов: 2286 / 115 | Оценка: 4.24 / 3.93 | Длительность: 17:47:00
Лекция 10:

Создание взаимодействующих с сервером приложений в Silverlight

Класс WebClient

Класс WebClient является простейшим классом удаленного взаимодействия для Silverlight. При его использовании задается Uri содержимого, доступ к которому необходимо организовать, и затем для загрузки данных вызывается метод DownloadStringAsync (Загрузить строку асинхронно) или OpenReadAsync (Открыть для чтения асинхронно). Первый используется для получения строковых данных, второй -для получения любых данных в виде потока. Для возвращения результатов выполнения этих методов потребуется функция обратного вызова, DownloadStringCompleted (Загрузка строки завершена) или OpenReadCompleted (Чтение завершено), соответственно.

Попробуем все это на практике. Создадим приложение Silverlight и, как делали это ранее, добавим универсальный обработчик в Веб-приложение и используем его для возвращения текущего времени на сервере. Для этого просто изменим ProcessRequest (Обработать запрос) следующим образом:

public void ProcessRequest (HttpContext context) 
{
  context. Response.ContentType = "text/plain";
  context. Response. Write(System.DateTime. Now.ToLongTimeString()); 
}

Теперь в Page.xaml.cs можно использовать класс WebClient для общения с сервером. Для этого добавьте в начало своего кода ссылку на пространство имен System.Net:

using System.Net;

Теперь, чтобы использовать класс WebClient, необходимо будет просто применить следующий код. Обратите внимание, что при написании кода этого приложения я использовал Cassini, поэтому работал с портом 65144. Вы можете использовать другой порт при выполнении своего приложения, поэтому не забудьте внести в код соответствующие изменения или настройте Cassini на использование конкретного порта.

public Page()
{
 InitializeComponent();
 WebClient cl = new WebClient();
 Uri uri = new Uri("http://localhost:65144/WebClientTest Web/Time.ashx");
 cl.DownloadStringCompleted +=
 new DownloadStringCompletedEventHandler(cl DownloadStringCompleted);
 cl.DownloadStringAsync(uri);
}

Для события DownloadStringCompleted объявлена функция-обработчик cl DownloadStringCompleted, поэтому по завершении передачи данных будет вызываться эта функция. Рассмотрим ее:

void cl  DownloadStringCompleted(object sender,
         DownloadStringCompletedEventArgs e) {
txtTime.Text = e.Result; }

Как видите, функция получает объект аргументов (в виде класса DownloadStringCompletedEventArgs ), в котором имеется свойство Result, содержащее возвращенную строку.

WebClient имеет еще несколько полезных атрибутов: свойство IsBusy (Занят), которое возвращает true, если асинхронная передача данных еще не завершена, и метод CancelAync, который может использоваться для отмены выполняющихся асинхронных транзакций. Если это происходит, свойству Cancelled (Отменен) соответствующего обработчика ( DownloadStringCompleted или OpenReadCompleted ) присваивается значение true.

Класс WebRequest

Немного больше возможностей, включая использование Silverlight в качестве клиентской части стандартного шаблона HTTP-форм (с HTTP-POST ), предоставляет класс WebRequest. Он действительно полезен с точки зрения обеспечения возможности взаимодействия, потому что методика HTTP-POST широко используется во всех серверных технологиях, так что клиентскую часть на HTML можно заменить Silverlight-приложением без всяких изменений серверной части кода.

Итак, например, объединим серверный компонент, принимающий запрос HTTP post к трем текстовым полям, t1, t2 и t3. Начнем с создания Silverlight-приложения и добавим универсальный обработчик в Веб-проект. Отредактируем метод обработчика ProcessRequest так, чтобы он принимал значения формы через HTTP-POST. Вот как реализовать прием трех строк из запроса HTTP-POST:

public void ProcessRequest (HttpContext context) {
 string str1 = "";
 string str2 = "";
 string str3 = "";
 if (context.Request.HttpMethod == "POST")
 {
  str1 = context.Request.Form["t1"];
  str2 = context.Request.Form["t2"];
  str3 = context.Request.Form["t3"];
 }
 context.Response.ContentType = "text/plain";
 context.Response.Write("OK");
}

Обычно в таких случаях используется HTML-форма с тремя элементами управления TextField (t1, t2 и t3 ) и кнопкой Submit (Отправить) для передачи этих данных. То же самое можно сделать в Silverlight. Вот XAML для простой формы ввода данных:

<UserControl x:Class="WebRequestTest.Page" xmlns=" http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xam l" Width="400" Height="300">

<UserControl x:Class="WebRequestTest.Page"
             xmlns="http://schemas.microsoft.com/client/2007"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Width="400" Height="300">
  <Grid x:Name="LayoutRoot" Background="White">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="0.265*"/>
      <ColumnDefinition Width="0.735*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="0.037*"/>
      <RowDefinition Height="0.1*"/>
      <RowDefinition Height="0.05*"/>
      <RowDefinition Height="0.106*"/>
      <RowDefinition Height="0.054*"/>
      <RowDefinition Height="0.09*"/>
      <RowDefinition Height="0.563*"/>
    </Grid.RowDefinitions>
    <TextBox Margin="0,0,25,0" Grid.Column="1"
             Grid.Row="1" x:Name="t1"/>
    <TextBox Margin="0,0,25,0" Grid.Column="1"
             Grid.Row="3" x:Name="t2"/>
    <TextBox Margin="0,0,25,0" Grid.Column="1"
             Grid.Row="5" x:Name="t3"/>
    <TextBlock Margin="8,0,0,0" Grid.Row="1"
               Text="Field 1" TextWrapping="Wrap"/>
    <TextBlock Margin="8,0,8,0" Grid.Row="3"
               Text="Field 2" TextWrapping="Wrap"/>
    <TextBlock Margin="8,0,8,0" Grid.Row="5"
               Text="Field 3" TextWrapping="Wrap"/>
    <Button Height="36" HorizontalAlignment="Left"
            Margin="0,26.9,0,0" VerticalAlignment="Top"
            Width="77" Grid.Column="1" Grid.Row="6"
            Content="Submit" x:Name="b" Click="b_Click" />
  </Grid>
</UserControl>

Как эта форма выглядит, можно увидеть на рис. 10.14.

 Форма ввода данных на Silverlight

Рис. 10.14. Форма ввода данных на Silverlight

Пользователь вводит текст в трех полях и затем нажимает кнопку Submit. При этом формируется событие b_Click. Вот код обработки этого события:

private void b Click(object sender, RoutedEventArgs e) {
  Uri uri = new Uri( "http://localhost:22602/WebRequestTest Web/SubmitForm.ashx");
  WebRequest rq = WebRequest.Create(uri);
  rq. Method = "POST";
  rq.ContentType = "application/x-www-form-urlencoded";
  rq.BeginGetRequestStream(new AsyncCallback(RequestReady), rq);
  rq.BeginGetResponse(new AsyncCallback(ResponseReady), rq); 
}

При использовании класса WebResponse сначала необходимо задать вызываемый URI. Это выполняется с помощью объекта Uri; он указывает на сайт, содержащий обработчик форм. Затем этот URI передается в метод Create (Создать) WebRequest для установления связи. Также задается используемый Method (Метод). Это может быть метод HTTP-Verb, такой как POST или GET. В данном случае, выполняется отправка данных формы, поэтому должен применяться POST.

Далее необходимо задать соответствующий тип содержимого. Опять же, поскольку используется форма, этим типом будет application/x-www-form-urlencoded. Все эти действия выполняются соответственно Веб-стандартам, поэтому возможные варианты значений можно найти в любом хорошем справочнике по Веб.

Наконец, должен быть задан поток запроса. Это поток, потому что предполагается запись данных в запрос. Вы должны задать метод асинхронного обратного вызова, который будет выполняться после завершения Request, а также ссылку на сам объект запроса. Кроме того, требуется перехватывать ответ формы, поэтому вызывается BeginGetResponse (Начать прием ответа) для начала настройки потока и задается обратный вызов, который будет выполняться, когда поток ответа готов.

В методе обратного вызова, который вызывается, когда поток запроса готов, можно выполнить запись в поток, используя объект StreamWriter (объект записи в поток). В данном случае, записывается несколько параметров. Согласно протоколу HTTP они должны быть разделены символами &:

t1=значение1&t2=значение2&t3=значение3.

Итак, теперь осталось лишь записать имя параметра и свойство Text полей ввода:

void RequestReady(IAsyncResult aR){
  WebRequest rq = aR.AsyncState as WebRequest;
  Stream rqStream = rq.EndGetRequestStream(aR);
  StreamWriter w = new StreamWriter(rqStream);
  w.Write("t1=" + t1.Text + "&");
  w.Write("t2=" + t2.Text + "&");
  w.Write("t3=" + t3.Text );
  w.Flush(); 
}

Как было показано в универсальном обработчике событий, после того как сервер получает данные, он записывает OK для обозначения состояния. По завершении записи ответа вызывается метод обратного вызова ResponseReady (Ответ готов).

void ResponseReady(IAsyncResult aR) {
  WebRequest rq = aR.AsyncState as WebRequest;
  using(WebResponse rs = rq.EndGetResponse(aR))
  using (Stream rpStream = rs.GetResponseStream())
  { StreamReader rdr = new StreamReader(rpStream); 
    string postStatus = rdr.ReadToEnd();
  } 
}

Этот код просто извлекает поток ответа из результата асинхронного вызова и читает его до конца. В данном случае, это просто состояние, но так можно извлекать ответы с сервера для каждого поля.

Как видите, применяя данную методику, довольно просто создавать Silverlight-клиентские приложения заменяющие традиционные HTTP-формы!