WCF: WSDL-first approach: Problems with generating fault types
.net, c#, wcf, wsdl
Solution
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.
Problem
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"> <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"> <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"> <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> ``` 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