在契约优先的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了,你在配置文件里爱怎么配置怎么配置