zoukankan      html  css  js  c++  java
  • 使用 JointCode.Shuttle 进行跨 AppDomain 通信的一个简单示例

    JointCode.Shuttle 是一个用于进程内 AppDomain 间通信的服务架构(不支持跨进程),它旨在取代运行时库提供的 MarshalByrefObject 的功能。

    本文通过一个简单的示例来演示如何使用 JointCode.Shuttle。

    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 复制到此文件夹)。

    开始编码

    JointCode.Shuttle 是面向接口编程的,所以我们首先需要编写一个服务接口(也叫服务契约),并对其应用 ServiceInterface 属性。

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

    接着编写一个实现该契约的服务类,并对其应用 ServiceClass 属性。

     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 }

     如需完整代码,请移步前往 此处 下载。

  • 相关阅读:
    01 用CE查找游戏基址
    过QQ游戏大厅的SX保护 Evil0r's Blog 博客频道 CSDN_NET
    CODE人物坐标
    显示Combobox1中怪物名称列表.txt
    模拟安键F5 SendKeys
    红蓝保护(按键模拟)
    喊话CALL
    CODE Unicode roleName_字符类型数据 人物名子
    显示人物主要信息
    捡物 call 代码注入
  • 原文地址:https://www.cnblogs.com/johnny-liu/p/7196126.html
Copyright © 2011-2022 走看看