views:

946

answers:

2

Hi,

I'm currently in the process of creating a WCF webservice which should be compatible with WS-I Basic Profile 1.1. I'm using a wsdl-first approach (actually for the first time), defining first the xsd for the complex types, the WSDL and then using svcutil.exe for generating the according server as well as client-side interfaces/proxies. So far everything works fine. Then I decided to add a fault to my WSDL.

Regenerating with svcutil succeeded, but then I noticed that my generated fault doesn't have the properties I defined in my xsd file (which is imported by my WSDL).

complex data type 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"&gt;

    <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>

Fault XSD definition

<?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"&gt;

    <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 using both of the above XSDs

<?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"&gt;
    <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"&gt;

            <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>

Generated .Net fault object

[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;
    }
}

Is this ok?? I'd expect to have an object created that contains properties for "code" and "message" s.t. you can then throw it by using something like

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

(sorry for the lower-case type definitions, but this is generated code from the WSDL)

Why doesn't the svcutil.exe generate those properties?? Some sources on the web suggested to add the /useSerializerForFaults option of svcutil. I tried it, it doesn't work giving me an exception that the fault type is missing on the wsdl:portType declaration. Validation with several other tools succeeded however.

My command line output (maybe that helps for someone to identify any problems):

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:\>

Any help is VERY appreciated :) thx

+1  A: 

I can give you an example of a fault that is being correctly generated for me through svcutil (with /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>

Is it possible that you are simply missing the namespace for your types?

This is the generated code:

/// <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;
    }
  }
}

And this is my full svcutil cmd line statement (note that I am generating a service reference for a given existing service - but it shouldn't make much of a difference in terms of code generation):

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
JohnIdol
But what does it generate in this case. An object "MyError" containing a property "description"? Could you also paste the exact svcutil.exe statement?
Juri
see updated answer
JohnIdol
I tried to add the namespace definitions...still the same problem. I now included the full XSD definitions + WSDL in my question...may that helps someone
Juri
I get the same error as you at least if I try to import it :)
JohnIdol
perfect, at least not a software problem on my part. Do you maybe have a complete WSDL, XSD (with faults) definition that works perfectly for you, s.t. I can reproduce and check whats wrong with mine?? That would be great. I mean in the meantime I wrote the faults class by hand, but I'd like to know what's going on here for next time.
Juri
A: 

I think your problem is that you need to add elementFormDefault="qualified" as an attribute to the xsd:schema part of your wsdl. That worked for me.

David