В чем разница между типом и элементом в WSDL?

В файле WSDL функция может возвращать тип или элемент. До сих пор я использовал только пользовательские типы в качестве результатов. Однако мне интересно, когда элемент должен быть более подходящим, чем тип? В чем разница между ними?

Есть ли разница между

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" element="tns:Person"></wsdl:part>
</wsdl:message>

а также

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" type="tns:Person"></wsdl:part>
</wsdl:message>

с точки зрения клиента (приложение, использующее веб-службу)?

Вышеупомянутый вопрос, как указал Скаффман, приводит к другому вопросу. В чем разница между

<xs:element name="Person" ... >
 ...
</xs:element>

а также

<xs:complexType name="Person">
   ...
</xs:complexType>

?


person czuk    schedule 23.07.2009    source источник
comment
Ваш вопрос намного ценнее этих 14 голосов, по крайней мере, для меня.   -  person Farhan Shirgill Ansari    schedule 29.03.2015


Ответы (4)


Это еще не все.

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

Есть и неясности. Если вы скажете

<wsdl:message name="message1" type="ns:type1"/>

Затем вы сказали, что содержимое сообщения должно проверяться на соответствие типу ns:type1. Но вы ничего не сказали об элементе, содержащем контент. В каком пространстве имен он будет находиться?

Обратитесь к базовому профилю WS-I для получения некоторых правил по этому .


В комментариях обсуждались варианты document/literal и document/literal/wrapped. Вот мое мнение.

Я только что создал веб-сервис. Вот и все:

using System.Web.Services;

namespace WebService1
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class SimpleMathService : WebService
    {
        [WebMethod]
        public int Add(int a, int b)
        {
            return a + b;
        }

        [WebMethod]
        public int Multiply(int a, int b)
        {
            return a*b;
        }
    }
}

Я не буду публиковать весь WSDL, но вот хорошие части:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" 
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
     targetNamespace="http://tempuri.org/" xmlns:tns="http://tempuri.org/" >
    <wsdl:types>
        <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
            <s:element name="Add">
                <s:complexType>
                    <s:sequence>
                        <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int"/>
                        <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int"/>
                    </s:sequence>
                </s:complexType>
            </s:element>
            <s:element name="AddResponse">
                <s:complexType>
                    <s:sequence>
                        <s:element minOccurs="1" maxOccurs="1" 
                           name="AddResult" type="s:int"/>
                    </s:sequence>
                </s:complexType>
            </s:element>
            <s:element name="int" type="s:int"/>
        </s:schema>
    </wsdl:types>
    <wsdl:message name="AddSoapIn">
        <wsdl:part name="parameters" element="tns:Add"/>
    </wsdl:message>
    <wsdl:message name="AddSoapOut">
        <wsdl:part name="parameters" element="tns:AddResponse"/>
    </wsdl:message>
    <wsdl:portType name="SimpleMathServiceSoap">
        <wsdl:operation name="Add">
            <wsdl:input message="tns:AddSoapIn"/>
            <wsdl:output message="tns:AddSoapOut"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="SimpleMathServiceSoap" type="tns:SimpleMathServiceSoap">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="Add">
            <soap:operation soapAction="http://tempuri.org/Add" style="document"/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="SimpleMathService">
        <wsdl:port name="SimpleMathServiceSoap" binding="tns:SimpleMathServiceSoap">
            <soap:address location="http://localhost:5305/SimpleMathService.asmx"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

Обратите внимание, что слово wrap не появляется. То, что IBM в своем документе называет document/literal/wrapped, является просто документом/литералом, который использует одну часть сообщения, имеет имя, полученное из имени службы, и которое ссылается на элемент, и который содержит оба параметра операции.

Здесь нет ничего волшебного, здесь нет ничего нестандартного.

Во многих организациях по стандартизации компании встают на чью-то сторону. В случае SOAP у нас есть сторона RPC и сторона документа. Многим более привычный RPC — он сопоставляется один в один с вызовом функции. Документ менее знаком и требует, чтобы вы действительно думали с точки зрения простого XML. Возможно, IBM была на стороне RPC, я не знаю.


