导航

WCF------如何控制WCF应用生成的WSDL

Posted on 2009-03-31 11:14  鸡尾虾的壳  阅读(1835)  评论(0编辑  收藏  举报

技术价值:曾经在开发中,需要按照给定的wsdl提供ws实现,特别的是这个ws实现是BiztalkOrchestration发布得到的。如何保证Orchestration发布得到的ws符合预先的wsdl是一个很有挑战性的技术问题。WCF是微软在Web Service领域的升级技术。因此,这篇博客的内容对自顶向下的Web Service/WCF开发策略的实现有重要参考价值。

Original: http://www.pluralsight.com/community/blogs/kirillg/archive/2006/06/18/28380.aspx

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="MyServicetargetNamespace="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.