{

current.Rollback();

ShowError("Ошибка выполнения операции: " + e.toString());}

В среде веб-служб в программе-клиенте приходится надстраивать абстракции DTO [81] . А в серверном приложении, где используются соединения, например, с СУБД или монитором транзакций, необходимо фактически дублировать предыдущий код с раскруткой объекта – единицы работы (unit of work) в реальную транзакцию.

Псевдокод транзакции в среде веб-служб

StoreServiceClient storeServiceClient = new StoreServiceClient(url);

StoreOperationDTO operation1 = storeServiceClient.CreateOperation(store1.Id);

operation1.Type = StoreOperations.Remove;

operation1.ProductId = product.Id;

operation1.Quantity = quantity;

StoreOperationDTO operation2 = storeServiceClient.CreateOperation(store2.Id);

operation2.Type = StoreOperations.Append;

operation2.ProductId = product.Id;operation2.Quantity = quantity;

UnitOfWork uow = new UnitOfWork();

uof.RegisterDirty(operation1);

uof.RegisterDirty(operation2);

try

{

storeServiceClient.ProcessOperations(uow);

}

catch (Exception e)

{

ShowError("Ошибка выполнения операции: " + e.toString());}

Вторым «упрощением» стал переход от понятных прикладному программисту деклараций интерфейсов объектов и служб на языке IDL [82] к WSDL [83] – описаниям, ориентированным, прежде всего, на обработку компьютером. Сравним декларации складской службы, возвращающей по запросу текущее количество товарных позиций.

Декларация службы в CORBA IDL

module StockServices

{

typedef float CurrentQuantity;

struct QuantityRequest

{

string stockSymbol;

};

interface StockInventoryService

{

CurrentQuantity getCurrent(in QuantityRequest request);

};};

Декларация службы в WSDL

<?xml version ="1.0" encoding ="utf-8"?>

<definitions name ="StockInventoryService"

xmlns: sqs ="http://mycompany.com/stockinventoryservice.wsdl"

xmlns: sqsxsd ="http://mycompany.com/stockinventoryservice.xsd"

xmlns: soap ="http://schemas.xmlsoap.org/wsdl/soap/"

xmlns: wsdl ="http://schemas.xmlsoap.org/wsdl/"

xmlns: xsd ="http://www.w3.org/2000/10/XMLSchema">

<wsdl: types>

<xsd: element name ="CurrentQuantity">

<xsd: complexType>

<xsd: all>

<xsd: element name ="stockSymbol" type ="string"/>

</xsd: all>

</xsd: complexType>

</xsd: element>

<xsd: element name ="CurrentQuantity">

<xsd: complexType>

<xsd: all>

<xsd: element name ="quantity" type ="float"/>

</xsd: all>

</xsd: complexType>

</xsd: element></wsdl: types>

<xsd: element name ="CurrentQuantity">

<xsd: complexType>

<xsd: all>

<xsd: element name ="quantity" type ="float"/>

</xsd: all>

</xsd: complexType>

</xsd: element>

</wsdl: types>

<wsdl: message name ="getCurrentInput">

<wsdl: part name ="body" element ="sqsxsd: CurrentQuantity"/></wsdl: message>

<wsdl: message name ="getCurrentOutput">

<wsdl: part name ="body" element ="sqsxsd: CurrentQuantity"/>

</wsdl: message>

<wsdl: portType name ="StockInventoryServicePortType">

<wsdl: operation name ="getCurrent">

<wsdl: input message ="sqs: getCurrentInput"/>

<wsdl: output message ="sqs: getCurrentOutput"/>

</wsdl: operation></wsdl: portType>

<wsdl: binding name ="StockInventoryServiceSoapBinding"

type ="sqs: StockInventoryServicePortType">

<soap: binding style ="document" transport ="http://schemas.xmlsoap.org/soap/http"/>

<wsdl: operation name ="getCurrent">

<soap: operation soapAction ="http://mycompany.com/getCurrent"/>

<wsdl: input>

<soap: body use ="literal"/>

</wsdl: input>

<wsdl: output>

<soap: body use ="literal"/>

</wsdl: output>

</wsdl: operation></wsdl: binding>

<wsdl: service name ="StockInventoryService">

<wsdl: port name ="StockInventoryServicePort"

binding ="sqs: StockInventoryServiceBinding">

<soap: address location ="http://mycompany.com/StockInventoryService"/>

</wsdl: port>

</wsdl: service></definitions>

Третьим «усовершенствованием» стал отказ от автоматической подгрузки связанных объектов [84] в пользу исключительно ручного управления процессом.

В CORBA объекты функционируют на сервере, тогда как на клиенте находится только соответствующая заглушка ( stub ). То есть вы в программе вызываете какой-то метод, а на самом деле происходит обращение к серверу, вызов соответствующего метода у серверного объекта и возврат результата на клиента с возможным обновлением состояния локальных полей заглушки. Аналогично со свойствами объектного типа: связанный объект подгружается по мере необходимости. Всё это происходит прозрачно для программиста, которому не нужно вмешиваться в процесс взаимодействия, но желательно знать, что стоит за манипуляциями с заглушкой на клиенте. Соответственно, существует соблазн вместо реализации на сервере новой функции службы написать код непосредственно на клиенте, благо сделать это легко. Тогда, например, обработка достаточно большой коллекции объектов в цикле может вызвать интенсивный обмен сообщениями с сервером и возникновение узкого места в системе. Аналогичная проблема плохой реализации имеется и при работе приложения напрямую с СУБД.

В среде веб-сервисов вопрос с «нерадивым программистом» решили радикально – отменой самой возможности написать такой код. Несмотря на то что в 80 % случаев имевшаяся автоматическая загрузка была уместной и здорово сокращала программу.

Как уберечь кукурузу от насекомых-вредителей? Очень просто: выкосить её всю, к чертям. Вредители придут, а кушать нечего.Возвращаемые веб-службами объекты не связаны с серверными за их отсутствием. Потому что у серверной части приложения нет состояния и, соответственно, не может быть никаких объектов в принципе. Обмен сообщениями происходит как и в обычной веб-среде: запрос – ответ без поддержки сессии. Общеупотребительная практика – использование DTO для передачи состояния объектов от клиента к серверу и обратно. Но DTO не содержит никаких ссылок на другие объекты, кроме вложенных. Его структура состоит из полей скалярных типов, разрешённых стандартом, вложенных объектов и массивов. Соответственно, вы не можете прозрачным образом динамически подгрузить недостающий объект, для чего придётся явным образом вызывать службу.

Прозрачная загрузка объектов в клиентском CORBA-приложении

BookGroup group = catalog.getBookCategory("Программирование");

Book[] books = group.getItems(); // один вызов сервера

foreach(Book book in books)

{

ShowInfo(book.Name +": ");

ShowInfo(book.getPopularity(). getVotesCount()); // два вызова}

Работа клиентского приложения с DTO в среде веб-служб


Перейти на страницу:
Изменить размер шрифта: