Control generated WSDL in WCF - Part 1. Namespaces.

How to control WSDL namespaces in WCF is a common question, so I will tackle this first. I will assume WSDL basics to be known.

WSDLs exported by WCF

WCF services by default export a tree of WSDLs, i.e. several WSDLs, imported one from another using wsdl:import construct.

This is because different WSDL elements exported by WCF service have different lifecycles: wsdl:service, wsdl:binding, wsdl:portType and schemas.  For example schemas are prescribed by vertical industry standard; contract is written once for all providers; binding is prescribed by a vertical industry standard; service is implemented by individual provider.

Each of these WSDL elements has a namespace uri associated with it. In WSDL such namespace uri is assigned by the @targetNamespace attribute on <wsdl:definitions> root that contains one of these elements. Hence there are four types of namespaces in WSDLs generated by WCF.

There is always one WSDL generated for one target namespace URI. I.e. if the namespaces uris match for wsdl:portType and wsdl:binding , these elements are bundled into the same WSDL. XML Schemas are always exported as separate documents.

Compatibility note:

wsdl:import – the construct that allows to build the WSDL tree and put wsdl:service, wsdl:binding and wsdl:portType into different namespaces - was not very well supported by early toolkits. For example if your service is required to be consumed by early versions of InfoPath or Visual Studio ATL  sproxy.exe tool, you will need to set the target namespaces for wsdl:service, wsdl:binding and wsdl:portType to the same URI.

Control WSDL Namespaces

Here is how you control target namespaces for wsdl:service, wsdl:binding , wsdl:portType and schemas. WSDL has also wsdl:message – those are bundled together with the wsdl:portType

Service namespace

This is the target namespace of the root WSDL where <wsdl:service…/> element resides containing endpoints (<wsdl:port>)

Code

Set via ServiceBehavior attribute on the service class (not the contract!)

[ServiceBehavior(Name="MyService", Namespace="http://myservice.com/",

                 ConfigurationName="MyServiceConfiguration")]

public class MyService : IMyServiceContract

default for ConfigurationName (used in config) and Name (exported name into WSDL) is the name of the class. Default for the namespace is the “http://tempuri.org”

 WSDL

<wsdl:definitions name="MyService"  targetNamespace="http://myservice.com/" …>

  ...

  <wsdl:service name="MyService">

    ...

Note, we had an unfortunate bug in RC0 that caused stack overflow when you used this setting. This is fixed in later bits.

Binding namespace

This is the target namespace for the WSDL that contains wsdl:binding elements. wsdl:binding is where WCF exports bindings together with certain serialization aspects.

Config

<services>

   <service name="MyServiceConfiguration"...>

      <endpoint name="MyServiceEndpoint"

         bindingNamespace="http://myservice.com/binding"

         contract="Namespaces.MyServiceContract" ...>

Code

Binding b = new CustomBinding();           

b.Namespace = "http://myservice.com/binding";

se = sh.AddServiceEndpoint(typeof(MyServiceContract), b, "http://myservice.com:8080");

WSDL

<wsdl:definitions targetNamespace="http://myservice.com/binding" …>

  ...

  <wsdl:binding name="MyServiceEndpoint">

    ...

Contract namespace

This is the target namespace for the WSDL that contains wsdl:portType . ServiceContract is exported there.

Code

[ServiceContract(Name = "MyServiceContract", Namespace = "http://gadgets.org/contract")]

public interface MyServiceContract {}

WSDL

<wsdl:definitions targetNamespace="http://gadgets.org/contract">

  ...

  <wsdl:portType name="MyServiceContract">

    ...

Schema namespace

DataContract types , XmlSeriazer types and wrapper elements defined by MessageContract are being exported into schemas.  Schemas namespace are set on individual DataContract , XmlSerializer or MessageContract attributes.

Code

[DataContract(Name="Order", Namespace="http://gadgets.org/types")]

public class Order

{

    [DataMember]

    public string Id;

}

[MessageContract(IsWrapped = true, WrapperNamespace="http://gadgets.org/messages")]   

public class MyServiceUpdateRequest    

{

    [MessageBodyMember(Namespace = "http://startrek.net/messages")]       

    public Order Order;

}

WSDL

wsdl:types is always put into the same WSDL as wsdl:portType. It always contains a single xsd:schema referencing all the schemas used by that portType.

