程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF從理論到實踐(16):操作重載

WCF從理論到實踐(16):操作重載

編輯:關於.NET

本文目的:

閱讀本文,您能了解以下知識

什麼是操作重載?操作重載有什麼好處

WCF的服務端如何解決操作重載的問題?

WCF的客戶端如何解決操作重載問題?

小結

什麼是操作重載?操作重載有什麼好處

重載指的是在同一個類,接口或者結構中包含多個同名的 方法,而這些方法的參數列表或者返回值各不相同.使用它的好處在於提高模型的強壯性和通用性,使模型在一個可維護統一高度上運行,其功能和返回依賴於傳遞的參數. 在傳統的程序開發中,我們程序員經常使用這種技術,比如一個有一個功能既能夠計算兩個整數的和,又能計算兩個雙精度數的和,這樣的需求,我們往往會按下面這樣書寫代碼:

public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}

而在WCF中,還能不能這麼干呢?不能!為什麼呢?WCF中無論是服務端還是客戶端,如果單拿出來一個都是支持操作重載的,但是客戶端代理生成的依據卻是WSDL,而WSDL是不支持操作重載的,另外客戶端調用服務端的一個操作的必須先要確定兩個要素:1)操作所屬的服務是哪一個?2) 操作在服務中的名稱是什麼?這樣的話,向傳統應用程序程序那樣重載就會出現問題! 

WCF的服務端如何解決操作重載的問題?

如果按照下面的代碼來實現一個服務:

服務契約

[ServiceContract]
public interface IService
{
[OperationContract]
int Add(int a, int b);

[OperationContract]
double Add(double a, double b);
}

而服務實現為:

public class Service : IService
{
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}
}

那麼,在編譯的時候,是沒有錯誤的。此時,我們再按照下面的代碼實現一個托管:

using(ServiceHost host = new ServiceHost(typeof(Service),new Uri("net.tcp://127.0.0.1:12345")))
{
NetTcpBinding bind = new NetTcpBinding();
host.AddServiceEndpoint(typeof(IService), bind, "");
//下面代碼的目的是添加一個MeatedataExchage的EndPoint
BindingElement bindElement = new TcpTransportBindingElement();
CustomBinding metaBind = new CustomBinding(bindElement);
ServiceMetadataBehavior metaBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metaBehavior == null)
{
metaBehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metaBehavior);
}
host.AddServiceEndpoint(typeof(IMetadataExchange), metaBind, "MEX");
host.Open();
Console.WriteLine("服務已經運行!");
Console.Read();
}

隨後,我們啟動托管程序,發現代碼在運行到ServiceHost host = new ServiceHost(typeof(Service),new Uri("net.tcp://127.0.0.1:12345"))的時候,發生如下的異常:

這個異常提示我們,同一個協定之中不能存在相同的操作,在WCF中操作重載是不顯示適用的。而且問題不在於編譯階段,而在於托管階段。

但是我們能通過一些改進的手段來獲取WCF對操作重載的支持。我們先把服務契約的定義更改為如下的代碼:

[ServiceContract]
public interface IService
{
[OperationContract(Name="AddInt")]
int Add(int a, int b);

[OperationContract(Name="AddDouble")]
double Add(double a, double b);
}

此時,我們在啟動托管,發現已經能夠正常運行了

到此,我們是不是就完美的解決了WCF中關於操作重載的問題呢?不,還沒有,因為WCF既包含服務端,又包含客戶端,我們當前已經將服務端順利的運行起來了。總結一下,就說服務端不是顯示支持重載的,重載的操作各自的別名必須更不一致。

WCF的客戶端如何解決操作重載問題?

但客戶端呢?下面就來看下客戶端對操作重載的反應。

要想實現客戶端,我們創建一個Console的客戶端應用程序,然後需要用SvcUtiil.exe生成代理類,方法如下

打開Proxy.cs,我們會發現代理的代碼如下:

默認生成的代理類代碼
//------------------------------------------------------------------------------
// <auto-generated>
// 此代碼由工具生成。
// 運行庫版本:2.0.50727.1433
//
// 對此文件的更改可能會導致不正確的行為,並且如果
// 重新生成代碼,這些更改將會丟失。
// </auto-generated>
//------------------------------------------------------------------------------

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="IService")]
public interface IService
{

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/AddInt", ReplyAction="http://tempuri.org/IService/AddIntResponse")]
int AddInt(int a, int b);

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/AddDouble", ReplyAction="http://tempuri.org/IService/AddDoubleResponse")]
double AddDouble(double a, double b);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface IServiceChannel : IService, System.ServiceModel.IClientChannel
{
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class ServiceClient : System.ServiceModel.ClientBase<IService>, IService
{

public ServiceClient()
{
}

public ServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}

public ServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}

public ServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}

public ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}

public int AddInt(int a, int b)
{
return base.Channel.AddInt(a, b);
}

public double AddDouble(double a, double b)
{
return base.Channel.AddDouble(a, b);
}
}

仔細觀察代理的代碼不難發現,代理中的服務契約以及服務實現的操作與服務端定義的想比,有所更改。而且對於代理類來說,已經沒有了重載,雖然此代理類能夠被正常使用,但是卻沒有了重載的好處,如何更改代理類,才能使其也有重載是下面要研究的問題。 

我們將代理中的服務契約IService中的操作定義修改為:

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/AddInt", ReplyAction="http://tempuri.org/IService/AddIntResponse",Name="AddInt")]
int Add(int a, int b);
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/AddDouble", ReplyAction="http://tempuri.org/IService/AddDoubleResponse",Name="AddDouble")]
double Add(double a, double b);

然後將服務實現ServiceClient中的方法更改為:

public int Add(int a, int b)
{
return base.Channel.Add(a, b);
} 
public double Add(double a, double b)
{
return base.Channel.Add(a, b);
}
創建一個Console的客戶端應用程序,然後將修改後的Proxy.cs拷貝到其中,實現客戶端調用,代碼如下:

IService ws = new ServiceClient(new NetTcpBinding(), new EndpointAddress("net.tcp://127.0.0.1:12345"));
using (ws as IDisposable)
{
Console.WriteLine(ws.Add(1,2).ToString());
Console.WriteLine(ws.Add(1.3, 2.4).ToString());
}
Console.Read();

將解決方案設置為多啟動項目,並啟動托管和客戶端,出現下面的結果:

說明客戶端和服務端已經成功通訊。從上面實現客戶端的方法來看,客戶端想實現重載,也必須保證重載操作的別名要有服務端的相匹配,其各不相同。

小結

從本文可以看出,WCF編程雖然保持了大部分原有編程模式,也繼承了原有模式足夠多好的做法,但是限於分布式開發與傳統應用程序的差異,在有些細節上還是有區別的,比如本文所討論的操作重載問題,其實還有很多類似問題,比如繼承的差異,序列化的差異,處理集合的差異等等。要想真正的掌握這些問題,必須要深刻了解分布式開發的特型。加深對服務交互,類型轉換,封送等WCF架構方面的理解。以下幾點是對本文的總結:

1) 對於WCF中的服務端,對服務契約和服務實現不支持顯示的操作重載,但可以通過設置重載操作的別名來改善這種狀況

2) 對於WCF客戶端,默認情況下,生成的代理也不支持操作重載,想要改變這種狀況也必須依賴於別名。

3) 我推薦的做法是在服務端還是要用別名的方式支持操作重載,在客戶端手動更改代理類,以便也支持操作重載。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved