四、用戶端
用戶端主要做兩件事,一是注冊通道。這一點從圖一就可以看出,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 為空數組或空引用(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;