使用 JointCode.Shuttle 進行跨 AppDomain 通訊的一個簡單示例

JointCode.Shuttle 是一個用於進程內 AppDomain 間通訊的服務架構(不支持跨進程),它旨在取代運行時庫提供的 MarshalByrefObject 的功能。git

本文經過一個簡單的示例來演示如何使用 JointCode.Shuttle。github

 

JointCode.Shuttle 的發行包編程

在 JointCode.Shuttle 的發行包中,包含兩個文件:JointCode.Shuttle.dll 和 JointCode.Shuttle.Library.dll,其中 JointCode.Shuttle.dll 是使用託管語言編寫的庫文件,JointCode.Shuttle.Library.dll 則是前者依賴的、使用非託管語言編寫的一個組件。緩存

 

準備工做架構

要使用 JointCode.Shuttle,咱們首先須要在項目中引用 JointCode.Shuttle.dll 這個程序集,同時要把 JointCode.Shuttle.Library.dll 複製到項目編譯以後 JointCode.Shuttle.dll 所在的文件夾中(例如,假設項目編譯後,JointCode.Shuttle.dll 被複制到 c:/projects/sampleproject 文件夾中,則須要手動將 JointCode.Shuttle.Library.dll 複製到此文件夾)。dom

 

開始編碼ide

JointCode.Shuttle 是面向接口編程的,因此咱們首先須要編寫一個服務接口(也叫服務契約),並對其應用 ServiceInterface 屬性。ui

1     [ServiceInterface]
2     public interface ISimpleService
3     {
4         string GetOutput(string input);
5     }
View Code

接着編寫一個實現該契約的服務類,並對其應用 ServiceClass 屬性。this

 1 [ServiceClass(typeof(ISimpleService), Lifetime = LifetimeEnum.Transient)]
 2     public class SimpleService : ISimpleService
 3     {
 4         public string GetOutput(string input)
 5         {
 6             return string.Format
 7                 ("SimpleService.GetOutput says: now, we are running in AppDomain: {0}, and the input passed from the caller is: {1}",
 8                     AppDomain.CurrentDomain.FriendlyName, input);
 9         }
10     }
View Code

因爲要實現跨 AppDomain 通訊,所以這裏咱們須要編寫一個用於啓動遠程服務的類,並讓該類繼承自 MarshalByRefObject。編碼

 1 public class ServiceEnd : MarshalByRefObject
 2 {
 3     // 這裏必須使用一個字段來持有 ShuttleDomain 實例的引用,由於它是當前 AppDomain 與外部 AppDomain 之間通訊的橋樑。
 4     // 若是該實例被垃圾回收,經過該實例註冊的全部服務會被註銷,且當前 AppDomain 與外部 AppDomain 之間將沒法通訊。
 5     // We need a field to keep the _shuttleDomain alive, because if it is garbage collected, we'll lose all communications
 6     // with other AppDomains.
 7     ShuttleDomain _shuttleDomain;
 8 
 9     public void RegisterServices()
10     {
11         // 註冊服務組時,須要傳遞一個 Guid 對象
12         // A Guid is needed when registering service group
13         var guid = Guid.NewGuid();
14         _shuttleDomain.RegisterServiceGroup(ref guid,
15             new ServiceTypePair(typeof(ISimpleService), typeof(SimpleService)));
16     }
17 
18     public void CreateShuttleDomain()
19     {
20         // 建立一個 ShuttleDomain
21         // Create a ShuttleDomain object
22         _shuttleDomain = ShuttleDomainHelper.Create("domain1", "domain1");
23     }
24 
25     public void DisposeShuttleDomain()
26     {
27         _shuttleDomain.Dispose();
28     }
29 }
View Code

