繼上一節WCF分布式開發步步為贏(4):WCF服務可靠性傳輸配置與編程開發,本節我們繼續學習WCF分布式開發步步為贏的第(5)節:服務契約與操作重載。這裡我們首先講解OOP面向對象的編程中方法重載,重載的意義,WCF服務編程開發如何實現操作重載,隨後是代碼分析部分,給出了服務端服務契約定義和實現操作重載的注意的問題和實現過程,然後詳細介紹了客戶端實現操作重載的方式。最後是本文的總結部分。本節的結構是:【1】重載概念【2】操作重載【3】代碼實現分析【4】運行結果【5】總結
【1】重載概念:
【1.1】什麼是重載(OverLoad):
所謂重載是指同一個方法名可以對應著多個方法的實現。這些方法的名字相同,但是方法的參數的類型不同。這就是方法重載的概念。函數方法類和對象的應用尤其重要。
方法重載要求編譯器能夠唯一地確定調用一個方法時應執行哪個方法代碼,即采用哪個方法實現。確定方法實現時,要求從方法參數的個數和類型上來區分。這就是說,進行方法重載時,要求同名方法在參數個數上不同,或者參數類型上不同。否則,將無法實現重載。
關於重載一定要注意:重載方法的參數類型和參數個數一定要不同(即:要麼參數的類型不同,要麼參數的個數不同,要麼參數的類型和個數都不同),否則,編譯器就不知道該調用那個方法了。
方法重載的好處就是相同的方法,帶來不同的結果和實現,這裡我們可以根據傳遞參數的不同來決定調用飛方法。這是編譯時多態的一種實現機制。
【1.2】C#類方法重載示例:
我們這裡給出一個簡單的c#語言實現的方法重載的列子,這裡對於SayHelloOverLoading方法,同一個類裡給出的三個方法的參數個數不同。內部實現也不同。具體代碼如下:
//3.面向對象裡的類,如何實現操作重載,和WCF服務類裡的操作重載做對比
public class ClassOverLoading
{
public ClassOverLoading()
{
}
//掩飾方法重載,分別實現三個方法,C#等面向對象的語言提供了方法重載機制的支持。
public string SayHelloOverLoading()
{
//編寫代碼
return "Hello,This an C# class overloading demo";
}
//類裡的方法重載不需要別名
public string SayHelloOverLoading(string name)
{
//編寫代碼
return "Hello:" + name + "This an C# class overloading demo";
}
public string SayHelloOverLoading(string firstName, string lastName)
{
//編寫代碼
return "Hello:" + firstName + lastName + "This an C# class overloading demo";
}
}
【2】操作重載:
【2.1】操作重載:
WCF服務支持核心的Web 服務協議,同樣其元數據交換也是基於XML語言描述,客戶端通過WSDL文件來了解服務方法相關的信息,包括參數的個數、類型、返回值、調用順序等重要信息。由於WSDL不支持方法的重載,因此我們的WCF服務操作重載就無法通過WSDL暴露給客戶端。如果我們在服務契約裡定義了方法的重載,編譯可以正常通過,但是啟動服務宿主就會拋出System.InvalidOperationException異常,如下圖:
因此我們不能在WCF服務類了定義和實現方法重載,否則無法暴露為服務操作。
【2.2】解決辦法:
WCF給我們提供了一個解決辦法,讓我們可以在WCF服務類裡使用服務操作的重載。WCF定義了一個機制OperationContract,使用OperationContract特性的Name屬性,為操作指定別名:
[AttributeUsage(AttributeTargets.Method)]
public sealed class OperationContractAttribute : Attribute
{
public string Name
{get;set;}
//更多成員
}
【3】代碼實現分析:
下面我們來給出一個具體的WCF服務實現操作重載,包括服務定義、宿主配置、客戶端引用和測試的完整過程。
【3.1】服務契約:
定義了服務契約IWCFOverLoadingService,分別給出SayHelloOverLoading操作契約的3種不同定義和WCFService服務類裡的實現。具體代碼如下:
//1.服務契約,操作契約重載
[ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
public interface IWCFOverLoadingService
{
//操作契約
[OperationContract(Name = "SayHelloOverLoading1")]
string SayHelloOverLoading();
//操作契約
[OperationContract(Name = "SayHelloOverLoading2")]
string SayHelloOverLoading(string name);
//操作契約
[OperationContract(Name = "SayHelloOverLoading3")]
string SayHelloOverLoading(string firstName, string lastName);
}
//2.服務類,集成接口。實現契約
public class WCFService : IWCFOverLoadingService
{
//實現接口定義的方法
public string SayHelloOverLoading()
{
Console.WriteLine("Hello! ,This an overloading demo for WCF Service ");
return "Hello! This an overloading demo for WCF Service ";
}
//實現接口定義的方法
public string SayHelloOverLoading(string name)
{
Console.WriteLine("Hello! {0},This an overloading demo WCF Service ", name);
return "Hello! " + name + ", This an overloading demo for WCF Service ";
}
//實現接口定義的方法
public string SayHelloOverLoading(string firstName, string lastName)
{
Console.WriteLine("Hello! {0} {1},This an overloading demo WCF Service", firstName, lastName);
return "Hello! " + firstName + " " + lastName + ", This an overloading demo for WCF Service "; ;
}
}
【3.2】托管宿主:
自定義托管宿主使用配置文件來定義服務的終結點和元數據交換節點,服務的交換行為等其他屬性也在配置文件裡給出,我們配置了三種不同的數據服務通信方式,分別是http、tcp、IPC.具體配置信息如下:
<services>
<service behaviorConfiguration="WCFService.WCFServiceBehavior" name="WCFService.WCFService">
<endpoint
address="http://localhost:9001/WCFService"
binding="wsHttpBinding"
contract="WCFService.IWCFOverLoadingService">
</endpoint>
<endpoint
address="net.tcp://localhost:9002/WCFService"
binding="netTcpBinding"
contract="WCFService.IWCFOverLoadingService">
</endpoint>
<endpoint
address="net.pipe://localhost/WCFService"
binding="netNamedPipeBinding"
contract="WCFService.IWCFOverLoadingService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<endpoint address="mex" binding="mexNamedPipeBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9001/"/>
<add baseAddress="net.tcp://localhost:9002/"/>
<add baseAddress="net.pipe://localhost/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFService.WCFServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
【3.3】客戶端服務引用:
我們來分別添加對服務端的引用,首先啟動托管宿主程序。然後使用Visual Studio2008工具直接添加服務引用,你也可以使用svcUtil.exe工具,如圖所示:
客戶端輸入服務的基地址,查找服務,成功夠我們可以看到服務契約的信息,這裡顯示的3個操作名稱已經不同,實際上這裡給出的是三個不同名稱的服務方法。輸入命名空間,確定即可完成。
【3.4】代理代碼:
客戶端反序列化生成的服務契約等信息,我們查看操作契約對應的客戶端方法名稱以及改變,這樣一來,客戶端就沒有實現對應的方法重載,也就不能使用重載帶來的優勢,也即是編譯時多態的特性。手動更改客戶端服務代理類和服務契約代碼,使之支持操作方法重載,代碼如下:
public interface IWCFOverLoadingService {
[System.ServiceModel.OperationContractAttribute(Name = "SayHelloOverLoading1" ,Action="http://www.cnblogs.com/frank_xl/IWCFOverLoadingService/SayHelloOverLoading1", ReplyAction="http://www.cnblogs.com/frank_xl/IWCFOverLoadingService/SayHelloOverLoading1Respon" +
"se")]
string SayHelloOverLoading();
[System.ServiceModel.OperationContractAttribute(Name = "SayHelloOverLoading2", Action = "http://www.cnblogs.com/frank_xl/IWCFOverLoadingService/SayHelloOverLoading2", ReplyAction = "http://www.cnblogs.com/frank_xl/IWCFOverLoadingService/SayHelloOverLoading2Respon" +
"se")]
string SayHelloOverLoading(string name);
[System.ServiceModel.OperationContractAttribute(Name = "SayHelloOverLoading3", Action = "http://www.cnblogs.com/frank_xl/IWCFOverLoadingService/SayHelloOverLoading3", ReplyAction = "http://www.cnblogs.com/frank_xl/IWCFOverLoadingService/SayHelloOverLoading3Respon" +
"se")]
string SayHelloOverLoading(string firstName, string lastName);
}
這樣我們客戶端方法也支持操作方法的重載特性。
【3.5】客戶端測試代碼:
為了測試操作契約,我們在客戶端應用裡添加了部分的測試代碼,這裡為了測試服務端定義的不同的操作。我們分組按照協議給出了測試的代碼:
//實例化客戶端服務代理Tcp
ServiceOverLoadingTcp.WCFOverLoadingServiceClient wcfServiceProxyTcp =
new ServiceOverLoadingTcp.WCFOverLoadingServiceClient("WSHttpBinding_IWCFOverLoadingService1");
Console.WriteLine("Test call service using TCP--------------------.");
//通過代理調用SayHelloOverLoading服務,分別傳遞不同的參數,進行測試
Console.WriteLine(wcfServiceProxyTcp.SayHelloOverLoading());
Console.WriteLine(wcfServiceProxyTcp.SayHelloOverLoading("Frank Xu Lei"));
Console.WriteLine(wcfServiceProxyTcp.SayHelloOverLoading("Lei", "Xu"));
//實例化客戶端服務代理Http
ServiceOverLoadingHttp.WCFOverLoadingServiceClient wcfServiceProxyHttp =
new ServiceOverLoadingHttp.WCFOverLoadingServiceClient("NetTcpBinding_IWCFOverLoadingService");
Console.WriteLine("Test call service using Http-------------------");
//通過代理調用SayHelloOverLoading服務,分別傳遞不同的參數,進行測試
Console.WriteLine(wcfServiceProxyHttp.SayHelloOverLoading());
Console.WriteLine(wcfServiceProxyHttp.SayHelloOverLoading("Frank Xu Lei"));
Console.WriteLine(wcfServiceProxyHttp.SayHelloOverLoading("Lei", "Xu"));
//Debuging
Console.WriteLine("Press any key to continue");
Console.Read();
【4】運行結果:
這裡分別調用三種服務操作,進行測試。運行的結果如圖所示:
【5】總結:
以上就是本節對WCF服務操作重載的介紹,包括一般重載的基本定義和c#語言中簡單的方法重載的實現。然後介紹了WCF操作重載的實現機制、局限性和解決辦法,服務契約默認不支持操作方法重載,我們可以利用WCF已有的機制給出方法的別名來解決這個問題。然後給出了包括客戶端等完整的測試解決方案,客戶端反序列話生成服務類默認不支持服務操作方法重載的,生成的也是服務操作的別名方法。我們在客戶端要想使服務代理類支持重載,以利用重載的優勢,就需要重新修改客戶端服務代理代碼。
本文配套源碼