天天看點

.Net元件程式設計之遠端調用(一)

 .Net元件程式設計之遠端調用(一)

我們知道我們寫的C#代碼是在作業系統邏輯體系結構中最上層的,然而作業系統本身是不會認識C#代碼的,它隻認識機器代碼。那我們寫的程式經過編譯後是編譯成IL的,是怎麼運作的呢?實際是在一個托管的環境下運作的,是.NET提供的支援,作業系統是不會識别IL的,這中間就需要一個橋梁:應用程式域。作業系統中的程序是資源機關,應用程式域的執行使用當然也要占用空間使用資源了,是以是實體程序承載着應用程式域的,而且這種承載關系并不是一對一的。

圖:應用程式域

.Net元件程式設計之遠端調用(一)

使用應用程式域這樣的機制,是有許多好處的。比如說用戶端在調用其他元件的時候可以建立一個應用程式域,然後在建立的應用程式域中加載元件進行操作等等,即使被調用的元件發生一些緻命的錯誤也不會導緻用戶端崩潰,有效的進行了錯誤隔離。還有一些資料互動傳輸上的性能差異等等,這裡不做詳細的闡述了。

.NET Remoting是一種基于.NET平台的分布式系統架構,所了解的就是用于資料傳輸。 說幾句它被使用的局限性很大,受到了平台的限制,當然如果僅僅是這樣是不能否定它的強大和幾乎無限擴充的架構體系,無論在哪一個環節你都可以自己來實作一些自定義的功能。會在下個篇幅稍作講解。

在.NET中用AppDoMain類來表示應用程式域,也提供了擷取目前應用程式域的方法,可以直接使用AppDoMain類的靜态屬性CurrentDomain來擷取到目前程式所在的應用程式域,這是一種方法,還額外提供一種了,就是Thread類的GetDomain()靜态方法也是可以擷取到的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<code>  </code><code>1 </code><code>namespace</code> <code>RemoteServer</code>

<code> </code><code>2   </code><code>public</code> <code>class</code> <code>class1</code>

<code> </code><code>3     {</code>

<code> </code><code>4         </code><code>private</code> <code>string</code> <code>appDoMainName;</code>

<code> </code><code>5 </code>

<code> </code><code>6         </code><code>public</code> <code>class1()</code>

<code> </code><code>7         {</code>

<code> </code><code>8             appDoMainName = AppDomain.CurrentDomain.FriendlyName;</code>

<code> </code><code>9         }</code>

<code>10 </code>

<code>11         </code><code>public</code> <code>void</code> <code>Writer()</code>

<code>12         {</code>

<code>13             Console.WriteLine(appDoMainName);</code>

<code>14         }</code>

<code>15     }</code>

class1中構造函數是擷取目前應用程式域的名稱,并且是在Writer()方法中輸出到控制台界面中,

<code>using</code> <code>RemoteServer;</code>

<code>namespace</code> <code>RemoteCase</code>

<code>{</code>

<code>            </code><code>AppDomain appDoMain = AppDomain.CurrentDomain;</code>

<code>            </code><code>class1 cls1 = (class1)appDoMain.CreateInstanceFromAndUnwrap(</code><code>"RemoteServer.dll"</code><code>, </code><code>"RemoteServer.class1"</code><code>);</code>

<code>            </code><code>cls1.Writer();</code>

<code>}</code>

圖3-1

.Net元件程式設計之遠端調用(一)

這裡使用了AppDomain中的靜态方法CreateInstanceFromAndUnwrap(),因為目前項目已經引用了RemoteServer程式集,是以第一個參數隻是一個顯示的名稱,并不是全路徑,在調用方法的時候,應用程式域會加載程式集,用于擷取到中繼資料。

<code> </code><code>1 </code><code>namespace</code> <code>RemoteServer</code>

<code> </code><code>2       </code><code>public</code> <code>class</code> <code>class1:MarshalByRefObject</code>

<code> </code><code>3       {</code>

<code>15       }</code>

<code>1 </code><code>using</code> <code>RemoteServer;</code>

<code>2 </code>

<code>3       AppDomain appDoMain = AppDomain.CurrentDomain;</code>