如今,能夠開始使用 JointCode.Shuttle 了。有關使用方法,能夠參見注釋,代碼以下:

  1 class Program
  2 {
  3     const string SimpleServiceEndDll = "JoitCode.Shuttle.SimpleServiceEnd.dll";
  4     const string SimpleRemoteServiceEndType = "JoitCode.Shuttle.SimpleServiceEnd.SimpleRemoteServiceEnd2";
  5 
  6     static void Main(string[] args)
  7     {
  8         Console.WriteLine("Tests begin...");
  9 
 10         // 要使用 JointCode.Shuttle 進行跨 AppDomain 通訊,首先必須初始化 ShuttleDomain。
 11         // 這個初始化操做通常在默認 AppDomain 執行,但也能夠在其餘 AppDomain 中執行,都是同樣的。
 12         // To make cross-AppDomain communication with JointCode.Shuttle, initialize the ShuttleDomain at first.
 13         // It doesn't matter whether the initialization is done in default AppDomain or any other AppDomains, 
 14         // but it must be done before any ShuttleDomain instance is created.
 15         ShuttleDomain.Initialize();
 16 
 17         // 在默認 AppDomain 中,建立一個 ShuttleDomain。
 18         // 事實上,在須要與其餘 AppDomain 進行通訊的每一個 AppDomain 中,都要有一個且只能有一個 ShuttleDomain 對象。
 19         // 嘗試在一個 AppDomain 中建立多個 ShuttleDomain 對象時將會拋出異常。
 20         // 該對象用於與其餘 AppDomain 中的 ShuttleDomain 對象通訊。
 21         // Creating a ShuttleDomain instance in default AppDomain.
 22         // Actually, we needs one and only one ShuttleDomain instance in every AppDomain that needs to communicate 
 23         // with others. Trying to create another ShuttleDomain in the same AppDomain causes exceptions.
 24         // The ShuttleDomain instances communicates with each other across AppDomains.
 25         var str = Guid.NewGuid().ToString();
 26         var shuttleDomain = ShuttleDomainHelper.Create(str, str);
 27 
 28         if (CallServicesDefineInThisAssembly(shuttleDomain) 
 29             && CallServicesDefinedInAnotherAssembly(shuttleDomain))
 30         {
 31             Console.WriteLine("Tests completed...");
 32         }
 33         else
 34         {
 35             Console.WriteLine("Tests failed...");
 36         }
 37 
 38         shuttleDomain.Dispose();
 39 
 40         Console.Read();
 41     }
 42 
 43     static bool CallServicesDefineInThisAssembly(ShuttleDomain shuttleDomain)
 44     {
 45         Console.WriteLine();
 46         Console.WriteLine("=====================================");
 47 
 48         // 在默認 AppDomain 中建立一個子 AppDomain。
 49         // Creating a child AppDomain in default AppDomain.
 50         var serviceEnd1Domain = AppDomain.CreateDomain("ServiceEndDomain1", null, null);
 51 
 52         // 建立一個 ServiceEnd 對象以用於操做該子 AppDomain。
 53         // Creating a ServiceEnd instance for operating that child AppDomain.
 54         var serviceEnd = (ServiceEnd)serviceEnd1Domain.CreateInstanceAndUnwrap
 55             (typeof(Program).Assembly.FullName, "JoitCode.Shuttle.SimpleSample.ServiceEnd");
 56 
 57         // 在子 AppDomain 中,建立一個 ShuttleDomain 實例。
 58         // Creating a ShuttleDomain instance in the child AppDomain.
 59         serviceEnd.CreateShuttleDomain();
 60 
 61         // 在子 AppDomain 中,註冊 ISimpleService 服務。
 62         // Registering ISimpleService service in the child AppDomain.
 63         serviceEnd.RegisterServices();
 64 
 65 
 66         // 在默認 AppDomain 中,獲取子 AppDomain 中註冊的 ISimpleService 服務實例。
 67         // 目前服務實例的默認生存期爲 1 分鐘。每次調用服務方法時,服務實例的生存期延長 30 秒。
 68         // Get the ISimpleService service in default AppDomain, which is registered by the child AppDomain.
 69         // The lifetime of service is default to 1 minute, every call to the service method extends that time for 30 seconds.
 70         ISimpleService service;
 71         if (shuttleDomain.TryGetService(out service))
 72         {
 73             try
 74             {
 75                 Console.WriteLine("Currently, we are running in AppDomain {0}, " +
 76                     "and we are trying to call a remote serivce that defined in the same library...",
 77                     AppDomain.CurrentDomain.FriendlyName);
 78 
 79                 Console.WriteLine();
 80                 // 調用子 AppDomain 中註冊的 ISimpleService 服務實例的服務方法。
 81                 // Call the service method of ISimpleService service.
 82                 var output = service.GetOutput("Bingo");
 83                 Console.WriteLine(output);
 84 
 85                 Console.WriteLine();
 86             }
 87             catch
 88             {
 89                 Console.WriteLine();
 90                 Console.WriteLine("Failed to invoke the remote service method...");
 91                 return false;
 92             }
 93         }
 94         else
 95         {
 96             Console.WriteLine();
 97             Console.WriteLine("Failed to create remote service instance...");
 98             return false;
 99         }
100 
101         // 通知子 AppDomain 當即釋放 ISimpleService 服務實例,而不用等待其生存期結束。
102         // 此爲可選操做,由於即便不手動釋放 ISimpleService 服務實例,在其生命期結束之時系統也會自動釋放該實例
103         //(若是 ISimpleService 實現了 IDisposable,還會調用其 Dispose 方法)
104         // Indicating the child AppDomain to release the ISimpleService service immediately, instead of waiting for its lifetime to end.
105         // This is optional, because even if we don't do this explicitly, the ISimpleService service will still get released in the 
106         // child AppDomain automatically when its lifetime ends.
107         // And, if the ISimpleService derives from IDisposable, the Dispose method will also get called at that time.
108         shuttleDomain.ReleaseService(service);
109 
110         // 在子 AppDomain 中,釋放緩存的 ShuttleDomain 實例。這將會註銷經過該實例註冊的全部服務(在本示例中,即 ISimpleService 服務),
111         // 並切斷該 AppDomain 與全部 AppDomain 的通訊。
112         // Releasing the ShuttleDomain instance in the child AppDomain, this will unregister all services registered by that 
113         // instance, and shut down all communications between that child AppDomain and all other AppDomains.
114         serviceEnd.DisposeShuttleDomain();
115 
116         return true;
117     }
118 
119     static bool CallServicesDefinedInAnotherAssembly(ShuttleDomain shuttleDomain)
120     {
121         Console.WriteLine();
122         Console.WriteLine("=====================================");
123 
124         var remoteDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, null);
125 
126         var currentDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
127         var simpleServiceEndPath = Path.Combine(currentDir, SimpleServiceEndDll);
128         var asmName = AssemblyName.GetAssemblyName(simpleServiceEndPath);
129         var simpleRemoteServiceEnd = (SimpleRemoteServiceEnd)remoteDomain.CreateInstanceAndUnwrap
130             (asmName.FullName, SimpleRemoteServiceEndType);
131 
132         simpleRemoteServiceEnd.CreateShuttleDomain();
133         simpleRemoteServiceEnd.RegisterServices();
134 
135         ISimpleService2 service2;
136         if (shuttleDomain.TryGetService(out service2))
137         {
138             try
139             {
140                 Console.WriteLine("Trying to call a remote serivce that defined in another library from AppDomain {0}...",
141                     AppDomain.CurrentDomain.FriendlyName);
142 
143                 Console.WriteLine();
144                 // 調用子 AppDomain 中註冊的 ISimpleService2 服務實例的服務方法。
145                 // Call the service method of ISimpleService2 service.
146                 var output = service2.GetOutput("Duang");
147                 Console.WriteLine(output);
148 
149                 Console.WriteLine();
150             }
151             catch
152             {
153                 Console.WriteLine();
154                 Console.WriteLine("Failed to invoke the remote service method...");
155                 return false;
156             }
157         }
158         else
159         {
160             Console.WriteLine();
161             Console.WriteLine("Failed to create remote service instance...");
162             return false;
163         }
164 
165         simpleRemoteServiceEnd.DisposeShuttleDomain();
166         return true;
167     }
168 }

 如需完整代碼,請移步前往 此處 下載。

相關文章
相關標籤/搜索