<wsdl:definitions targetNamespace="http://gadgets.org/contract">

  <wsdl:types>

    <xsd:schema targetNamespace="http://gadgets.org/contract/Imports">

      <xsd:import schemaLocation="http://myservice.com:8080/?xsd=xsd0" namespace="http://gadgets.org/messages"/>

      <xsd:import schemaLocation="http://myservice.com:8080/?xsd=xsd1"

                  namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>

      <xsd:import schemaLocation="http://myservice.com:8080/?xsd=xsd2" namespace="http://gadgets.org/types"/>

    </xsd:schema>

  </wsdl:types>

  <wsdl:message name="MyServiceUpdateRequest">

    <wsdl:part name="parameters" element="q1:MyServiceUpdateRequest" xmlns:q1="http://gadgets.org/messages"/>

  </wsdl:message>

XSD

<xs:schema elementFormDefault="qualified" targetNamespace="http://gadgets.org/messages" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://gadgets.org/messages">

  <xs:import schemaLocation="http://localhost:8080/?xsd=xsd2" namespace="http://gadgets.org/types"/>

  <xs:element name="MyServiceUpdateRequest">

    <xs:complexType>

      <xs:sequence>

        <xs:element minOccurs="0" name="Order" nillable="true" type="q1:Order" xmlns:q1="http://gadgets.org/types"/>

      </xs:sequence>

    </xs:complexType>

  </xs:element>

</xs:schema>

<xs:schema elementFormDefault="qualified" targetNamespace="http://gadgets.org/types" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://gadgets.org/types">

  <xs:complexType name="Order">

    <xs:sequence/>

  </xs:complexType>

  <xs:element name="Order" nillable="true" type="tns:Order"/>

</xs:schema>

Note there is the third schema whenever you use DataContract / XmlFormatter as a formatter for your service contract. This defines several helper elements and types for certain CLR types schema representation.


Posted Jun 18 2006, 10:08 AM by kirill-gavrylyuk
Filed under:

Comments

Javier G. Lozano wrote WSDL Generation in WCF
on 06-19-2006 9:47 PM
Sam Gentile wrote New and Notable 104
on 06-24-2006 4:11 PM
You know what? Owning a pool really sucks-). Oh, it’s great to go in but not a lot of fun spending most...
TheArchitect.co.uk - Jorgen Thelin's weblog wrote Control Generated WSDL in WCF - Part 1 - Namespaces
on 06-27-2006 12:27 AM
Kirill is writing a series of postings showing how to control the contents of the WSDL generated by WCF. In Part 1 he talks about one of the most common requirements - defining which namespace will be used in the service, binding, porttype or schema definitions....
Sam Gentile wrote New and Notable 104
on 10-01-2006 1:39 AM
You know what? Owning a pool really sucks-). Oh, it&rsquo;s great to go in but not a lot of fun spending
Peterb wrote re: Control generated WSDL in WCF - Part 1. Namespaces.
on 11-14-2006 10:31 AM
Excellent post. What ever became of part 2?
Gaurav wrote re: Control generated WSDL in WCF - Part 1. Namespaces.
on 08-20-2007 1:42 PM
hi,
I'm writing a WCF token service. I wanted to add namespace for service as you mentioned above by decorating servicebehavior attribute to actual service class, but when I do that my custom servicebehavior as defined in config file does not take effect. Is there a work around? can I decorate service namespace in config file?
Gaurav wrote re: Control generated WSDL in WCF - Part 1. Namespaces.
on 08-20-2007 2:02 PM
My mistake, I did not see that the generated WSDL has import statement to another WSDL.
Travis Spencer wrote re: Control generated WSDL in WCF - Part 1. Namespaces.
on 10-05-2007 12:48 PM
Any idea how to set the namespace when the data contract being used is decorated w/ SerializableAttribute rather than DataContractAttribute? It doesn't seem possible, making the namespace http://datacontracts.org/blort/blort/blort.
Paul wrote re: Control generated WSDL in WCF - Part 1. Namespaces.
on 10-24-2007 7:05 AM
Thanks. Just resolved a headache I've had all day. Why does no one at Microsoft ever think to write a "if you want to change this in auto-generated code, edit that" type document for this stuff? Ahh, who cares, at least someone has.
Brian wrote re: Control generated WSDL in WCF - Part 1. Namespaces.
on 06-24-2008 7:17 AM
Not sure if there's a Part 2 coming, but I'm curious to know if there's a way to control whether or not the WCF generated WSDL includes xsd:import elements. I'm consuming a WCF service with Flash, which unfortunately does not support WSDL files containing xsd:import elements.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?