WCF: WSDL-первый подход: проблемы с генерацией типов ошибок - PullRequest
4 голосов
/ 16 марта 2010

В настоящее время я нахожусь в процессе создания веб-сервиса WCF, который должен быть совместим с WS-I Basic Profile 1.1. Я использую подход wsdl-first (фактически впервые), определяя сначала xsd для сложных типов, WSDL, а затем использую svcutil.exe для генерации соответствующего сервера, а также интерфейсы / прокси на стороне клиента. Пока все отлично работает. Затем я решил добавить ошибку в мой WSDL.

Регенерация с помощью svcutil прошла успешно, но затем я заметил, что моя сгенерированная ошибка не имеет свойств, которые я определил в своем файле xsd (который импортируется моим WSDL).

комплексный тип данных xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:tns="http://myprod.services.mycompany.com/groups_v1.xsd"
    targetNamespace="http://myprod.services.mycompany.com/groupsfault_v1.xsd">

    <xsd:complexType name="groupsFault">
        <xsd:sequence>
            <xsd:element name="code" type="xsd:int"/>
            <xsd:element name="message" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>

</xsd:schema>

Определение ошибки XSD

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:tns="http://myprod.services.mycompany.com/groups_v1.xsd"
    targetNamespace="http://myprod.services.mycompany.com/groups_v1.xsd">

    <xsd:complexType name="group">
        <xsd:sequence>
            <xsd:element name="groupDescD" type="xsd:string" />
            <xsd:element name="groupDescI" type="xsd:string" />
            <xsd:element name="groupProtNr" type="xsd:string" />
        </xsd:sequence>
    </xsd:complexType>

</xsd:schema>

WSDL с использованием обоих вышеуказанных XSD

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions name="Groups_v1.wsdl"
    targetNamespace="http://myprod.services.mycompany.com/groups_v1.wsdl"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://myprod.services.mycompany.com/groups_v1.wsdl"
    xmlns:fault="http://myprod.services.mycompany.com/groupsfault_v1.xsd"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <wsdl:types>
        <xsd:schema targetNamespace="http://myprod.services.mycompany.com/groups_v1.wsdl"
                xmlns="http://www.w3.org/2001/XMLSchema"
                xmlns:groups="http://myprod.services.mycompany.com/groups_v1.xsd">

            <import namespace="http://myprod.services.mycompany.com/groups_v1.xsd" schemaLocation="./Groups.xsd"/>
            <import namespace="http://myprod.services.mycompany.com/groupsfault_v1.xsd" schemaLocation="./GroupsFault.xsd"/>

            <xsd:element name="getGroupList">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="StationProtNr" type="xsd:string" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            <xsd:element name="getGroupListResponse">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element maxOccurs="unbounded" name="group" type="groups:group" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>

            <xsd:element name="groupsFault">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="groupsFault" type="fault:groupsFault"/>
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>

        </xsd:schema>
    </wsdl:types>
    <wsdl:message name="getGroupList">
        <wsdl:part element="tns:getGroupList" name="parameters" />
    </wsdl:message>
    <wsdl:message name="getGroupListResponse">
        <wsdl:part element="tns:getGroupListResponse" name="parameters" />
    </wsdl:message>

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

    <wsdl:portType name="Groups_v1">
        <wsdl:operation name="getGroupList">
            <wsdl:input name="getGroupList" message="tns:getGroupList"/>
            <wsdl:output name="getGroupListResponse" message="tns:getGroupListResponse"/>
            <wsdl:fault name="getGroupListFault" message="tns:groupsFault" />
        </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="Groups_v1_SOAPBinding" type="tns:Groups_v1">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="getGroupList">
            <soap:operation soapAction="http://myprod.services.mycompany.com/groups_v1/getGroupList" />
            <wsdl:input name="getGroupList">
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output name="getGroupListResponse">
                <soap:body use="literal" />
            </wsdl:output>
            <wsdl:fault name="getGroupListFault">
                <soap:fault name="getGroupListFault" use="literal"/>
            </wsdl:fault>
        </wsdl:operation>
    </wsdl:binding>


    <wsdl:service name="getGroupList">
        <wsdl:port binding="tns:Groups_v1_SOAPBinding" name="GroupsSOAP">
            <soap:address location="http://myprod.services.mycompany.com/groups_v1" />
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

Сгенерированный .Net объект сбоя

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Xml.Serialization.XmlSchemaProviderAttribute("ExportSchema")]
[System.Xml.Serialization.XmlRootAttribute(IsNullable=false)]
public partial class groupFault : object, System.Xml.Serialization.IXmlSerializable
{

    private System.Xml.XmlNode[] nodesField;

    private static System.Xml.XmlQualifiedName typeName = new System.Xml.XmlQualifiedName("groupFault", "http://sicp.services.siag.it/groups_v1.wsdl");

