zoukankan      html  css  js  c++  java
  • 某项目要调用现有的100多个DLL 三 先解决为一个类型做一个跨域的问题

    将同类的操作Wrap在同一个类型中,如以下代码:

    /// <summary>
    /// really business operation.
    /// </summary>
    [Serializable]
    public class ServiceWrapper1 : MarshalByRefObject
    {
    protected ServiceWrapper1()
    {
    }

    public virtual List<OpaOutput> GetUserDto(OpaInput input)
    {

    Console.WriteLine(AppDomain.CurrentDomain.FriendlyName
    + " Test2"); //show current domain
    OPATest test = new OPATest();
    return test.GetUserDto(input);
    }
    }
    }

    这是一个简单的wrap  用于调用另外一个dll的OPATest 类 , 同时测试一下代码是否运行在独立的域中

    构造函数变为Protected的主要原因是禁止直接通过构造函数新建wrap实例,强迫通过DefaultInstance的方式调用代码 (这样才是应用程序隔离的)

    不变成Private的原因是之后还需要有继承 如果把父类的构造函数设置为private 那么子类也构造不了

    但是在当前代码中 你应该把protected改为public 才可以正常的运行, 

    为了解决跨域的问题 将wrap类继承于 MarshalByRefObject ,

    OpaInput和 OpaOutput分别是输入输出参数 (定义在现有的dll中 为了方便开发 先暂时定义为可以序列化,真正的序列化实现的问题稍后解决)以下是他们的定义

    namespace ClassLibrary2
    {

    public class OPATest
    {
    public List<OpaOutput> GetUserDto(OpaInput input)
    {
    return new List<OpaOutput> {
    new OpaOutput() { Date=DateTime.Now },
    new OpaOutput(){Date=DateTime.Now},
    new OpaOutput(){Date=DateTime.Now},
    };
    }
    }
    [Serializable]
    public class OpaOutput
    {
    public string Name { get; set; }
    public string Content;
    public int Type;
    public DateTime Date { get; set; }
    }
    [Serializable]
    public class OpaInput
    {
    public string UserCode { get; set; }
    public string Content;
    public int? Type;
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    }
    }

    为了方便的访问跨域的dll 实现了以下类型

    [Serializable]
    public class BaseWrapper<T> : MarshalByRefObject
    {
    /// <summary>
    /// define a application domain for every T
    /// </summary>
    private static AppDomain _CurrentDomian = null;

    /// <summary>
    /// static constructor
    /// </summary>
    static BaseWrapper()
    {
    string domainName = "Application Execution Domain " + typeof(T).FullName;
    _CurrentDomian
    = AppDomain.CreateDomain(domainName, null, null);
    }

    /// <summary>
    /// forbid call constructor directly.
    /// </summary>
    protected BaseWrapper()
    {
    }

    /// <summary>
    /// singleton instance.
    /// </summary>
    public static T DefaultInstance
    {
    get
    {
    return (T)_CurrentDomian.CreateInstanceAndUnwrap(typeof(T).Assembly.FullName, typeof(T).FullName);
    }
    }

    }

    那么跨域的调用就非常简单了,并且为一个类型T维护一个ApplicationDomain

    调用代码如下所示:

    BaseWrapper<ServiceWrapper1>.DefaultInstance.GetUserDto(new ClassLibrary2.OpaInput() { Content = "123" });

    非常的简单 和原来的调用代码相比 增加的代码量一点都不多,原来的调用代码如下所示

    ServiceWrapper1 s = new ServiceWrapper1();
    s.GetUserDto(
    new ClassLibrary2.OpaInput() { Content = "123" });

    最终运行结果如下:

    Application Execution Domain ClassLibrary1.ServiceWrapper1 Test2

    说明 这个方法是在新的应用程序域中执行 

    PS:这里做了一个假设 即输入输出删除可序列化, 实际上不是所有的人声明代码的时候都会加上可序列化标签的 稍后我们来解决这个问题

    那么到目前为止 我们把所有调用外部dll的代码集中到了一部分类里面,并且隔离在不同的应用程序域来执行了

  • 相关阅读:
    WPF快速指导10:WPF中的事件及冒泡事件和隧道事件(预览事件)的区别
    改善C#程序的建议1:非用ICloneable不可的理由
    WPF快速指导5:验证
    改善C#程序的建议4:C#中标准Dispose模式的实现
    我所入选的微软技术社区电子报
    C#中new, override, virtual的具体用法
    C#中FCL迭代器模式的一点问题
    WPF快速指导3:数据绑定
    WPF快速指导2:模板
    C#高效编程话题集2(每期10话题)
  • 原文地址:https://www.cnblogs.com/PurpleTide/p/1954190.html
Copyright © 2011-2022 走看看