某项目要调用现有的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的代码集中到了一部分类里面,并且隔离在不同的应用程序域来执行了