<code>4       AppDomain newDoMain = AppDomain.CreateDomain(</code><code>"NewDoMain"</code><code>);</code>

<code>5       class1 cls1 = (class1)newDoMain.CreateInstanceFromAndUnwrap(</code><code>"RemoteServer.dll"</code><code>, </code><code>"RemoteServer.class1"</code><code>);</code>

<code>6       cls1.Writer();</code>

圖3-2

.Net元件程式設計之遠端調用(一)

圖3-3-1

.Net元件程式設計之遠端調用(一)

這段代碼是3.2中的代碼,cls1并不是class1類型本身,而是代理,通路遠端對象都是通過代理完成的,這麼屌炸天的.NET當然提供優化,将建立遠端對象和在用戶端建立代理分離,這樣可以在你建立了一個遠端對象之後再建立代理。 AppDomain類提供了一套CreateInstance()方法來建立對象,但是都以ObjectHandle的形式傳回一個遠端對象句柄(意思就是遠端對象的唯一标示,這個句柄能代表遠端對象)

ObjectHandle對象實作了System.Runtime.Remoting命名空間下的IObjectHandle接口:

16

<code> </code><code>2 </code><code>public</code> <code>class</code> <code>class1:MarshalByRefObject</code>

<code>15 </code>

<code>16     }</code>

<code> </code><code>1 </code><code>using</code> <code>RemoteServer;</code>

<code> </code><code>2 </code>

<code> </code><code>3             AppDomain appDoMain = AppDomain.CurrentDomain;</code>

<code> </code><code>4             AppDomain newDoMain = AppDomain.CreateDomain(</code><code>"NewDoMain"</code><code>);</code>

<code> </code><code>5             IObjectHandle objecthandle;</code>

<code> </code><code>6             objecthandle = newDoMain.CreateInstance(</code><code>"RemoteServer"</code><code>, </code><code>"RemoteServer.class1"</code><code>);</code>

<code> </code><code>7 </code>

<code> </code><code>8             RemoteServer.class1 cls1 = objecthandle.Unwrap() </code><code>as</code> <code>RemoteServer.class1;</code>

<code> </code><code>9 </code>

<code>10             cls1.Writer();</code>

一般情況下是不需要手動拆包對象句柄的,這樣做的好處隻是可以推遲加載RemoteServer程式集,隻有在 objecthandle.Unwrap()的時候才會建立代理,而建立代理必須需要對象中繼資料。

一般情況下,被引用對象和用戶端同在一個應用程式域,這樣的情況下不涉及到代理,也不會用到什麼遠端調用,

而是直接引用對象,如果當你需要調用另一個應用程式域裡的對象時會是什麼樣的?預設情況下.NET是不允許對象跨應用程式域通路的,

不管是不是在同一個程序内。但是呢如果要通路,也不是不行的,.NET提供了兩種資料傳遞方式,一種是值傳遞,一種是引用傳遞

   當應用程式域A調用應用程式域B中的對象時,應用程式域B中的對象會被拷貝一個克隆到應用程式域A,這時候兩個對象是不存在任何關系的,這種情況叫做按值封送    一般情況下都是使類型使用Serializable特性,支援序列化,通過序列化來達到按值封送的目的,在被調用方序列化,到調用方反序列化。

   這種情況就是當應用程式域A調用應用程式域B的對象時,應用程式域A獲得的是應用程式域B中對象的引用,

這個引用挂在哪裡呢?挂在應用程式域A的對象代理上,這種情況就叫引用封送    引用封送就比按值封送有意思多了,想要滿足可以引用封送的要求,則對象必須繼承自MarshalByRefObject,MarshalByRefObject類型給出的解釋就是 允許在支援遠端處理的應用程式中跨應用程式域邊界通路對象,這樣作為它的子類同樣的也享受這樣的優待。在引用封送中會有兩種遠端對象激活模式,這個内容在下一個篇幅中會有詳細的示例代碼。

     本文轉自jinyuan0829 51CTO部落格,原文連結:http://blog.51cto.com/jinyuan/1422395,如需轉載請自行聯系原作者