Я закончил работу над документом IBM «Какой стиль WSDL». Резюме:

Резюме

Есть четыре стиля привязки (на самом деле их пять, но document/encoded не имеет смысла). Хотя у каждого стиля есть свое место, в большинстве ситуаций лучший стиль — это обертка документа/литерала.


Я также хочу отреагировать на места в документе, где обсуждается уровень сложности диспетчеризации в зависимости от того, присутствует ли в сообщении имя операции. Это не проблема. Если вы прочтете документ, то заметите, что в разделе <binding> ничего не обсуждается. Решение проблемы отсутствия имени операции есть.

<wsdl:binding name="SimpleMathServiceSoap" type="tns:SimpleMathServiceSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Add">
        <soap:operation soapAction="http://tempuri.org/Add" style="document"/>

SoapAction отправляется в заголовках HTTP запроса и может использоваться для отправки:

POST /SimpleMathService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Add"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Add xmlns="http://tempuri.org/">
      <a>int</a>
      <b>int</b>
    </Add>
  </soap:Body>
</soap:Envelope>
person John Saunders    schedule 23.07.2009
comment
Итак, если я использую службу на основе RPC, все мои функции должны возвращать элемент схемы? - person czuk; 23.07.2009
comment
Я не знаю. Я не использую их. Я нахожу их проблематичными. Я всегда использую document/literal. - person John Saunders; 23.07.2009
comment
Для документа/литерала имя операции теряется. У меня есть пара функций с одинаковым набором аргументов, поэтому я не могу использовать document/literal. Несмотря на это, вы когда-нибудь использовали элемент Schema в качестве результата функции? - person czuk; 23.07.2009
comment
Я понятия не имею, почему вы думаете, что не можете использовать document/literal. Есть пример? - person John Saunders; 23.07.2009
comment
Допустим, у меня есть две функции: int add(int a, int b) и intmultiple(int a, int b). Когда клиент запускает любой из этих двух методов, генерируется одно и то же сообщение SOAP: [SOAP-ENV:Body›[a›1[/a›[b›2[/b›[/SOAP-ENV:Body› (я заменил все с [потому что они исчезли). Имя операции потеряно. Для обеих операций клиент получит одинаковый результат, потому что каждый раз будет выполняться первая операция. Таким образом, я мог бы использовать document/literal только в том случае, если бы я изменил интерфейс, объединив функции или различая их аргументы. - person czuk; 23.07.2009
comment
Ни за что. Они будут обернуты элементом на основе имени операции. Как вы создали эти сервисы? ASMX или WCF? В любом случае, я попробую прямо сейчас и покажу вам. Может быть, начать новый вопрос по этому поводу, чтобы мы не делали комментариев. - person John Saunders; 23.07.2009
comment
Только что попробовал. Без проблем. <Envelope><Body><Add><a>1</a><b>2</b></Add></Body></Envelope>. (Подсказка: окружить встроенный код символом ``) - person John Saunders; 23.07.2009
comment
Это странно. Вы уверены, что используете документ/литерал? Согласно этой статье ibm.com/developerworks/webservices/library/ws-whatwsdl В листинге 5 это сообщение rpc/literal. - person czuk; 24.07.2009
comment
Они дали плохой пример. У меня есть одна часть, называемая параметрами, которая представляет собой элемент с именем Add, представляющий собой q последовательность x и y. - person John Saunders; 24.07.2009
comment
Я понимаю. Читать дальше. Microsoft использует то, что они называют обернутым документом/литералом, как будто с этим что-то не так. Затем они почти лгут, когда говорят, что необходимо сделать обоснованное предположение. Бред какой то. Сообщение имеет часть, представляющую собой элемент, тип которого определен в схеме. Операция использует сообщение. Не нужно гадать. - person John Saunders; 24.07.2009
comment
Хорошо, но обернутый документ/литерал — это не то же самое, что документ/литерал. Я думал, ты говоришь о втором. В этой статье вы можете прочитать, что одним из недостатков документа/литерала является то, что имя операции в сообщении SOAP теряется. Без имени диспетчеризация может быть затруднена, а иногда и невозможна. - person czuk; 24.07.2009
comment
Спасибо за длинное объяснение. Насколько я понимаю, С# по умолчанию оборачивает сообщения для документа/литерала, поэтому с именем операции проблем нет. В PHP ситуация иная. При использовании SoapClient имя операции теряется, как указано в упомянутой статье. Мой вывод состоит в том, что документ/литерал в С# на самом деле является обернутым документом/литералом. В свою очередь в PHP нет никакой разницы. Как на других языках? Я не знаю этого. - person czuk; 24.07.2009

Какой из них вы используете, зависит от схемы, на которую он ссылается. Если tns:Person определен в схеме как:

<xs:element name="Person" ... >
 ...
</xs:element>

Затем вы используете

<wsdl:part name="parameters" element="tns:Person">

Если, с другой стороны, схема определяется как

<xs:complexType name="Person">
   ...
</xs:complexType>

тогда вы используете

<wsdl:part name="parameters" type="tns:Person">

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

person skaffman    schedule 23.07.2009
comment
Да, именно, я хотел бы знать, когда я должен создать тип схемы и когда элемент схемы. Или, может быть, в этом контексте нет никакой разницы? - person czuk; 23.07.2009
comment
Вам лучше не создавать ни того, ни другого, пока вы не разберетесь в этом немного лучше. А пока полагайтесь на автоматически сгенерированные файлы WSDL и схемы. - person John Saunders; 23.07.2009

Я не могу комментировать часть вопроса о WSDL, но я отвечу на часть схемы XML.

<xs:complexType> определяет тип, который описывает содержимое элемента, не описывая сам элемент (то есть его имя). <xs:element> описывает элемент (в частности, его имя), но не его тип. Однако <xs:element> всегда ссылается на тип содержимого описываемого им элемента. Это может быть ссылка на определение существующего типа (включая, помимо прочего, <xs:complexType> — это также может быть <xs:simpleType>, например) в другом месте схемы или встроенное определение <xs:complexType>:

<xs:element name="foo">
   <xs:complexType>
      ...
   </xs:complexType>
</xs:element>

Поскольку приведенная выше конструкция очень распространена, вы можете полностью опустить <xs:complexType>, и она будет подразумеваться.

Что касается того, должны ли вы всегда определять типы отдельно, а затем ссылаться на них в объявлениях элементов, или же вы должны предпочтительнее определять типы элементов внутри объявлений элементов, это вопрос стиля.

person Pavel Minaev    schedule 23.07.2009
comment
По словам Скаффмана, можно назвать complexType. Итак, в чем разница между именованием complexType и обертыванием типа element? - person czuk; 24.07.2009
comment
Если вы назовете его, вы сможете применить его к нескольким различным объявлениям элементов и/или получить от него другие типы. Таким образом, вы можете иметь комплексный тип Person, производный от него комплексный тип Employee путем расширения (добавляя дополнительные дочерние элементы для описания атрибутов), а затем назначать эти типы, например, элементам Person и Employee. - person Pavel Minaev; 24.07.2009

<xs:element name="person" type="persontype"/>

<xs:complexType name="persontype">
  <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

атрибут <element> из type ссылается на атрибут <complexType> из name.


<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" element="tns:person"></wsdl:part>
</wsdl:message>

а также

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" type="tns:person"></wsdl:part>
</wsdl:message>
  • Параметр <part> связан с конкретным типом, определенным в элементе контейнера <types>. и <part> может относиться либо к <complexType> по атрибуту type, либо к <element> по атрибуту элемента, как показано выше.
  • Это может быть либо <complexType>, либо <portType>, либо любые, на которые ссылается атрибут type.
person Premraj    schedule 08.11.2017