二、遠端對象的定義
前面講到,用戶端在擷取伺服器端對象時,并不是獲得實際的服務端對象,而是獲得它的引用。是以在Remoting中,對于遠端對象有一些必須的定義規範要遵循。
由于Remoting傳遞的對象是以引用的方式,是以所傳遞的遠端對象類必須繼承MarshalByRefObject。MSDN對MarshalByRefObject的說明是:MarshalByRefObject 是那些通過使用代理交換消息來跨越應用程式域邊界進行通信的對象的基類。不是從 MarshalByRefObject 繼承的對象會以隐式方式按值封送。當遠端應用程式引用一個按值封送的對象時,将跨越遠端處理邊界傳遞該對象的副本。因為您希望使用代理方法而不是副本方法進行通信,是以需要繼承MarshallByRefObject。
以下是一個遠端對象類的定義:
public class ServerObject:MarshalByRefObject { public Person GetPersonInfo(string name,string sex,int age) { Person person = new Person(); person.Name = name; person.Sex = sex; person.Age = age; return person; } } |
這個類隻實作了最簡單的方法,就是設定一個人的基本資訊,并傳回一個Person類對象。注意這裡傳回的Person類。由于這裡所傳遞的Person則是以傳值的方式來完成的,而Remoting要求必須是引用的對象,是以必須将Person類序列化。
是以,在Remoting中的遠端對象中,如果還要調用或傳遞某個對象,例如類,或者結構,則該類或結構則必須實作串行化Attribute[SerializableAttribute]:
[Serializable] public class Person { public Person() {} private string name; private string sex; private int age; public string Name { get {return name;} set {name = value;} } public string Sex { get {return sex;} set {sex = value;} } public int Age { get {return age;} set {age = value;} } } |
将該遠端對象以類庫的方式編譯成Dll。這個Dll将分别放在伺服器端和用戶端,以添加引用。
在Remoting中能夠傳遞的遠端對象可以是各種類型,包括複雜的DataSet對象,隻要它能夠被序列化。遠端對象也可以包含事件,但伺服器端對于事件的處理比較特殊,我将在本系列之三中介紹。
三、伺服器端
根據第一部分所述,根據激活模式的不同,通道類型的不同伺服器端的實作方式也有所不同。大體上說,伺服器端應分為三步:
1、注冊通道
要跨越應用程式域進行通信,必須實作通道。如前所述,Remoting提供了IChannel接口,分别包含TcpChannel和HttpChannel兩種類型的通道。這兩種類型除了性能和序列化資料的格式不同外,實作的方式完全一緻,是以下面我們就以TcpChannel為例。
注冊TcpChannel,首先要在項目中添加引用“System.Runtime.Remoting”,然後using名字空間:System.Runtime.Remoting.Channel.Tcp。代碼如下:
TcpChannel channel = new TcpChannel(8080); ChannelServices.RegisterChannel(channel); |
在執行個體化通道對象時,将端口号作為參數傳遞。然後再調用靜态方法RegisterChannel()來注冊該通道對象即可。
2、注冊遠端對象
注冊了通道後,要能激活遠端對象,必須在通道中注冊該對象。根據激活模式的不同,注冊對象的方法也不同。
(1) SingleTon模式
對于WellKnown對象,可以通過靜态方法RemotingConfiguration.RegisterWellKnownServiceType()來實作:
RemotingConfiguration.RegisterWellKnownServiceType(typeof(ServerRemoteObject.ServerObject), "ServiceMessage",WellKnownObjectMode.SingleTon); |
(2)SingleCall模式
注冊對象的方法基本上和SingleTon模式相同,隻需要将枚舉參數WellKnownObjectMode改為SingleCall就可以了。
RemotingConfiguration.RegisterWellKnownServiceType(typeof(ServerRemoteObject.ServerObject), "ServiceMessage",WellKnownObjectMode.SingleCall); |
(3)用戶端激活模式
對于用戶端激活模式,使用的方法又有不同,但差別不大,看了代碼就一目了然。
RemotingConfiguration.ApplicationName = "ServiceMessage"; RemotingConfiguration.RegisterActivatedServiceType(typeof(ServerRemoteObject.ServerObject)); |
為什麼要在注冊對象方法前設定ApplicationName屬性呢?其實這個屬性就是該對象的URI。對于WellKnown模式,URI是放在RegisterWellKnownServiceType()方法的參數中,當然也可以拿出來專門對ApplicationName屬性指派。而RegisterActivatedServiceType()方法的重載中,沒有ApplicationName的參數,是以必須分開。
3、登出通道
如果要關閉Remoting的服務,則需要登出通道,也可以關閉對通道的監聽。在Remoting中當我們注冊通道的時候,就自動開啟了通道的監聽。而如果關閉了對通道的監聽,則該通道就無法接受用戶端的請求,但通道仍然存在,如果你想再一次注冊該通道,會抛出異常。
//獲得目前已注冊的通道; IChannel[] channels = ChannelServices.RegisteredChannels; //關閉指定名為MyTcp的通道; foreach (IChannel eachChannel in channels) { if (eachChannel.ChannelName == "MyTcp") { TcpChannel tcpChannel = (TcpChannel)eachChannel; //關閉監聽; tcpChannel.StopListening(null); //登出通道; ChannelServices.UnregisterChannel(tcpChannel); } } |
代碼中,RegisterdChannel屬性獲得的是目前已注冊的通道。在Remoting中,是允許同時注冊多個通道的,這一點會在後面說明。
轉載于:https://www.cnblogs.com/goody9807/archive/2007/07/03/800300.html