重載是物件導向編程裡面比較常見的一個問題,如下:
interface ICalculator{ int Add(int a, int b); double Add(double a, double b);}通過不同的參數列表,給出不一樣的函數簽名。但是在WCF通過interface公開服務契約的時候,有這樣一個問題。直接在這2個Add方法上添加[OperationContract]會導致異常發生。 我們來建立一個例子,服務端代碼:
interface ICalculator{ [OperationContract] int Add(int a, int b); [OperationContract] double Add(double a, double b);} ........static void Main(string[] args){ try { ServiceHost host = new ServiceHost(typeof(Calculator)); Binding wsHttpBinding = new WSHttpBinding(); host.AddServiceEndpoint(typeof(ICalculator), wsHttpBinding, new Uri("http://localhost:8086/Calculator/")); host.Open(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.Read();}在啟動self-host的時候遇到如下的異常資訊:
System.InvalidOperationException: Cannot have two operations in the same contract with the same name, methods Add and Add in type Server.ICalculator violate this rule. You can change the name of one of the operations by changing the method name or by using the Name property of OperationContractAttribute.
原因在於,基於wsdl的方法是不支援重載的,方法名是唯一的標識。WCF提供了一個解決方案,就是給[OperationContract]一個name屬性。
[ServiceContract]interface ICalculator{ [OperationContract(Name="AddInt")] int Add(int a, int b); [OperationContract(Name="AddDouble")] double Add(double a, double b);} 重新啟動self-host以後,異常不再出現。從用戶端角度來看,如果以channel的方式調用:
static void Main(string[] args){ Binding binding = new WSHttpBinding(); EndpointAddress address = new EndpointAddress("http://localhost:8086/Calculator/"); ICalculator proxy = ChannelFactory<ICalculator>.CreateChannel(binding, address); using (proxy as IDisposable) { Console.WriteLine(proxy.Add(1, 2)); Console.WriteLine(proxy.Add(1.0, 2.0)); } Console.Read();}因為是引用了ICalculator介面,用戶端也支援了物件導向語言的重載特性。但如果使用的自動產生的proxy類,會產生類似如下的類定義:
[ServiceContract]interface ICalculator{ [OperationContract] int AddInt(int a, int b); [OperationContract] double AddDouble(double a, double b);} public partial class CalculatorClient : ClientBase<ICalculator>, ICalculator{ public int AddInt(int a, int b) { return Channel.AddInt(a, b); } public int AddDouble(double a, double b) { return Channel.AddDouble(a, b); }}.....為了讓代理類也支援重載特性,可以手工的修改代理:
[ServiceContract]interface ICalculator{ [OperationContract(Name="AddInt")] int Add(int a, int b); [OperationContract(Name="AddDouble")] double Add(double a, double b);} public partial class CalculatorClient : ClientBase<ICalculator>, ICalculator{ public int Add(int a, int b) { return Channel.Add(a, b); } public int Add(double a, double b) { return Channel.Add(a, b); }}.....然後我們在調用代理類的時候,可以同使用channel一樣,使用重載特性啦。。。。
CalculatorClient proxy = new CalculatorClient ();Console.WriteLine(proxy.Add(1, 2));Console.WriteLine(proxy.Add(1.0, 2.0));proxy.Close();