四、用戶端
用戶端主要做兩件事,一是註冊通道。這一點從圖一就可以看出,Remoting中伺服器端和用戶端都必須通過通道來傳遞訊息,以獲得遠程對象。第二步則是獲得該遠程對象。
1、註冊通道:
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel);
注意在用戶端執行個體化通道時,是調用的預設建構函式,即沒有傳遞連接埠號碼。事實上,這個連接埠號碼是缺一不可的,只不過它的指定被放在後面作為了Uri的一部分。
2、獲得遠程對象。
與伺服器端相同,不同的啟用模式決定了用戶端的實現方式也將不同。不過這個區別僅僅是WellKnown啟用模式和用戶端啟用模式之間的區別,而對於SingleTon和SingleCall模式,用戶端的實現完全相同。
(1) WellKnown啟用模式
要獲得伺服器端的知名遠程對象,可通過Activator進程的GetObject()方法來獲得:
ServerRemoteObject.ServerObject serverObj = (ServerRemoteObject.ServerObject)Activator.GetObject( typeof(ServerRemoteObject.ServerObject), "tcp://localhost:8080/ServiceMessage"); |
首先以WellKnown模式啟用,用戶端獲得對象的方法是使用GetObject()。其中參數第一個是遠程對象的類型。第二個參數就是伺服器端的uri。如果是http通道,自然是用http://localhost:8080/ServiceMessage了。因為我是用本地機,所以這裡是localhost,你可以用具體的伺服器IP地址來代替它。連接埠必須和伺服器端的連接埠一致。後面則是伺服器定義的遠程物件服務名,即ApplicationName屬性的內容。
(2) 用戶端啟用模式
如前所述,WellKnown模式在用戶端建立對象時,只能調用預設的建構函式,上面的代碼就說明了這一點,因為GetObject()方法不能傳遞建構函式的參數。而用戶端啟用模式則可以通過自訂的建構函式來建立遠程對象。
用戶端啟用模式有兩種方法:
1) 調用RemotingConfiguration的靜態方法RegisterActivatedClientType()。這個方法傳回值為Void,它只是將遠程對象註冊在用戶端而已。具體的執行個體化還需要調用對象類的建構函式。
RemotingConfiguration.RegisterActivatedClientType( typeof(ServerRemoteObject.ServerObject), "tcp://localhost:8080/ServiceMessage"); ServerRemoteObject.ServerObject serverObj = new ServerRemoteObject.ServerObject(); |
2) 調用進程Activator的CreateInstance()方法。這個方法將建立方法參數指定類型的類對象。它與前面的GetObject()不同的是,它要在用戶端調用建構函式,而GetObject()只是獲得對象,而建立執行個體是在伺服器端完成的。CreateInstance()方法有很多個重載,我著重說一下其中常用的兩個。
a、 public static object CreateInstance(Type type, object[] args, object[] activationAttributes);
參數說明:
type:要建立的對象的類型。
args :與要調用建構函式的參數數量、順序和類型匹配的參數數組。如果 args 為空白數組或Null 參考(Visual Basic 中為 Nothing),則調用不帶任何參數的建構函式(預設建構函式)。
activationAttributes :包含一個或多個可以參與啟用的屬性的數組。
這裡的參數args是一個object[]數群組類型。它可以傳遞要建立對象的建構函式中的參數。從這裡其實可以得到一個結論:WellKnown啟用模式所傳遞的遠程對象類,只能使用預設的建構函式;而Activated模式則可以使用者自訂建構函式。activationAttributes參數在這個方法中通常用來傳遞伺服器的url。
假設我們的遠程對象類ServerObject有個建構函式:
ServerObject(string pName,string pSex,int pAge) { name = pName; sex = pSex; age = pAge; } |
那麼實現的代碼是:
object[] attrs = {new UrlAttribute("tcp://localhost:8080/ServiceMessage")}; object[] objs = new object[3]; objs[0] = "wayfarer"; objs[1] = "male"; objs[2] = 28; ServerRemoteObject.ServerObject = Activator.CreateInstance( typeof(ServerRemoteObject.ServerObject),objs,attrs); |
可以看到,objs[]數組傳遞的就是建構函式的參數。
b、public static ObjectHandle CreateInstance(string assemblyName, string typeName, object[] activationAttribute);
參數說明:
assemblyName :將在其中尋找名為 typeName 的類型的程式集的名稱。如果 assemblyName 為空白引用(Visual Basic 中為 Nothing),則搜尋正在執行的程式集。
typeName:首選類型的名稱。
activationAttributes :包含一個或多個可以參與啟用的屬性的數組。
參數說明一目瞭然。注意這個方法傳回值為ObjectHandle類型,因此代碼與前不同:
object[] attrs = {new UrlAttribute("tcp://localhost:8080/EchoMessage")}; ObjectHandle handle = Activator.CreateInstance("ServerRemoteObject", "ServerRemoteObject.ServerObject",attrs); ServerRemoteObject.ServerObject obj = (ServerRemoteObject.ServerObject)handle.Unwrap(); |
這個方法實際上是調用的預設建構函式。ObjectHandle.Unwrap()方法是返回被封裝的對象。
說明:要使用UrlAttribute,還需要在命名空間中添加:using System.Runtime.Remoting.Activation;