在契約優先的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); }
} 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了,你在配置文件裏愛怎麼配置怎麼配置