    public System.Xml.XmlNode[] Nodes
    {
        get
        {
            return this.nodesField;
        }
        set
        {
            this.nodesField = value;
        }
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        this.nodesField = System.Runtime.Serialization.XmlSerializableServices.ReadNodes(reader);
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        System.Runtime.Serialization.XmlSerializableServices.WriteNodes(writer, this.Nodes);
    }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public static System.Xml.XmlQualifiedName ExportSchema(System.Xml.Schema.XmlSchemaSet schemas)
    {
        System.Runtime.Serialization.XmlSerializableServices.AddDefaultSchema(schemas, typeName);
        return typeName;
    }
}

Это нормально ?? Я ожидал бы создать объект, который содержит свойства для "кода" и "сообщения" s.t. затем вы можете бросить его, используя что-то вроде

...
throw new FaultException<groupFault>(new groupFault { code=100, message="error" });
...

(извините за определения типов в нижнем регистре, но это сгенерированный код из WSDL)

Почему svcutil.exe не генерирует эти свойства ?? Некоторые источники в Интернете предложили добавить параметр / useSerializerForFaults в svcutil. Я попробовал это, это не работает, давая мне исключение, что тип ошибки отсутствует в объявлении wsdl:portType. Однако проверка с использованием нескольких других инструментов прошла успешно.

Мой вывод из командной строки (может быть, это поможет кому-то выявить какие-либо проблемы):

C:\>svcutil /out:IGroupsServi
ce.cs /n:*,MyCompany.MyProduct.MyModule /UseSerializerForFaults *.wsdl *.xsd
Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation.  All rights reserved.

Error: Cannot import wsdl:portType
Detail: An exception was thrown while running a WSDL import extension: System.Se
rviceModel.Description.XmlSerializerMessageContractImporter
Error: The datatype 'http://myprod.services.mycompany.com/groups_v1.wsdl:groupsFault' is
 missing.
XPath to Error Source: //wsdl:definitions[@targetNamespace='http://myprod.services.mycompany.com/groups_v1.wsdl']/wsdl:portType[@name='Groups_v1']


Error: Cannot import wsdl:binding
Detail: There was an error importing a wsdl:portType that the wsdl:binding is de
pendent on.
XPath to wsdl:portType: //wsdl:definitions[@targetNamespace='http://myprod.services.mycompany.com/groups_v1.wsdl']/wsdl:portType[@name='Groups_v1']
XPath to Error Source: //wsdl:definitions[@targetNamespace='http://myprod.services.mycompany.com/groups_v1.wsdl']/wsdl:binding[@name='Groups_v1_SOAPBinding']


Error: Cannot import wsdl:port
Detail: There was an error importing a wsdl:binding that the wsdl:port is depend
ent on.
XPath to wsdl:binding: //wsdl:definitions[@targetNamespace='http://myprod.services.mycompany.com/groups_v1.wsdl']/wsdl:binding[@name='Groups_v1_SOAPBinding']
XPath to Error Source: //wsdl:definitions[@targetNamespace='http://myprod.services.mycompany.com/groups_v1.wsdl']/wsdl:service[@name='getGroupList']/wsdl:port[@name='Gr
oupsSOAP']


Generating files...
Warning: No code was generated.
If you were trying to generate a client, this could be because the metadata docu
ments did not contain any valid contracts or services
or because all contracts/services were discovered to exist in /reference assembl
ies. Verify that you passed all the metadata documents to the tool.

Warning: If you would like to generate data contracts from schemas make sure to
use the /dataContractOnly option.

C:\>

Любая помощь ОЧЕНЬ приветствуется :) thx

Ответы [ 2 ]

2 голосов
/ 11 мая 2010

Я думаю, что ваша проблема в том, что вам нужно добавить elementFormDefault = "qualified" в качестве атрибута в часть схемы xsd: вашего wsdl. Это сработало для меня.

2 голосов
/ 16 марта 2010

Я могу привести пример ошибки, которая корректно генерируется для меня через svcutil (с / useSerializerForFaults):

<xsd:schema targetNamespace="http://myproduct.mycompany.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
  <xsd:complexType name="MyError">
    <xsd:sequence>
      <!-- other stuff -->
      <xsd:element name="description" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

Возможно ли, что вам просто не хватает пространства имен для ваших типов?

Это сгенерированный код:

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.2152")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://myproduct.mycompany.com/")]
public partial class MyError
{

  // other stuff

  private string descriptionField;

  /// <remarks/>
  [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
  public string description
  {
    get
    {
      return this.descriptionField;
    }
    set
    {
      this.descriptionField = value;
    }
  }
}

И это мой полный оператор строки svcutil cmd (обратите внимание, что я генерирую ссылку на службу для данной существующей службы - но это не должно сильно влиять на генерацию кода):

svcutil /t:code /out:C:\MyRepository\GeneratedCode\MyServiceReference.cs /n:*,myproduct.mycompany.servicereference /UseSerializerForFaults C:\MyRepository\*.wsdl C:\MyRepository\*.xsd /config:C:\MyRepository\GeneratedCode\MyServiceReference.config
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...