Работа вне браузера означает:
Устанавливается по нажатию правой клавиши:

(рис 3.1) Локальная установка Silverlight приложенияЯрлык можно разместить в меню старт или на рабочем столе. Приложение не будет перечислено в списке программ в панели управления. Приложение можно деинсталлировать с веб страницы и из самого приложения с помощью правой клавиши мыши. Будут удалены также ярлыки.
(рис 3.2) Удаление Silverlight приложенияПо умолчанию создаваемое вами Silverlight приложения нельзя установить вне браузера. Чтобы добиться этого, необходимо в свойствах проекта Visual Studio указать работу вне браузера. Можно также указать различные опции, такие как ярлыки и название.
(рис 3.3) Создание Silverlight приложения с поддержкой внебраузерной работы
(рис 3.4) Создание Silverlight приложения с поддержкой внебраузерной работы. Активация
(рис 3.5) Создание Silverlight приложения с поддержкой внебраузерной работы. Параметры приложенияИнсталляцией можно управлять изнутри кода .NET. Имеются следующие API:
Application.Current.Install();
bool IsRunningOutOfBrowser = Application.Current.IsRunningOutOfBrowser;
System.Windows.InstallState state = Application.Current.InstallState;
Installed ), неустановленно ( NotInstalled ), устанавливается ( Installing ), установка не удалась ( InstallFailed ).Application.Current.InstallStateChanged += (sender, e) => UpdateUI();
Установки внебраузерного приложения в проекте хранятся в xml файле OutOfBrowserSettings.xml. Ниже приведен пример такого файла.
<OutOfBrowserSettings ShortName="SilverlightApplication1 Application"
EnableGPUAcceleration="False" ShowInstallMenuItem="True">
<OutOfBrowserSettings.Blurb>
SilverlightApplication1 Application on your desktop; at home, at work or on the go.
</OutOfBrowserSettings.Blurb>
<OutOfBrowserSettings.WindowSettings>
<WindowSettings Title="SilverlightApplication1 Application" />
</OutOfBrowserSettings.WindowSettings>
<OutOfBrowserSettings.Icons />
</OutOfBrowserSettings>
Доступ к ним из кода .NET можно осуществить так:
System.Windows.OutOfBrowserSettings settings = Deployment.Current.OutOfBrowserSettings;
После установки приложения установки копируются в файл манифеста AppManifest.xml.
Установленное локальное приложение может иметь различные версии с серверным. В Silverlight можно контролировать версии и загружать обновления с помощью кода .NET:
Application.Current.CheckAndDownloadUpdateAsync();
Application.Current.CheckAndDownloadUpdateCompleted +=
new CheckAndDownloadUpdateCompletedEventHandler(Current_CheckAndDownloadUpdateCompleted);
CheckAndDownloadUpdateCompleted (object sender, CheckAndDownloadUpdateCompletedEventArgs e), вызываемый после окончания загрузки и обновления локального приложенияРаботающее в настоящий момент приложение обновлено не будет. Надо перезапустить приложение заново.
При работе с сетью (загрузка обновления, доступ к базе данных, веб сервису и т.д.) надо всегда проверять установлена ли сеть и работоспособна ли она. Также необходимо знать изменилось ли состояние сети за время работы приложения.
bool isNetworkAvailable = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
В данном случае выполняется проверка состояния сети.
NetworkChange.NetworkAddressChanged +=
new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
Здесь вызывается метод NetworkChange_NetworkAddressChanged(object sender, EventArgs e), если состояние сети изменилось.
Внебраузерные приложения Silverlight всегда работают в изолированном хранилище. Это означает, что данные изолированы от пользователя в виртуальной файловой системе, которая может быть как один файл в корневой директории, так и дерево каталогов и файлов. Изолированное хранилище - это абстракция, а не реальное хранилище. Любой вид данных может храниться в этом хранилище. Хранилище может располагаться на клиенте, но приложение так же может использовать изолированное хранилище на сервере. Однако, Silverlight не поддерживает "бродячий" профиль (
Размер изолированного хранилища, доступного для приложения, называется "группы квот". Размер группы по-умолчанию 1 Мб. Приложение может увеличить этот объем с помощью метода System.IO.IsolatedStorage.IsolatedStorageFile.IncreaseQuotaTo(newvalue).
Ключевым аспектом любого бизнес-приложения и многих других приложений является возможность переноса информации из базы данных в пользовательский интерфейс. Подключение осуществляется с помощью сущностей Entity. В качестве промежуточного транспортного слоя можно использовать классы служб RIA (подробнее в разделе 8 "Создание бизнес-приложений Silverlight с использованием .NET RIA сервисов"), либо классы Windows Communication Foundation.
В данном разделе используем базу данных-пример AdventureWorks для MS SQL Server 2008. Непосредственное подключение к базе данных мы не рассматриваем, т.к. нежелательно иметь прямой доступ к базе данных из Интернета. Ведь доступ рассматривается в контексте Silverlight, т.е. веб-технологии. Лучшим образом организовать доступ к СУБД посредством ASP.NET класса Domain Service и Entity, который размещен на том же сайте, где и приложение Silverlight.
Воспользуемся шаблоном Silverlight Application при создании Silverlight приложения имеющего доступ к данным базы данных. Будет создано решение с двумя проектами SilverlightApplication1 и SilverlightApplication1.Web. Эта процедура описана в разделе 0 "Дизайн и разработка приложений Silverlight в Visual Studio 2008". Затем в веб-проекте SilverlightApplication1.Web создадим модель ADO.NET Entity
(рис 3.6) Создание ADO.NET Entity Data ModelВыбираем шаблон генерации модели на основе существующей базы данных. Выбираем имеющуюся СУБД (параметр Connection String), выбираем все нужные таблицы, представления, функции и процедуры. И запускаем процедуру генерации модели. Все данные действия показаны на рис. 3.7, рис. 3.8, рис. 3.9.
(рис 3.7) Генерация модели данных на основе существующей базы данных
(рис 3.8) Выбор источника данных для модели
(рис 3.9) Выбор объектов базы данных для моделиАвтоматически будет сгенерирован класс прокси-класс Model1.Designer.cs, который содержит все выбранные элементы, как отдельные классы и свойства. После окончания генерации будет видно окно с визуальным представлением сгенерированной модели (рис. 3.10 и рис. 3.11).
(рис 3.10) Сущности модели данных
(рис 3.11) Свойства сущности модели данныхТеперь необходимо в том же веб-проекте SilverlightApplication1.Web создать прокси-класс Domain Service (рис. 3.12). Но перед этим необходимо скомпилировать приложение SilverlightApplication1.Web. Иначе нельзя будет увидеть сущности.
(рис 3.12) Добавление класса Domain ServiceДалее выбираем все необходимые сущности (рис. 3.13), которые войдут в прокси-класс Domain Service DomainService1.
(рис 3.13) Добавление класса Domain Service. Выбор сущностейТеперь переходим к проекту SilverlightApplication1. Добавляем элемент управления DataGrid на главную страницу MainPage.xaml.
<data:DataGrid x:Name="dataGrid1"/>
Данные можно загрузить с помощью процедурного языка, как показано на рис. 3.14 и на листинге кода программы:
using SilverlightApplication1.Web;
using System.Windows.Ria.Data;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
private SilverlightApplication1.Web.DomainService1 domainService =
new DomainService1();
public MainPage()
{
InitializeComponent();
System.Windows.Ria.Data.LoadOperation<Product> loadOp =
this.domainService.Load<Product>
(this.domainService.GetProductQuery());
this.dataGrid1.DataContext = loadOp.Entities;
}
}
}
(рис 3.14) Добавление ссылки на сервис Domain ServiceТеперь можно запускать отладку и увидеть таблицу Product.
(рис 3.15) Пример приложения, имеющего доступ к базе данныхДля создания приложения, имеющего доступ к базе данных с помощью технологии Windows Communication Foundation необходимо выполнить шаги, показанные на рис. 3.6, рис. 3.7, рис. 3.8, рис. 3.9, рис. 3.10 и рис. 3.11. Создав модель данных на этих этапах можно приступить к созданию веб-сервиса для того, чтобы информация была доступна приложению Silverlight, работающему со стороны клиента. В данном разделе используется модель WCF/SOAP и шаблон Silverlight-Enabled WCF Service. Щелкнем правой кнопкой мыши по веб-проекту BusinessApplication1.Web и выберем Add… New Item, выбрав Silverlight-Enabled WCF Service. Новый сервис будет называться ProductServiceWPF.svc. Если открыть ProductServiceWPF.svc.cs, можно найти метод-пустышку DoWork, который переименуем в GetProducts и изменим так, чтобы он получал список товаров Product из базы данных AdventureWorks.
(рис 3.16) Создание WCF сервиса для SilverlightКод изменим следующим образом:
namespace BusinessApplication1.Web
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements
(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class ProductServiceWPF
{
[OperationContract]
public List<Product> GetProducts()
{
AdventureWorksLT2008Entities1 dataEntity =
new AdventureWorksLT2008Entities1();
return dataEntity.Product.Where
(prod => prod.ListPrice > 3000).ToList();
}
}
}
Первая строка списка GetProducts() создает экземпляр dataEntity, который мы определили ранее. Вторая строка запрашивает экземпляр данных об объектах Product, но поскольку их слишком много, то добавим оператор where, использующий выражение prod => prod.ListPrice > 3000 для того, чтобы уменьшить число возвращаемых элементов. Чтобы привести возвращаемую сущность к списку List, вызываем свойство ToList(), конвертируя результат в List<Product>.
Теперь переходим в проект BusinessApplication1 и на странице MainPage.xaml добавляем элемент управления DataGrid по имени dataGrid1:
<UserControl
xmlns:data="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data"
x:Class="SilverlightApplication7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<data:DataGrid x:Name="dataGrid1" />
</Grid>
</UserControl>
Теперь необходимо привязать данные из веб-сервиса к данным табличной сетки. Это делается в Page.xaml.cs. Первым шагом будет добавление к этому проекту ссылки на веб-сервис. Для этого после щелчка правой кнопкой мыши по ServiceReferences и в диалоговом окне Add Service Reference по Discover увидим, созданный ранее веб-сервис (ProductServiceWPF), который появится в списке. Пространство имен останется ServiceReference1.
(рис 3.17) Добавление ссылки на веб-сервис в приложении SilverlightДобавить ссылку на сервис нужно в MainPage.xaml.cs.
ServiceReference1.ProductServiceWPFClient clnt =
new SilverlightApplication7.ServiceReference1.
ProductServiceWPFClient();
Хотя приложение Silverlight запускается в браузере, мы не можем осуществлять вызовы методов напрямую (нельзя блокировать браузер), нам скорее необходимо осуществлять асинхронные вызовы. Intellisense не только предлагает нам альтернативу в виде асинхронных вызовов, но и не предлагает нам синхронные методы, которые были созданы!
(рис 3.18) Асинхронные вызовы WPF сервисовВ общем код, после добавления обработчика событий и привязки источника данных к веб-сервису выглядит следующим образом:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading;
namespace BusinessApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
ServiceReference1.ProductServiceWPFClient clnt =
new SilverlightApplication7.ServiceReference1.
ProductServiceWPFClient();
clnt.GetProductsCompleted +=
new EventHandler<SilverlightApplication7.
ServiceReference1.GetProductsCompletedEventArgs>
(clnt_GetProductsCompleted);
clnt.GetProductsAsync();
}
void clnt_GetProductsCompleted(object sender,
SilverlightApplication7.ServiceReference1.
GetProductsCompletedEventArgs e)
{
this.dataGrid1.ItemsSource = e.Result;
}
}
}
Результат выполнения будет выглядеть, как показано на рис. 3.19.
(рис 3.19) Вызов таблицы базы данных с помощью WCFКогда проект будет скомпилирован, информация будет извлечена из базы данных, и результат будет ограничиваться лямбда-выражением, ограничивающим цену выше 3000. Он будет доступен посредством веб-сервиса и привязан к элементу управления DataGrid.
Далее рассмотрим, что можно сделать с таблицами, чтобы гибко отображать данные.
При работе с таблицами DataGrid по умолчанию можно осуществлять сортировку по значению одного поля. Одно нажатие на заголовке поля дает сортировку по возрастанию, два - по убыванию (рис. 3.20). Можно также изменить ширину колонки.
(рис 3.20) Сортировка в DataGridМожно ограничить количество выводимых полей, например тремя:
<data:DataGrid x:Name="dataGrid1"
AutoGenerateColumns="False" >
<data:DataGrid.Columns>
<data:DataGridTextColumn
x:Name="ListPrice"
Header="ListPrice"
Binding="{Binding ListPrice}"/>
<data:DataGridTextColumn
x:Name="ModifiedDate"
Header="ModifiedDate"
Binding="{Binding ModifiedDate}"/>
<data:DataGridTextColumn
x:Name="Name"
Header="Name"
Binding="{Binding Name}"/>
</data:DataGrid.Columns>
</data:DataGrid>
Остальные сервисы, такие как paging, grouping, filtering делаются методами .NET и не рассматриваются в контексте Silverlight framework.
Существует 2 подхода к созданию веб-сервисов. В случае подхода SOAP (Simple Object Access Protocol) сервер выставляет клиенту контракт, в котором указаны параметры, методы, которые клиент может вызвать из приложения. Вся работа осуществляется веб-сервисом, а клиенту передается результат работы сервиса. SOAP предоставляет способ коммуникации между приложениями, работающими под управлением различных операционных систем, на основе различных технологий и языков программирования. SOAP - ключевой элемент архитектуры .NET компании Microsoft, предназначенной для разработки интернет приложений. Примерами SOAP являются WCF, ASMX веб-сервисы. Веб-сервис имеет адрес URL, по которому клиент к нему подключается, используя протокол HTTP.
Подход REST (Representational State Transfer) сфокусирован на данных. Здесь клиент запрашивает исключительно данные, а сервер является их хранителем. В REST-сервисах акцент сделан на доступ к ресурсам, а не на исполнение удаленных сервисов; в этом их кардинальное отличие от SOAP-сервисов. Если SOAP-клиенты запрашивают выполнение действия на сервере, то REST-клиенты попросту требуют сам ресурс. Например, вместо того чтобы запрашивать удаленное исполнение функции для нахождения нужного вам формуляра заказа, вы просто запрашиваете этот формуляр, примерно так же, как статичную Web-страницу. Примеры: WCF REST, ADO.NET Data Services. Например, в Интернете имеется доступный веб-сервис интернет магазина. По URL делается запрос к нему. В запросе требуется вывести список ноутбуков, имеющихся в продаже. http://shopping.yahooapis.com/ShoppingService/v3/productSearch?appid=YahooDemoquery=notebookshow_numratings=1 - запрос. Ответом будет XML файл следующего содержания:
<?xml version="1.0" encoding="utf-8"?>
<ProductSearch xmlns="urn:yahoo:prods"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:yahoo:prods
http://shopping.yahooapis.com/shoppingservice/v3/productsearch.xsd">
…
<Refinement name="Brand"
totalAvailable="26"
totalValues="10">
<RefineValue>
<Title>Dell</Title>
<Value>4168-Brand=Dell</Value>
<Category>Laptops</Category>
<NumberOfProducts>1778</NumberOfProducts>
</RefineValue>
…
В ответе содержится число ноутбуков, и список, с указанием производителя, марки, количества штук в наличие. Далее
Для того чтобы создать приложение Silverlight, работающее с веб-сервисом SOAP, необходимо реализовать сам веб-сервис, выполняющий какие-то функции. Затем, проектируя приложение Silverlight, в Visual Studio добавляем ссылку на веб-сервис "Add Service Reference". Это делается в проекте веб сайта (хоста), на котором будет отображаться работающее приложение Silverlight. Visual Studio автоматически подключится к веб-сервису и сгенерирует прокси-класс, методы которого становятся доступными при программировании. Эти методы можно вызывать из приложения асинхронно.
(рис 3.21) Создание веб-сервиса
(рис 3.22) Добавление веб-сервиса в приложение SilverlightНиже представлен код C# для веб-сервиса:
public class Service1
{
[OperationContract]
public string CourseName()
{
return "Методика создания интерактивных приложений с
использованием технологии Silverlight";
}
}
Ниже представлен код для асинхронного вызова веб-сервиса и его метода, который возвращает название данного курса.
ServiceReference1.Service1Client client =
new SilverlightApplication1.ServiceReference1.Service1Client();
client.CourseNameCompleted +=
new EventHandler<ServiceReference1.CourseNameCompletedEventArgs>
(client_CourseNameCompleted);
client.CourseNameAsync();
void client_CourseNameCompleted(object sender,
ServiceReference1.CourseNameCompletedEventArgs e)
{
string str = "Название курса: " + e.Result;
}
Не всегда производительность веб-сервисов устраивает разработчика приложения Silverlight. При взаимодействии приложения Silverlight и веб-сервиса происходит обмен XML сообщениями. Такой формат вызывает излишний трафик. Поэтому в Silverlight 3 предусмотрен двоичный формат данных Binary XML и он является форматом по умолчанию ( <binaryMessageEncoding /> -строка файла web.config). Binary XML характеризуется компактностью и возможностью индексации содержимого. Использование двоичного формата позволяет сократить размеры пересылаемых сообщений, увеличить скорость их обработки. Формат Binary XML направлен на увеличение производительности, но не является способом сжатия. Хотя этот эффект также присутствует.
(рис 3.23) Повышение производительности при использовании Binary XMLТестирование приложения (см. результаты теста на рис. 3.23) показывает, что при высокой нагрузке двоичный формат имеет значительное преимущество в количестве обрабатываемых запросов. При 20 передаваемых объектах прирост составил 24%, а при 100 объектах уже 71%.
(рис 3.24) Уменьшение размеров сообщений при использовании формата Binary XMLКроме того, происходило уменьшение размеров сообщений (см. рис. 3.24). "Коэффициент сжатия" для строковых переменных составил 15%.
Другим важным моментом является обработка исключений. Например, при возникновении необрабатываемого исключения на стороне сервиса на стороне клиента возникает ошибка соединения CommunicationException, которая сама по себе мало о чем говорит. Если в WCF включить флаг IncludeExceptionDetailsInFaults (по умолчанию false, сделать true: <serviceDebug includeExceptionDetailInFaults="true"/> ), то даже в этом случае подробности исключения не доступны на клиенте Silverlight. Это происходит потому, что приложение Silverlight является плагином для браузера. И если сервис выдает исключение, то он посылает браузеру HTTP сообщение с кодом 500, а не 200. В этом случае приложение Silverlight не получает от браузера никаких сообщений. Решение здесь таково, что в любом случае надо посылать HTTP сообщение с кодом 200. Пример "Message Inspector Sample" в Silverlight 2 доступен по адресу
http://code.msdn.com/SilverlightWS. В Silverlight 3 это можно сделать проще, т.к. имеется поддержка классов Faults: System.ServiceModel.ExceptionDetail и FaultException<T>.
Безопасность приложений Silverlight основывается на безопасности ASP.NET. Пользователь заходит на страницу *.aspx с контейнером для приложения Silverlight и аутентифицируется на ней. Полученное разрешение используется приложением Silverlight. Схема работает нормально, если используется один домен (рис. 3.25). Если злоумышленники хотят подменить приложение и выводят пользователя на другой домен и оттуда пользователь получает доступ к информации, тогда возможно нарушение безопасности (рис. 3.26). Ситуация, когда приложение из одного интернет домена работает с веб-сервисом из другого домена, называется кроcсдоменный доступ.
(рис 3.25) Регистрация пользователяРегулирование кроcсдоменного доступа в технологии Silverlight происходит с помощью файла clientaccesspolicy.xml либо файла crossdomain.xml, используемого технологией Flash. Файл размещается в корне сайта, например, mydomain.com/clientaccesspolicy.xml. По умолчанию кросдоменный доступ запрещен.
(рис 3.26) Кроcсдоменный доступВот URL такого файла http://video.msn.com/clientaccesspolicy.xml, и его содержимое:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from>
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
Это означает, что доступ разрешен из любого домена. И другой файл http://video.msn.com/crossdomain.xml:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*.msn.com" />
<allow-access-from domain="sand.msn-int.com" />
<allow-access-from domain="articles.moneycentral.alpha.msn-int.com" />
<allow-http-request-headers-from domain="*.msn.com"
headers="SOAPAction"/>
</cross-domain-policy>
Тут видно, что для flash-приложений разрешен доступ только с определенных доменов.
Браузерная аутентификация, т.е. аутентификация, основанная на файлах cookie, или windows аутентификация, подходит только в том случае, если веб-сервис находится в одном домене, что и приложение Silverlight, либо доступ ограничен только доверенными доменами. В остальных случаях нужно использовать Message-based аутентификацию.
При Message-based аутентификации передача логина и пароля осуществляется в URL или в SOAP-заголовках.
(рис 3.27) Message-based аутентификацияАутентификация осуществляется непосредственно из приложения Silverlight (рис. 3.27). В таком случае вредное приложение не может получить доступ к специфичной информации, имеющейся в распоряжении легального приложения. Передавать логин и пароль можно как параметр:
[OperationContract] public decimal GetInfo(int accountID, string userName, string password);
Можно использовать расширения WCF, что требует глубоких знаний WCF. Но можно использовать возможности Silverlight 3. Надо указать в файле ServiceReferences.ClientConfig приложения Silverlight:
<bindings>
<customBinding>
<binding name="CustomBinding_Service1">
<binaryMessageEncoding />
<security authenticationMode="UserNameOverTransport"/>
…
</binding>
</customBinding>
</bindings>
И в файле Web.config сайта:
<bindings>
<customBinding>
<binding name="customBinding0">
<security authenticationMode="UserNameOverTransport"/>
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
Кроме того, в этом же файле надо указать:
<behaviors>
<serviceBehaviors>
<behavior name="SilverlightApplication1.Web.Service1Behavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
…
</behavior>
</serviceBehaviors>
</behaviors>
В этом случае в коде C# можно использовать прокси-класс следующим образом:
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); client.ClientCredentials.UserName.UserName = "test"; client.ClientCredentials.UserName.Password = "test";
Следует помнить, что в заголовках SOAP имя и пароль будут передаваться в открытом виде, а значит, приложение должно использовать протокол HTTPS. В Silverlight 3 имеется утилита SlSvcUtil.exe, расположенная в каталоге C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Tools. Она позволяет более гибко настраивать безопасность приложения Silverlight.
Ниже приведены некоторые опции для утилиты.
-= COMMON OPTIONS =- C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Tools>slsvcutil.exe | |
|---|---|
/directory:<directory> |
Directory to create files in (default: |
/slsvcutilConfig:<configFile> |
Custom |
/noLogo |
|
/help |
|
-= Syntax: slsvcutil.exe <metadataDocumentPath>* | <url>* | <epr> |
|
<metadataDocumentPath> |
The path to a metadata document (wsdl or xsd). Standard command-line wildcards can be used in the file path. |
<url> |
The URL to a service endpoint that provides metadata or to a metadata document hosted online. |
<epr> |
The path to an XML file that contains a WS-Addressing EndpointReference for a service endpoint that supports WS-Metadata Exchange. |
| Options: | |
/out:<file> |
The filename for the generated code. Default: derived from the WSDL definition name, WSDL service name or targetNamespace of one of the schemas. (Short Form: /o) |
/config:<configFile> |
The filename for the generated config file. Default: ServiceReferences.ClientConfig |
/mergeConfig |
Merge the generated config into an existing file instead of overwriting the existing file. |
/noConfig |
Do not generate config |
/language:<language> |
The programming language to use for generating code. Provide either a language name registered in the machine.config file or provide the fully-qualified name of a class that inherits from System.CodeDom.Compiler.CodeDomProvider. Examples of language names to use are CS and VB. Default: C#. (Short Form: /l) |
/namespace:<string,string> |
A mapping from a WSDL or XML Schema targetNamespace to a CLR namespace. Using the '*' for the targetNamespace maps all targetNamespaces without an explicit mapping to that CLR namespace. Default: derived from the target namespace of the schema document for Data Contracts. The default namespace is used for all other generated types. (Short Form: /n) |
/messageContract |
Generate Message |
/enableDataBinding |
Implement the System.ComponentModel.INotif yPropertyChanged interface on all Data |
/internal - |
Generate classes that are marked as internal. Default: generate public classes. (Short Form: /i) |
/reference:<file path> |
|
/collectionType:<type> |
A fully-qualified or assembly-qualified name of the type to use as a collection data type when code is generated from schemas. (Short Form: /ct) |
/excludeType:<type> |
A fully-qualified or assembly-qualified type name to exclude from referenced |
/noStdLib |
Do not reference |
/serializer:Auto |
Automatically select the serializer. This tries to use the Data |
/serializer:DataContractSerializer |
Generate data types that use the Data |
/serializer:XmlSerializer |
Generate data types that use the XmlSerializer for serialization and
|
/wrapped |
Generated code will not unwrap "parameters" member of document-wrapped-literal messages. |
При создании приложения Silverlight можно использовать так называемое "дуплексное" взаимодействие. Это когда сервер вызывает методы клиента, например, для системы мониторинга клиента. Либо, например, клиент вызывает веб-сервис, с помощью которого подписывается на какое-либо событие на сервере. Когда это событие происходит веб-сервис обращается к клиенту и вызывает там какой-нибудь метод. Для реализации этого необходимо на клиенте с помощью средств WCF запустить прослушивание порта TCP. Этого может не допустить
В Silverlight 3 дуплексное взаимодействие осуществляется с помощью фабрики factory, имеющейся в библиотеке System.ServiceModel.PollingDuplex, состоящей из клиентской *.dll для приложения Silverlight и серверной для веб-сервиса. Реализовать дуплекс в Silverlight 3 гораздо проще и не нужны знания WCF. Библиотеки расположены в каталогах C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.ServiceModel.PollingDuplex.dll и C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Server\System.ServiceModel.PollingDuplex.dll.
Чтобы организовать дуплекс, необходимо на веб-сервисе определить контракт с обратным вызовом:
[ServiceContract(CallbackContract = typeof(…))] [OperationContract(IsOneWay = true)]
Получить вызывающего "клиента"
OperationContext.Current.GetCallbackChannel<…>();
Для примера приведится приложение периодически генерирующее GUID, который после генерации передается клиенту и отображается в приложении Silverlight. Ниже приведен код веб-сервиса:
namespace DuplexCommunication.Web
{
[ServiceContract(Namespace = "", CallbackContract = typeof(ICallback))]
public class DataPushService
{
private ICallback client;
private Timer timer;
[OperationContract(IsOneWay = true)]
public void Subscribe()
{
client = OperationContext.Current.GetCallbackChannel<ICallback>();
timer = new Timer(
new TimerCallback(PushUpdateToClient), null, 0, 3000);
return;
}
private void PushUpdateToClient(object state)
{
try
{
client.Update(Guid.NewGuid().ToString());
}
catch (TimeoutException)
{
timer.Dispose();
}
catch (CommunicationException)
{
timer.Dispose();
}
}
}
[ServiceContract]
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void Update(string message);
}
}
Здесь в коде опеределен контракт и указан параметр CallbackContract = typeof(ICallback). Параметр ICallback представляет собой интерфейс, который передает одну переменную string message. Т.е. в этом примере GUID. В методе Subscribe() каждые 3 секунды генерируется новый GUID и в методе PushUpdateToClient он передается клиенту.
На клиенте добавляется ссылка на веб-сервис, как было показано ранее. Но адрес веб-сервиса нужно указать явно "http://localhost:6652/DataPushService.svc".
namespace DuplexCommunication
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataPushServiceClient proxy =
new DataPushServiceClient(binding, address);
proxy.UpdateReceived +=
new EventHandler<UpdateReceivedEventArgs>(proxy_UpdateReceived);
proxy.SubscribeAsync();
}
EndpointAddress address =
new EndpointAddress(@"http://localhost:6652/DataPushService.svc");
CustomBinding binding = new CustomBinding(
new PollingDuplexBindingElement(),
new TextMessageEncodingBindingElement (MessageVersion.Soap12WSAddressing10,
Encoding.UTF8),
new HttpTransportBindingElement());
void proxy_UpdateReceived(object sender, UpdateReceivedEventArgs e)
{
serverResponse.Text = e.message;
}
}
}
Здесь создается прокси-класс, который "подписывается" на событие proxy.UpdateReceived, proxy.SubscribeAsync(). При возникновении этого события вызывается метод proxy_UpdateReceived, который выводит на экран то, что передает веб-сервис через прокси-класс.
Для доступа к REST сервису приложение Silverlight использует классы HttpWebRequest и WebClient. REST сервис возвращает данные в определенном формате. Если это формат XML, то на стороне сервера используются средства XmlReader / XmlWriter, Linq to XML, XmlSerializer.
Чтобы вызвать веб-сервис REST надо:
Uri serviceUri = new Uri("http://fabrikam.com/service/getUser")WebClient downloader = new WebClient()downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted); downloader.OpenReadAsync(serviceUri)System.IO.Stream responseStream = e.Result ;Пример с классом WebClient:
public void HowToMakeRequestsToHttpBasedServices()
{
Uri serviceUri =
new Uri("http://fabrikam.com/service/getUser");
WebClient downloader = new WebClient();
downloader.OpenReadCompleted +=
new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
downloader.OpenReadAsync(serviceUri);
}
void downloader_OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
System.IO.Stream responseStream = e.Result;
}
}
Таким образом, приложение Silverlight 3 может использовать как SOAP, так и REST веб-сервисы. И делается это довольно просто.
Работа вне браузера означает:
Устанавливается по нажатию правой клавиши:

(рис 3.1) Локальная установка Silverlight приложенияЯрлык можно разместить в меню старт или на рабочем столе. Приложение не будет перечислено в списке программ в панели управления. Приложение можно деинсталлировать с веб страницы и из самого приложения с помощью правой клавиши мыши. Будут удалены также ярлыки.
(рис 3.2) Удаление Silverlight приложенияПо умолчанию создаваемое вами Silverlight приложения нельзя установить вне браузера. Чтобы добиться этого, необходимо в свойствах проекта Visual Studio указать работу вне браузера. Можно также указать различные опции, такие как ярлыки и название.
(рис 3.3) Создание Silverlight приложения с поддержкой внебраузерной работы
(рис 3.4) Создание Silverlight приложения с поддержкой внебраузерной работы. Активация
(рис 3.5) Создание Silverlight приложения с поддержкой внебраузерной работы. Параметры приложенияИнсталляцией можно управлять изнутри кода .NET. Имеются следующие API:
Application.Current.Install();
bool IsRunningOutOfBrowser = Application.Current.IsRunningOutOfBrowser;
System.Windows.InstallState state = Application.Current.InstallState;
Installed ), неустановленно ( NotInstalled ), устанавливается ( Installing ), установка не удалась ( InstallFailed ).Application.Current.InstallStateChanged += (sender, e) => UpdateUI();
Установки внебраузерного приложения в проекте хранятся в xml файле OutOfBrowserSettings.xml. Ниже приведен пример такого файла.
<OutOfBrowserSettings ShortName="SilverlightApplication1 Application"
EnableGPUAcceleration="False" ShowInstallMenuItem="True">
<OutOfBrowserSettings.Blurb>
SilverlightApplication1 Application on your desktop; at home, at work or on the go.
</OutOfBrowserSettings.Blurb>
<OutOfBrowserSettings.WindowSettings>
<WindowSettings Title="SilverlightApplication1 Application" />
</OutOfBrowserSettings.WindowSettings>
<OutOfBrowserSettings.Icons />
</OutOfBrowserSettings>
Доступ к ним из кода .NET можно осуществить так:
System.Windows.OutOfBrowserSettings settings = Deployment.Current.OutOfBrowserSettings;
После установки приложения установки копируются в файл манифеста AppManifest.xml.
Установленное локальное приложение может иметь различные версии с серверным. В Silverlight можно контролировать версии и загружать обновления с помощью кода .NET:
Application.Current.CheckAndDownloadUpdateAsync();
Application.Current.CheckAndDownloadUpdateCompleted +=
new CheckAndDownloadUpdateCompletedEventHandler(Current_CheckAndDownloadUpdateCompleted);
CheckAndDownloadUpdateCompleted (object sender, CheckAndDownloadUpdateCompletedEventArgs e), вызываемый после окончания загрузки и обновления локального приложенияРаботающее в настоящий момент приложение обновлено не будет. Надо перезапустить приложение заново.
При работе с сетью (загрузка обновления, доступ к базе данных, веб сервису и т.д.) надо всегда проверять установлена ли сеть и работоспособна ли она. Также необходимо знать изменилось ли состояние сети за время работы приложения.
bool isNetworkAvailable = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
В данном случае выполняется проверка состояния сети.
NetworkChange.NetworkAddressChanged +=
new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
Здесь вызывается метод NetworkChange_NetworkAddressChanged(object sender, EventArgs e), если состояние сети изменилось.
Внебраузерные приложения Silverlight всегда работают в изолированном хранилище. Это означает, что данные изолированы от пользователя в виртуальной файловой системе, которая может быть как один файл в корневой директории, так и дерево каталогов и файлов. Изолированное хранилище - это абстракция, а не реальное хранилище. Любой вид данных может храниться в этом хранилище. Хранилище может располагаться на клиенте, но приложение так же может использовать изолированное хранилище на сервере. Однако, Silverlight не поддерживает "бродячий" профиль (
Размер изолированного хранилища, доступного для приложения, называется "группы квот". Размер группы по-умолчанию 1 Мб. Приложение может увеличить этот объем с помощью метода System.IO.IsolatedStorage.IsolatedStorageFile.IncreaseQuotaTo(newvalue).
Ключевым аспектом любого бизнес-приложения и многих других приложений является возможность переноса информации из базы данных в пользовательский интерфейс. Подключение осуществляется с помощью сущностей Entity. В качестве промежуточного транспортного слоя можно использовать классы служб RIA (подробнее в разделе 8 "Создание бизнес-приложений Silverlight с использованием .NET RIA сервисов"), либо классы Windows Communication Foundation.
В данном разделе используем базу данных-пример AdventureWorks для MS SQL Server 2008. Непосредственное подключение к базе данных мы не рассматриваем, т.к. нежелательно иметь прямой доступ к базе данных из Интернета. Ведь доступ рассматривается в контексте Silverlight, т.е. веб-технологии. Лучшим образом организовать доступ к СУБД посредством ASP.NET класса Domain Service и Entity, который размещен на том же сайте, где и приложение Silverlight.
Воспользуемся шаблоном Silverlight Application при создании Silverlight приложения имеющего доступ к данным базы данных. Будет создано решение с двумя проектами SilverlightApplication1 и SilverlightApplication1.Web. Эта процедура описана в разделе 0 "Дизайн и разработка приложений Silverlight в Visual Studio 2008". Затем в веб-проекте SilverlightApplication1.Web создадим модель ADO.NET Entity
(рис 3.6) Создание ADO.NET Entity Data ModelВыбираем шаблон генерации модели на основе существующей базы данных. Выбираем имеющуюся СУБД (параметр Connection String), выбираем все нужные таблицы, представления, функции и процедуры. И запускаем процедуру генерации модели. Все данные действия показаны на рис. 3.7, рис. 3.8, рис. 3.9.
(рис 3.7) Генерация модели данных на основе существующей базы данных
(рис 3.8) Выбор источника данных для модели
(рис 3.9) Выбор объектов базы данных для моделиАвтоматически будет сгенерирован класс прокси-класс Model1.Designer.cs, который содержит все выбранные элементы, как отдельные классы и свойства. После окончания генерации будет видно окно с визуальным представлением сгенерированной модели (рис. 3.10 и рис. 3.11).
(рис 3.10) Сущности модели данных
(рис 3.11) Свойства сущности модели данныхТеперь необходимо в том же веб-проекте SilverlightApplication1.Web создать прокси-класс Domain Service (рис. 3.12). Но перед этим необходимо скомпилировать приложение SilverlightApplication1.Web. Иначе нельзя будет увидеть сущности.
(рис 3.12) Добавление класса Domain ServiceДалее выбираем все необходимые сущности (рис. 3.13), которые войдут в прокси-класс Domain Service DomainService1.
(рис 3.13) Добавление класса Domain Service. Выбор сущностейТеперь переходим к проекту SilverlightApplication1. Добавляем элемент управления DataGrid на главную страницу MainPage.xaml.
<data:DataGrid x:Name="dataGrid1"/>
Данные можно загрузить с помощью процедурного языка, как показано на рис. 3.14 и на листинге кода программы:
using SilverlightApplication1.Web;
using System.Windows.Ria.Data;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
private SilverlightApplication1.Web.DomainService1 domainService =
new DomainService1();
public MainPage()
{
InitializeComponent();
System.Windows.Ria.Data.LoadOperation<Product> loadOp =
this.domainService.Load<Product>
(this.domainService.GetProductQuery());
this.dataGrid1.DataContext = loadOp.Entities;
}
}
}
(рис 3.14) Добавление ссылки на сервис Domain ServiceТеперь можно запускать отладку и увидеть таблицу Product.
(рис 3.15) Пример приложения, имеющего доступ к базе данныхДля создания приложения, имеющего доступ к базе данных с помощью технологии Windows Communication Foundation необходимо выполнить шаги, показанные на рис. 3.6, рис. 3.7, рис. 3.8, рис. 3.9, рис. 3.10 и рис. 3.11. Создав модель данных на этих этапах можно приступить к созданию веб-сервиса для того, чтобы информация была доступна приложению Silverlight, работающему со стороны клиента. В данном разделе используется модель WCF/SOAP и шаблон Silverlight-Enabled WCF Service. Щелкнем правой кнопкой мыши по веб-проекту BusinessApplication1.Web и выберем Add… New Item, выбрав Silverlight-Enabled WCF Service. Новый сервис будет называться ProductServiceWPF.svc. Если открыть ProductServiceWPF.svc.cs, можно найти метод-пустышку DoWork, который переименуем в GetProducts и изменим так, чтобы он получал список товаров Product из базы данных AdventureWorks.
(рис 3.16) Создание WCF сервиса для SilverlightКод изменим следующим образом:
namespace BusinessApplication1.Web
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements
(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class ProductServiceWPF
{
[OperationContract]
public List<Product> GetProducts()
{
AdventureWorksLT2008Entities1 dataEntity =
new AdventureWorksLT2008Entities1();
return dataEntity.Product.Where
(prod => prod.ListPrice > 3000).ToList();
}
}
}
Первая строка списка GetProducts() создает экземпляр dataEntity, который мы определили ранее. Вторая строка запрашивает экземпляр данных об объектах Product, но поскольку их слишком много, то добавим оператор where, использующий выражение prod => prod.ListPrice > 3000 для того, чтобы уменьшить число возвращаемых элементов. Чтобы привести возвращаемую сущность к списку List, вызываем свойство ToList(), конвертируя результат в List<Product>.
Теперь переходим в проект BusinessApplication1 и на странице MainPage.xaml добавляем элемент управления DataGrid по имени dataGrid1:
<UserControl
xmlns:data="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data"
x:Class="SilverlightApplication7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<data:DataGrid x:Name="dataGrid1" />
</Grid>
</UserControl>
Теперь необходимо привязать данные из веб-сервиса к данным табличной сетки. Это делается в Page.xaml.cs. Первым шагом будет добавление к этому проекту ссылки на веб-сервис. Для этого после щелчка правой кнопкой мыши по ServiceReferences и в диалоговом окне Add Service Reference по Discover увидим, созданный ранее веб-сервис (ProductServiceWPF), который появится в списке. Пространство имен останется ServiceReference1.
(рис 3.17) Добавление ссылки на веб-сервис в приложении SilverlightДобавить ссылку на сервис нужно в MainPage.xaml.cs.
ServiceReference1.ProductServiceWPFClient clnt =
new SilverlightApplication7.ServiceReference1.
ProductServiceWPFClient();
Хотя приложение Silverlight запускается в браузере, мы не можем осуществлять вызовы методов напрямую (нельзя блокировать браузер), нам скорее необходимо осуществлять асинхронные вызовы. Intellisense не только предлагает нам альтернативу в виде асинхронных вызовов, но и не предлагает нам синхронные методы, которые были созданы!
(рис 3.18) Асинхронные вызовы WPF сервисовВ общем код, после добавления обработчика событий и привязки источника данных к веб-сервису выглядит следующим образом:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading;
namespace BusinessApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
ServiceReference1.ProductServiceWPFClient clnt =
new SilverlightApplication7.ServiceReference1.
ProductServiceWPFClient();
clnt.GetProductsCompleted +=
new EventHandler<SilverlightApplication7.
ServiceReference1.GetProductsCompletedEventArgs>
(clnt_GetProductsCompleted);
clnt.GetProductsAsync();
}
void clnt_GetProductsCompleted(object sender,
SilverlightApplication7.ServiceReference1.
GetProductsCompletedEventArgs e)
{
this.dataGrid1.ItemsSource = e.Result;
}
}
}
Результат выполнения будет выглядеть, как показано на рис. 3.19.
(рис 3.19) Вызов таблицы базы данных с помощью WCFКогда проект будет скомпилирован, информация будет извлечена из базы данных, и результат будет ограничиваться лямбда-выражением, ограничивающим цену выше 3000. Он будет доступен посредством веб-сервиса и привязан к элементу управления DataGrid.
Далее рассмотрим, что можно сделать с таблицами, чтобы гибко отображать данные.
При работе с таблицами DataGrid по умолчанию можно осуществлять сортировку по значению одного поля. Одно нажатие на заголовке поля дает сортировку по возрастанию, два - по убыванию (рис. 3.20). Можно также изменить ширину колонки.
(рис 3.20) Сортировка в DataGridМожно ограничить количество выводимых полей, например тремя:
<data:DataGrid x:Name="dataGrid1"
AutoGenerateColumns="False" >
<data:DataGrid.Columns>
<data:DataGridTextColumn
x:Name="ListPrice"
Header="ListPrice"
Binding="{Binding ListPrice}"/>
<data:DataGridTextColumn
x:Name="ModifiedDate"
Header="ModifiedDate"
Binding="{Binding ModifiedDate}"/>
<data:DataGridTextColumn
x:Name="Name"
Header="Name"
Binding="{Binding Name}"/>
</data:DataGrid.Columns>
</data:DataGrid>
Остальные сервисы, такие как paging, grouping, filtering делаются методами .NET и не рассматриваются в контексте Silverlight framework.
Существует 2 подхода к созданию веб-сервисов. В случае подхода SOAP (Simple Object Access Protocol) сервер выставляет клиенту контракт, в котором указаны параметры, методы, которые клиент может вызвать из приложения. Вся работа осуществляется веб-сервисом, а клиенту передается результат работы сервиса. SOAP предоставляет способ коммуникации между приложениями, работающими под управлением различных операционных систем, на основе различных технологий и языков программирования. SOAP - ключевой элемент архитектуры .NET компании Microsoft, предназначенной для разработки интернет приложений. Примерами SOAP являются WCF, ASMX веб-сервисы. Веб-сервис имеет адрес URL, по которому клиент к нему подключается, используя протокол HTTP.
Подход REST (Representational State Transfer) сфокусирован на данных. Здесь клиент запрашивает исключительно данные, а сервер является их хранителем. В REST-сервисах акцент сделан на доступ к ресурсам, а не на исполнение удаленных сервисов; в этом их кардинальное отличие от SOAP-сервисов. Если SOAP-клиенты запрашивают выполнение действия на сервере, то REST-клиенты попросту требуют сам ресурс. Например, вместо того чтобы запрашивать удаленное исполнение функции для нахождения нужного вам формуляра заказа, вы просто запрашиваете этот формуляр, примерно так же, как статичную Web-страницу. Примеры: WCF REST, ADO.NET Data Services. Например, в Интернете имеется доступный веб-сервис интернет магазина. По URL делается запрос к нему. В запросе требуется вывести список ноутбуков, имеющихся в продаже. http://shopping.yahooapis.com/ShoppingService/v3/productSearch?appid=YahooDemoquery=notebookshow_numratings=1 - запрос. Ответом будет XML файл следующего содержания:
<?xml version="1.0" encoding="utf-8"?>
<ProductSearch xmlns="urn:yahoo:prods"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:yahoo:prods
http://shopping.yahooapis.com/shoppingservice/v3/productsearch.xsd">
…
<Refinement name="Brand"
totalAvailable="26"
totalValues="10">
<RefineValue>
<Title>Dell</Title>
<Value>4168-Brand=Dell</Value>
<Category>Laptops</Category>
<NumberOfProducts>1778</NumberOfProducts>
</RefineValue>
…
В ответе содержится число ноутбуков, и список, с указанием производителя, марки, количества штук в наличие. Далее
Для того чтобы создать приложение Silverlight, работающее с веб-сервисом SOAP, необходимо реализовать сам веб-сервис, выполняющий какие-то функции. Затем, проектируя приложение Silverlight, в Visual Studio добавляем ссылку на веб-сервис "Add Service Reference". Это делается в проекте веб сайта (хоста), на котором будет отображаться работающее приложение Silverlight. Visual Studio автоматически подключится к веб-сервису и сгенерирует прокси-класс, методы которого становятся доступными при программировании. Эти методы можно вызывать из приложения асинхронно.
(рис 3.21) Создание веб-сервиса
(рис 3.22) Добавление веб-сервиса в приложение SilverlightНиже представлен код C# для веб-сервиса:
public class Service1
{
[OperationContract]
public string CourseName()
{
return "Методика создания интерактивных приложений с
использованием технологии Silverlight";
}
}
Ниже представлен код для асинхронного вызова веб-сервиса и его метода, который возвращает название данного курса.
ServiceReference1.Service1Client client =
new SilverlightApplication1.ServiceReference1.Service1Client();
client.CourseNameCompleted +=
new EventHandler<ServiceReference1.CourseNameCompletedEventArgs>
(client_CourseNameCompleted);
client.CourseNameAsync();
void client_CourseNameCompleted(object sender,
ServiceReference1.CourseNameCompletedEventArgs e)
{
string str = "Название курса: " + e.Result;
}
Не всегда производительность веб-сервисов устраивает разработчика приложения Silverlight. При взаимодействии приложения Silverlight и веб-сервиса происходит обмен XML сообщениями. Такой формат вызывает излишний трафик. Поэтому в Silverlight 3 предусмотрен двоичный формат данных Binary XML и он является форматом по умолчанию ( <binaryMessageEncoding /> -строка файла web.config). Binary XML характеризуется компактностью и возможностью индексации содержимого. Использование двоичного формата позволяет сократить размеры пересылаемых сообщений, увеличить скорость их обработки. Формат Binary XML направлен на увеличение производительности, но не является способом сжатия. Хотя этот эффект также присутствует.
(рис 3.23) Повышение производительности при использовании Binary XMLТестирование приложения (см. результаты теста на рис. 3.23) показывает, что при высокой нагрузке двоичный формат имеет значительное преимущество в количестве обрабатываемых запросов. При 20 передаваемых объектах прирост составил 24%, а при 100 объектах уже 71%.
(рис 3.24) Уменьшение размеров сообщений при использовании формата Binary XMLКроме того, происходило уменьшение размеров сообщений (см. рис. 3.24). "Коэффициент сжатия" для строковых переменных составил 15%.
Другим важным моментом является обработка исключений. Например, при возникновении необрабатываемого исключения на стороне сервиса на стороне клиента возникает ошибка соединения CommunicationException, которая сама по себе мало о чем говорит. Если в WCF включить флаг IncludeExceptionDetailsInFaults (по умолчанию false, сделать true: <serviceDebug includeExceptionDetailInFaults="true"/> ), то даже в этом случае подробности исключения не доступны на клиенте Silverlight. Это происходит потому, что приложение Silverlight является плагином для браузера. И если сервис выдает исключение, то он посылает браузеру HTTP сообщение с кодом 500, а не 200. В этом случае приложение Silverlight не получает от браузера никаких сообщений. Решение здесь таково, что в любом случае надо посылать HTTP сообщение с кодом 200. Пример "Message Inspector Sample" в Silverlight 2 доступен по адресу
http://code.msdn.com/SilverlightWS. В Silverlight 3 это можно сделать проще, т.к. имеется поддержка классов Faults: System.ServiceModel.ExceptionDetail и FaultException<T>.
Безопасность приложений Silverlight основывается на безопасности ASP.NET. Пользователь заходит на страницу *.aspx с контейнером для приложения Silverlight и аутентифицируется на ней. Полученное разрешение используется приложением Silverlight. Схема работает нормально, если используется один домен (рис. 3.25). Если злоумышленники хотят подменить приложение и выводят пользователя на другой домен и оттуда пользователь получает доступ к информации, тогда возможно нарушение безопасности (рис. 3.26). Ситуация, когда приложение из одного интернет домена работает с веб-сервисом из другого домена, называется кроcсдоменный доступ.
(рис 3.25) Регистрация пользователяРегулирование кроcсдоменного доступа в технологии Silverlight происходит с помощью файла clientaccesspolicy.xml либо файла crossdomain.xml, используемого технологией Flash. Файл размещается в корне сайта, например, mydomain.com/clientaccesspolicy.xml. По умолчанию кросдоменный доступ запрещен.
(рис 3.26) Кроcсдоменный доступВот URL такого файла http://video.msn.com/clientaccesspolicy.xml, и его содержимое:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from>
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
Это означает, что доступ разрешен из любого домена. И другой файл http://video.msn.com/crossdomain.xml:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*.msn.com" />
<allow-access-from domain="sand.msn-int.com" />
<allow-access-from domain="articles.moneycentral.alpha.msn-int.com" />
<allow-http-request-headers-from domain="*.msn.com"
headers="SOAPAction"/>
</cross-domain-policy>
Тут видно, что для flash-приложений разрешен доступ только с определенных доменов.
Браузерная аутентификация, т.е. аутентификация, основанная на файлах cookie, или windows аутентификация, подходит только в том случае, если веб-сервис находится в одном домене, что и приложение Silverlight, либо доступ ограничен только доверенными доменами. В остальных случаях нужно использовать Message-based аутентификацию.
При Message-based аутентификации передача логина и пароля осуществляется в URL или в SOAP-заголовках.
(рис 3.27) Message-based аутентификацияАутентификация осуществляется непосредственно из приложения Silverlight (рис. 3.27). В таком случае вредное приложение не может получить доступ к специфичной информации, имеющейся в распоряжении легального приложения. Передавать логин и пароль можно как параметр:
[OperationContract] public decimal GetInfo(int accountID, string userName, string password);
Можно использовать расширения WCF, что требует глубоких знаний WCF. Но можно использовать возможности Silverlight 3. Надо указать в файле ServiceReferences.ClientConfig приложения Silverlight:
<bindings>
<customBinding>
<binding name="CustomBinding_Service1">
<binaryMessageEncoding />
<security authenticationMode="UserNameOverTransport"/>
…
</binding>
</customBinding>
</bindings>
И в файле Web.config сайта:
<bindings>
<customBinding>
<binding name="customBinding0">
<security authenticationMode="UserNameOverTransport"/>
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
Кроме того, в этом же файле надо указать:
<behaviors>
<serviceBehaviors>
<behavior name="SilverlightApplication1.Web.Service1Behavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
…
</behavior>
</serviceBehaviors>
</behaviors>
В этом случае в коде C# можно использовать прокси-класс следующим образом:
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); client.ClientCredentials.UserName.UserName = "test"; client.ClientCredentials.UserName.Password = "test";
Следует помнить, что в заголовках SOAP имя и пароль будут передаваться в открытом виде, а значит, приложение должно использовать протокол HTTPS. В Silverlight 3 имеется утилита SlSvcUtil.exe, расположенная в каталоге C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Tools. Она позволяет более гибко настраивать безопасность приложения Silverlight.
Ниже приведены некоторые опции для утилиты.
-= COMMON OPTIONS =- C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Tools>slsvcutil.exe | |
|---|---|
/directory:<directory> |
Directory to create files in (default: |
/slsvcutilConfig:<configFile> |
Custom |
/noLogo |
|
/help |
|
-= Syntax: slsvcutil.exe <metadataDocumentPath>* | <url>* | <epr> |
|
<metadataDocumentPath> |
The path to a metadata document (wsdl or xsd). Standard command-line wildcards can be used in the file path. |
<url> |
The URL to a service endpoint that provides metadata or to a metadata document hosted online. |
<epr> |
The path to an XML file that contains a WS-Addressing EndpointReference for a service endpoint that supports WS-Metadata Exchange. |
| Options: | |
/out:<file> |
The filename for the generated code. Default: derived from the WSDL definition name, WSDL service name or targetNamespace of one of the schemas. (Short Form: /o) |
/config:<configFile> |
The filename for the generated config file. Default: ServiceReferences.ClientConfig |
/mergeConfig |
Merge the generated config into an existing file instead of overwriting the existing file. |
/noConfig |
Do not generate config |
/language:<language> |
The programming language to use for generating code. Provide either a language name registered in the machine.config file or provide the fully-qualified name of a class that inherits from System.CodeDom.Compiler.CodeDomProvider. Examples of language names to use are CS and VB. Default: C#. (Short Form: /l) |
/namespace:<string,string> |
A mapping from a WSDL or XML Schema targetNamespace to a CLR namespace. Using the '*' for the targetNamespace maps all targetNamespaces without an explicit mapping to that CLR namespace. Default: derived from the target namespace of the schema document for Data Contracts. The default namespace is used for all other generated types. (Short Form: /n) |
/messageContract |
Generate Message |
/enableDataBinding |
Implement the System.ComponentModel.INotif yPropertyChanged interface on all Data |
/internal - |
Generate classes that are marked as internal. Default: generate public classes. (Short Form: /i) |
/reference:<file path> |
|
/collectionType:<type> |
A fully-qualified or assembly-qualified name of the type to use as a collection data type when code is generated from schemas. (Short Form: /ct) |
/excludeType:<type> |
A fully-qualified or assembly-qualified type name to exclude from referenced |
/noStdLib |
Do not reference |
/serializer:Auto |
Automatically select the serializer. This tries to use the Data |
/serializer:DataContractSerializer |
Generate data types that use the Data |
/serializer:XmlSerializer |
Generate data types that use the XmlSerializer for serialization and
|
/wrapped |
Generated code will not unwrap "parameters" member of document-wrapped-literal messages. |
При создании приложения Silverlight можно использовать так называемое "дуплексное" взаимодействие. Это когда сервер вызывает методы клиента, например, для системы мониторинга клиента. Либо, например, клиент вызывает веб-сервис, с помощью которого подписывается на какое-либо событие на сервере. Когда это событие происходит веб-сервис обращается к клиенту и вызывает там какой-нибудь метод. Для реализации этого необходимо на клиенте с помощью средств WCF запустить прослушивание порта TCP. Этого может не допустить
В Silverlight 3 дуплексное взаимодействие осуществляется с помощью фабрики factory, имеющейся в библиотеке System.ServiceModel.PollingDuplex, состоящей из клиентской *.dll для приложения Silverlight и серверной для веб-сервиса. Реализовать дуплекс в Silverlight 3 гораздо проще и не нужны знания WCF. Библиотеки расположены в каталогах C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.ServiceModel.PollingDuplex.dll и C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Server\System.ServiceModel.PollingDuplex.dll.
Чтобы организовать дуплекс, необходимо на веб-сервисе определить контракт с обратным вызовом:
[ServiceContract(CallbackContract = typeof(…))] [OperationContract(IsOneWay = true)]
Получить вызывающего "клиента"
OperationContext.Current.GetCallbackChannel<…>();
Для примера приведится приложение периодически генерирующее GUID, который после генерации передается клиенту и отображается в приложении Silverlight. Ниже приведен код веб-сервиса:
namespace DuplexCommunication.Web
{
[ServiceContract(Namespace = "", CallbackContract = typeof(ICallback))]
public class DataPushService
{
private ICallback client;
private Timer timer;
[OperationContract(IsOneWay = true)]
public void Subscribe()
{
client = OperationContext.Current.GetCallbackChannel<ICallback>();
timer = new Timer(
new TimerCallback(PushUpdateToClient), null, 0, 3000);
return;
}
private void PushUpdateToClient(object state)
{
try
{
client.Update(Guid.NewGuid().ToString());
}
catch (TimeoutException)
{
timer.Dispose();
}
catch (CommunicationException)
{
timer.Dispose();
}
}
}
[ServiceContract]
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void Update(string message);
}
}
Здесь в коде опеределен контракт и указан параметр CallbackContract = typeof(ICallback). Параметр ICallback представляет собой интерфейс, который передает одну переменную string message. Т.е. в этом примере GUID. В методе Subscribe() каждые 3 секунды генерируется новый GUID и в методе PushUpdateToClient он передается клиенту.
На клиенте добавляется ссылка на веб-сервис, как было показано ранее. Но адрес веб-сервиса нужно указать явно "http://localhost:6652/DataPushService.svc".
namespace DuplexCommunication
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataPushServiceClient proxy =
new DataPushServiceClient(binding, address);
proxy.UpdateReceived +=
new EventHandler<UpdateReceivedEventArgs>(proxy_UpdateReceived);
proxy.SubscribeAsync();
}
EndpointAddress address =
new EndpointAddress(@"http://localhost:6652/DataPushService.svc");
CustomBinding binding = new CustomBinding(
new PollingDuplexBindingElement(),
new TextMessageEncodingBindingElement (MessageVersion.Soap12WSAddressing10,
Encoding.UTF8),
new HttpTransportBindingElement());
void proxy_UpdateReceived(object sender, UpdateReceivedEventArgs e)
{
serverResponse.Text = e.message;
}
}
}
Здесь создается прокси-класс, который "подписывается" на событие proxy.UpdateReceived, proxy.SubscribeAsync(). При возникновении этого события вызывается метод proxy_UpdateReceived, который выводит на экран то, что передает веб-сервис через прокси-класс.
Для доступа к REST сервису приложение Silverlight использует классы HttpWebRequest и WebClient. REST сервис возвращает данные в определенном формате. Если это формат XML, то на стороне сервера используются средства XmlReader / XmlWriter, Linq to XML, XmlSerializer.
Чтобы вызвать веб-сервис REST надо:
Uri serviceUri = new Uri("http://fabrikam.com/service/getUser")WebClient downloader = new WebClient()downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted); downloader.OpenReadAsync(serviceUri)System.IO.Stream responseStream = e.Result ;Пример с классом WebClient:
public void HowToMakeRequestsToHttpBasedServices()
{
Uri serviceUri =
new Uri("http://fabrikam.com/service/getUser");
WebClient downloader = new WebClient();
downloader.OpenReadCompleted +=
new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
downloader.OpenReadAsync(serviceUri);
}
void downloader_OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
System.IO.Stream responseStream = e.Result;
}
}
Таким образом, приложение Silverlight 3 может использовать как SOAP, так и REST веб-сервисы. И делается это довольно просто.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.