在基於WCF開發的Web Service導出WSDL定義問題及自定義wsdl:port 名稱

         在契約優先的Web服務開發過程當中,每每是先拿到WSDL服務定義,各家開發各自的服務實現或客戶端,而後互相調用。框架

         儘管Web Service的標準已經發布不少年,但各個語言,框架對其實現仍然有差別,實際使用中仍有許多坑須要填。ide

        .NET平臺下,ASP.NET Web Service的兼容性最好,對比較複雜一點的wsdl文件更較好的生成Proxy Stub代碼,而WCF兼容性較差,遇到複雜一點的生產就會存在問題,並且從Java等平臺的客戶端調用也存在問題。但畢竟WCF很靈活,能夠嵌入到任何應用中,沒必要必須是Web應用,這一點很誘人。this

         在Web Service服務實現好之後,通常不會直接使用原來的wsdl定義文件,平臺會根據導出契約自動生成wsdl,而後客戶端會據今生成相應的Proxy訪問代碼。spa

WCF導出WSDL的坑接口

      悲催的是,在我根據WSDL生成的類,並實現相應接口後,在導出的WSDL中找不到任何方法,基本就是空的,我還覺得哪裏的配置出來問題,百思不得其解。改來改去,最後,用攢機時的最小系統法來排除,原來問題出在OperationContract裏的Action屬性,這個屬性是由WSDL文件生成代碼時自動產生的,所以不敢去改,但正是所以,致使沒法正確生成WSDL,刪掉之後,一切正常。ci

OperationContract的Action屬性本是用於控制消息的派發,基本對應WSDL裏定義的operation的名字,在一個服務裏能夠有一個方法Action=」*」來接收全部未處理的消息。開發

  [ServiceContract(Namespace="http://Microsoft.WCF.Documentation")]
  public interface ISampleService{

    [OperationContract(
      Action="http://Microsoft.WCF.Documentation/OperationContractMethod",
      Name="OCAMethod",
      ReplyAction="http://Microsoft.WCF.Documentation/ResponseToOCAMethod"
    )]
    string SampleMethod(string msg);

    [OperationContractAttribute(Action = "*")]
    void UnrecognizedMessageHandler(Message msg);
  }

至於爲什麼有他會影響我WSDL的導出,還但願高手指點。get

wsdl:port的名稱的自定義string

       本人先使用的使用Java平臺的JAX-WS實現Linux下Web Service,而後在Windows上用客戶端調用,客戶端同時本身也實現Web Service,用於回調消息。這裏問題就來了,同一個WSDL定義,在Java下面名稱是XXXServerSoap,而在WCF裏就是BasicHttpBinding_XXXServerSoap,這樣在Java裏回調的時候就失敗了,本人Java不熟,不知道Java裏爲啥不能自動取可用的port,非得指定命名。這裏最好能把BasicHttpBinding_這個前綴去掉,查了很久好像這是寫死的,BasicHttpBinding這個名字能夠改,但必須是BindingName_ServiceName這種形式。it

    惟一有的辦法就是寫一個擴展,自定義WSDL導出過程,呵呵還真有人這麼幹

    public class PortNameWsdlBehavior : IWsdlExportExtension, IEndpointBehavior
    {
        public string Name { get; set; }

        public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
        {
        }

        public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
        {
            if (!string.IsNullOrEmpty(Name))
            {
                context.WsdlPort.Name = Name;
            }
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }
    }

    public class PortNameWsdlBehaviorExtension : BehaviorExtensionElement
    {
        [ConfigurationProperty("name")]
        public string Name
        {
            get
            {
                Console.WriteLine("PortNameWsdlBehaviorExtension");
                object value = this["name"];
                return value != null ? value.ToString() : string.Empty;
            }
            set { this["name"] = value; }
        }

        public override Type BehaviorType
        {
            get { return typeof(PortNameWsdlBehavior); }
Technorati 標籤: Web Service, WCF, WSDL, Java, JAX-WS
        }

        protected override object CreateBehavior()
        {
            return new PortNameWsdlBehavior { Name = Name };
        }
    }
拷貝,粘貼。在服務配置節<system.serviceModel>中加入擴展的配置:
  <extensions>
        <behaviorExtensions>
            <add name="portName" type="<NameSpace>.PortNameWsdlBehaviorExtension, <NameSpace>, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
 </extensions>
搞定,這時候再看wsdl:port的name屬性已經變成你的binding name了,你在配置文件裏愛怎麼配置怎麼配置
相關文章
相關標籤/搜索