Web-сервис - это компонент, к которому можно обращаться с помощью XML. Результаты вызова метода также
оборачиваются в XML. Протокол устройства XML-сообщений, которыми обмениваются клиент и Web-сервис,
называется SOAP. В отличие от RPC и других бинарных, зависимых от платформы протоколов, ориентированных
на плотное взаимодействие, SOAP предусматривает работу в слабосвязанных средах (Интернет) и, будучи
основан на XML, позволяет общаться компонентам независимо от операционной системе или инструмента
разработки, в которых они были созданы. Потребность в удаленном взаимодействии компонентов через Интернет
назрела давно. В свое время HTML-формы и ASP превратили посетителя Web-узла из пассивного зрителя,
просматривающего заранее подготовленные странички, в активного участника, формирующего страницу по
информации из базы на основе своих критериев. Однако эта информация доставлялась потребителю по-прежнему
в HTML-формате, что, может быть, удобно с точки зрения визуального восприятия, но никуда не годится,
если вы хотите, например, выцепить из полученной странички котировки акций, превратить их в recordset
и передать своему приложению. Web-сервисы публикуют описания своих интерфейсов в wsdl-файлах (аналог
библиотеки типов в СОМ). Например, методу, возвращающему котировки, нужно подать на вход интересующую
дату и биржевой символ. Чтобы найти подходящий Web-сервис или выяснить назначение найденного, можно
использовать универсальный реестр UDDI и протокол DISCO. В Visual Studio.Net входят средства создания
как самих Web-сервисов, так и клиентов, их использующих. Например, не составляет труда создать Web-сервис,
который будет принимать имя и параметры хранимой процедуры на SQL Server, выполнять ее и отсылать
результаты клиенту. Словом, типичная трехуровневая архитектура, только клиентская компонента, компонента
бизнес-логика и сервер теперь не ограничены пределами локальной сети, а находятся где угодно в Интернете.
Начиная с SQLXML 3.0 в роли Web-сервиса может выступать SQL Server 2000, так что надобность в промежуточной
компоненте теперь отпадает. Присутствие ПО промежуточного слоя наиболее часто оправдывают требованиями
безопасности, масштабируемости и программируемости. Последние два, вероятно, наиболее честные, потому
что я с трудом понимаю, как толщина middleware может влиять на устойчивость сервера к попыткам
несанкционированного проникновения. Если вы дыряво настроили политики безопасности на сервере, то
злоумышленник все равно на него придет независимо от того, 5 шагов ему перед этим придется сделать или 10.
Вот программируемость - это уже серьезней. Т-SQL до сих пор остается странной смесью мощи и ограничений.
Отсутствие многих обыденных для современных языков конструкций, не говоря уже об ООП, приводило к тому,
что народ утешал себя тем, что SQL не для того предназначался, и уходил писать логику на С++, Visual Basic,
Delphi и т.д. В последнее время круг задач, решаемых SQL Server, очень сильно расширился за рамки
пресловутого SQL, следовательно, возможности языка программирования на серверной стороне, как бы он ни
назывался, должны им соответствовать. И они будут соответствовать в следующей версии. Пункт третий -
масштабируемость. С целью повышения масштабируемости и распределения нагрузки в SQL Server 2000, как
известно, были введены распределенные фрагментированные представления. Несмотря на то, что благодаря
этому механизму SQL Server занимает в настоящий момент первые места в рейтингах производительности,
следует понимать, что в действительности это лишь первый этап на пути к базе данных, автоматически
распределяемой по многим серверам в сети, когда каждый узел, получивший запрос, разбивает его на подзапросы
к тем серверам, где в действительности лежат нужные данные (а если они продублированы, то к наименее
загруженным). Таким образом, понятно, что все три критерия обособления являются достаточно условными,
и не всегда компоненты бизнес-логики будут выноситься за пределы SQL Server. Следовательно, тот факт,
что клиентское приложение сможет общаться с ним напрямую как с Web-сервисом, на самом деле очень важен.
Вернемся к Скрипту 14.
Для запросов к SQL Server по SOAP мы создаем еще один подкаталог websvc виртуальной директории и
присваиваем ему тип vtSOAP. Его необходимо проассоциировать с физической поддиректорией (\WebService),
т.к. в ней будет храниться wsdl и др. файлы, описывающие данный Web-сервис. Не мудрствуя лукаво, обзовем
его SQLSoapSample. Методами могут выступать хранимые процедуры / функции, либо хранимые шаблоны. Первые
добавляются как AddStoredProcMethod. Параметрами выступают имя метода, под которым он будет виден и
вызываться с клиента, имя хранимой процедуры или функции, если в SELECT участвуют несколько таблиц,
соединенных оператором JOIN, то должны ли они на клиенте получаться как вложенные элементы в случае
XML-вывода / связанные таблицы в случае DataSet-вывода (1 - да, 0 - как независимые), должны ли ошибки
выполнения возвращаться как ошибки SOAP (1 - да, 0 - нет) и что является результатом работы метода
Web-сервиса: массив элементов XML, единственный DataSet или массив DataSet'ов. В данном случае выбран
второй вариант. Массив DataSet'ов имеет смысл использовать в том случае, когда внутри процедуры
выполняются несколько независимых SELECT'ов. Хранимая процедура CustomerOrdersForYear состоит из одного
параметризованного запроса, с которым мы работали еще со Скрипта 3.
CREATE PROCEDURE CustomerOrdersForYear @Name nvarchar(20), @Year smallint AS
SELECT c.ContactName, c.ContactTitle, o.OrderDate, o.Freight FROM Customers c
INNER JOIN Orders o ON c.CustomerID = o.CustomerID
WHERE c.ContactName like @Name + '%' and year(o.OrderDate) = @Year
Скрипт 19
В качестве второго метода Web-сервиса выбираем шаблон из п.10 (рис.6). Он добавляется вызовом
AddTemplateMethod. Параметрами служат внешнее имя метода, местоположение шаблона относительно данного
скрипта и способ передачи ошибок (SOAP - да/нет). Результат шаблона можно передавать только как набор
XML-элементов. Строка sqlWebSvc.SoapMethods.GenerateWSDL(); производит автоматическую генерацию
wsdl-файла, который кладется в физическую директорию, соответствующую виртуальному подкаталогу типа soap.
После этого Web-сервис становится доступным для обращений.
Как и в классическом DCOM, на машине клиента нужно создать прокси, содержащего сигнатуру методов
Web-сервиса. В графической среде разработки Visual Studio это происходит автоматически при добавлении
ссылки на wsdl-файл в раздел Web References проекта. Прокси можно также сгенерировать с помощью утилиты
командной строки wsdl.exe:
wsdl.exe /l:CS /o:SQLSrvWebService_Proxy.cs /n:SQLSrvWebRef
http://localhost/SQLXML3/websvc?wsdl
В качестве параметров здесь передаются язык, на котором будет создан прокси, имя файла с прокси, его
пространство имен и URI Web-сервиса с его описанием в виде wsdl. Обращение клиента к Web-сервису
показано в Скрипте 20.
static void SQLSrvWebService_Client()
{
SQLSrvWebRef.SQLSoapSample proxy = new SQLSrvWebRef.SQLSoapSample();
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
Console.WriteLine("----------------------------------------------------------------");
Console.WriteLine("Результаты выполнения шаблона (всегда как массив XML-элементов):");
object[] resultXml = proxy.ПримерВызоваШаблона("20", "1000");
foreach (XmlElement x in resultXml)
Console.WriteLine(x.OuterXml);
Console.WriteLine("\n----------------------------------------------------------------");
Console.WriteLine("Результаты выполнения хранимой процедуры (заказаны как DataSet):");
int retVal;
DataSet resultRel = proxy.ЗаказыКлиентаЗаГод("Maria", 1997, out retVal);
DataRelation rel = resultRel.Relations[0];
Console.WriteLine("\nТаблицы связаны отношением " + rel.RelationName);
Console.Write("Родительская таблица " + rel.ParentTable.TableName + ", родительский ключ - ");
foreach (DataColumn c in rel.ParentColumns) Console.Write(c.ColumnName + " ");
Console.Write("\nДочерняя таблица " + rel.ChildTable.TableName + ", дочерний ключ - ");
foreach (DataColumn c in rel.ChildColumns) Console.Write(c.ColumnName + " ");
Console.WriteLine("");
foreach (DataRow rParent in rel.ParentTable.Rows)
{
Console.WriteLine("\nТаблица " + rel.ParentTable.TableName);
foreach (DataColumn cParent in rel.ParentTable.Columns) Console.Write(cParent.Caption
+ ": " + rParent[cParent] + "; ");
Console.Write("\n\tСвязанные записи из таблицы " + rel.ChildTable.TableName);
foreach (DataRow rChild in rParent.GetChildRows(rel))
{
Console.Write("\n\t");
foreach (DataColumn cChild in rel.ChildTable.Columns)
Console.Write(cChild.Caption + ": " + rChild[cChild] + "; ");
}
Console.WriteLine("");
}
}
Скрипт 20
Результат выполнения шаблона получается в виде массива XmlElement, состоящего из единственного элемента,
OuterXml которого показан ниже:
<Солянка xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<Employees EmployeeID="1" LastName="Davolio" FirstName="Nancy" Title="Sales Re
presentative" TitleOfCourtesy="Ms." ... />
<Customers ContactName="Horst Kloss" Кол-во="28" /><Customers ContactName="Jos
e Pavarotti" Кол-во="31" /><Customers ContactName="Roland Mendel" Кол-во="30" />
<Клиент Имя="Horst Kloss" Фирма="QUICK-Stop" Должность="Accounting Manager"><А
дрес><Страна>Germany</Страна><Город>Cunewalde</Город><Улица_дом>Taucherstra?e 10
</Улица_дом></Адрес><Заказы><Заказ Номер="10273"><Дата>1996-08-05</Дата><Стоимос
ть>76.07</Стоимость></Заказ><Заказ Номер="10285"><Дата>1996-08-20</Дата><Стоимос
ть>76.83</Стоимость></Заказ>...</Заказы></Клиент>
<Сотрудник Фамилия="Fuller" Имя="Andrew"><Сотрудник Фамилия="Davolio" Имя="Nan
cy" /><Сотрудник Фамилия="Leverling" Имя="Janet" /><Сотрудник Фамилия="Peacock"
Имя="Margaret" /><Сотрудник Фамилия="Buchanan" Имя="Steven"><Сотрудник Фамилия="
Suyama" Имя="Michael" /><Сотрудник Фамилия="King" Имя="Robert" /><Сотрудник Фами
лия="Dodsworth" Имя="Anne" /></Сотрудник><Сотрудник Фамилия="Callahan" Имя="Laur
a" /></Сотрудник>
</Солянка>
DataSet как результат второго метода состоит из двух таблиц: Customers и Orders. Выбор
Row Formatting = Nested на стадии определения метода Web-сервиса приводит к тому, что условие соединения
таблиц в запросе (JOIN) переходит в свойство Relations объекта DataSet и позволяет для каждого клиента
выбрать сделанные им заказы:
Таблица Customers
ContactName: Maria Larsson; ContactTitle: Owner; Customers_Id: 0;
Связанные записи из таблицы Orders
OrderDate: 03.02.1997 0:00:00; Freight: 17.92; Customers_Id: 0;
OrderDate: 28.02.1997 0:00:00; Freight: 16.27; Customers_Id: 0;
OrderDate: 12.05.1997 0:00:00; Freight: 188.04; Customers_Id: 0;
OrderDate: 06.06.1997 0:00:00; Freight: 242.21; Customers_Id: 0;
Таблица Customers
ContactName: Maria Anders; ContactTitle: Sales Representative; Customers_Id: 1;
Связанные записи из таблицы Orders
OrderDate: 25.08.1997 0:00:00; Freight: 29.46; Customers_Id: 1;
OrderDate: 03.10.1997 0:00:00; Freight: 61.02; Customers_Id: 1;
OrderDate: 13.10.1997 0:00:00; Freight: 23.94; Customers_Id: 1;
Таблица Customers
ContactName: Maria Larsson; ContactTitle: Owner; Customers_Id: 2;
Связанные записи из таблицы Orders
OrderDate: 14.10.1997 0:00:00; Freight: 152.3; Customers_Id: 2;
OrderDate: 02.12.1997 0:00:00; Freight: 328.74; Customers_Id: 2;
OrderDate: 11.12.1997 0:00:00; Freight: 48.2; Customers_Id: 2;
The program '[2460] ConsoleApplication1.exe' has exited with code 0 (0x0).
|
|