Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Custom Type Mapper 2






Мы можем использовать поддержку бинарных вложений для более эффективной передачи сериализованных COM-объектов клиенту. Разработанный нами Custom Type Mapper использовал кодировку base64, чтобы сохранить сериализованный объект непосредственно в теле XML-ответа сервера. Мы можем избежать необходимости перекодирования бинарного потока в base64, используя бинарные вложения.

Чтобы добавить в mapper поддержку DIME, придется немного изменить методы Read и Write. Кроме того, метод XSDType будет теперь возвращать enXSDbinary. Новые реализации Read и Write будут использовать возможности объектов SOAPReader30 и SOAPSerializer30 для работы с бинарными вложениями:

STDMETHODIMP CDIMEMapper:: Write(ISoapSerializer * par_ISoapSerializer, BSTR par_encoding, enEncodingStyle par_encodingMode, LONG par_flags, VARIANT * par_var) { try { using namespace _com_util; if((par_var-> vt! = VT_UNKNOWN) & & (par_var-> vt! = VT_DISPATCH)) _com_issue_error(E_INVALIDARG); // сохраняем состоаяние объекта с помощью IPersistStream:: Save CComPtr< IPersistStream> spPersist; CheckError(par_var-> punkVal-> QueryInterface(IID_IPersistStream, (void**)& spPersist)); CComPtr< IStream> spStm; CheckError(CreateStreamOnHGlobal(0, TRUE, & spStm)); CheckError(spPersist-> Save(spStm, FALSE)); // добавляем данные в виде бинарного вложения CComPtr< IStreamAttachment> spAttach; CheckError(spAttach.CoCreateInstance(CLSID_StreamAttachment30)); CheckError(spAttach-> putref_Stream(spStm)); CheckError(par_ISoapSerializer-> AddAttachmentAndReference(spAttach)); } catch(_com_error& e) { return e.Error(); } return S_OK; }

В реализации метода Write мы добавляем данные с помощью метода AddAttachmentAndReference.

STDMETHODIMP CDIMEMapper:: Read(ISoapReader * par_soapreader, IXMLDOMNode * par_Node, BSTR par_encoding, enEncodingStyle par_encodingMode, LONG par_flags, VARIANT * par_var) { if (par_var == NULL) return E_POINTER; try { using namespace _com_util; CComPtr< IPersistStream> spPersist; // создаем объект spPersist по targetProgID аналогично реализации // Write предыдущего mapper-а... // получаем бинарное вложение // конвертируем его в IStream CComPtr< IReceivedAttachment> spAttach; CheckError(par_soapreader-> GetReferencedAttachment(par_Node, & spAttach)); CComVariant vArray; CheckError(spAttach-> GetAsByteArray(& vArray)); if(vArray.vt! = (VT_ARRAY | VT_UI1)) _com_issue_error(E_UNEXPECTED); VOID* pData = NULL; CheckError(SafeArrayAccessData(vArray.parray, & pData)); CComPtr< IStream> spStm; CheckError(CreateStreamOnHGlobal(0, TRUE, & spStm)); long lBound, uBound; CheckError(SafeArrayGetLBound(vArray.parray, 1, & lBound)); CheckError(SafeArrayGetUBound(vArray.parray, 1, & uBound)); CheckError(spStm-> Write(pData, uBound - lBound + 1, 0)); LARGE_INTEGER off = { 0 }; CheckError(spStm-> Seek(off, STREAM_SEEK_SET, 0)); //... и загружаем состояние объекта CheckError(spPersist-> Load(spStm)); CComPtr< IUnknown> spUnk; CheckError(spPersist.QueryInterface(& spUnk)); CComVariant vResult = spUnk; // возвращаем ссылку на созданный объект CheckError(vResult.Detach(par_var)); } catch(_com_error& e) { return e.Error(); } return S_OK; }

Read использует метод GetReferencedAttachment, чтобы добраться до бинарного вложения, переданного в составе сообщения.

Чтобы новый mapper мог правильно работать, придется изменить описание типа Recordset в WSDL-файле и добавить ссылку на DIME в описание SOAP-операции:

< complexType name ='RecordsetEx'> < simpleContent> < restriction base='typens: ReferencedBinary'> < annotation> < appInfo> < /appInfo> < /annotation> < /restriction> < /simpleContent> < /complexType> < binding name='PersistObjSoapBinding' type='wsdlns: PersistObjSoapPort' >... < operation name='GetEx'> < soap: operation.../> < input> < soap: body use='encoded'.../> < /input> < output> < dime: message layout= 'https://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout' wsdl: required='true' /> < soap: body... /> < /output> < /soap: operation> < /operation> < /binding>

Тег dime-message заставит SOAPServer использовать формат DIME при передаче данных клиенту. Это можно увидеть, используя утилиту трассировки:

< DimePayload> < DimeRecord traceOffset=" 0x00000000" > < Recordinfo Version=" 1" MB=" 1" ME=" 0" CF=" 0" IDLength=" 41" /> < Typefield TNF=" 2" TypeLength=" 41" /> < Options O=" 0" OptionLength=" 0" /> < Datalength length=" 585" /> < ID value=" uuid: 714C6C40-4531-442E-A498-3AC614200295" /> < Type value=" https://schemas.xmlsoap.org/soap/envelope/" /> < /DimeRecord> < DimeRecord traceOffset=" 0x000002B0" > < Recordinfo Version=" 1" MB=" 0" ME=" 1" CF=" 0" IDLength=" 41" /> < Typefield TNF=" 3" TypeLength=" 0" /> < Options O=" 0" OptionLength=" 0" /> < Datalength length=" 380" /> < ID value=" uuid: 13849D5F-BA10-4B4B-AFD1-5C3838D0524D" /> < /DimeRecord> < /DimePayload>

Как видим, DIME-сообщение включает в себя 2 записи, первая является обычным SOAP XML-откликом сервера, а вторая – сериализованным COM-объектом. Длина данных указывает на то, что преобразования в base64 не было.

Надо заметить, что код клиента и код сервера при замене одного mapper-а на другой не изменились, метод сервера использует тип Recordset, поэтому такой метод можно использовать и в DCOM-приложениях. Таким образом, использование mapper-ов придает гибкость SOAP-приложениям, позволяя “на лету” изменять способ и формат передаваемых данных, никак не затрагивая при этом ни сервер, ни клиента.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.