通过AppDomain

时间:2017-07-06 03:12:25

标签: c# .net serialization appdomain remoting

我有一个插件系统,插件本身可以有多个运行时实例。这些实例是通过各种API为插件本身提供的配置对象定义的。

配置包含父应用程序理解的特定部分,但插件需要通过子类化来指定自己的部分。

[Serializable]
public class PluginConfiguration {
    public string Name { get; set; }
}

public class MyPluginConfiguration : PluginConfiguration {
    public string AccessToken { get; set; }
}

这部分是技术原因,因为它允许主应用程序将整个对象序列化为JSON / XML /等。进入数据库以保持常见配置和插件特定配置。

每个插件都托管在自己的AppDomain中。但是,当我尝试从主应用程序域和插件中读取插件配置时,我遇到了麻烦(MarshalByRefObject返回其MyPluginConfiguration对象实例。

有没有办法在基类中执行一些序列化魔术,以确保将对象实例序列化为PluginConfiguration个实例?序列化MyPluginConfiguration实例的问题是:

  • 自定义配置类型可能不是[Serializable]
  • 即使他们是[Serializable],他们仍然没有在主应用程序域中加载他们的程序集。

理想情况下,我希望将实现限制为PluginConfiguration基类。旧的[Serializable]语义和AppDomains不是.Net中最常见的概念,如果他们不需要处理它们,我想隐藏其中一些方面的内容。

1 个答案:

答案 0 :(得分:0)

根据[Serializable]

使用二进制序列化

注意:XML有IXmlSerializable 和Javascript也不同。我相信JSON.net将ISerializable对象序列化为

下面实现的
[Serializable]
public class PluginConfiguration : System.Runtime.Serialization.ISerializable
{
    public string Name { get; set; }
    public PluginConfiguration()
    {

    }
    protected PluginConfiguration(SerializationInfo info, StreamingContext context)
    {
        if (info == null)
            throw new System.ArgumentNullException("info");
        Name = (string)info.GetValue("Name", typeof(string));

    }
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Name", Name);
    }

}

[Serializable]
public class MyPluginConfiguration : PluginConfiguration
{
    public string AccessToken { get; set; }
    public MyPluginConfiguration()
    {

    }
    protected MyPluginConfiguration(SerializationInfo info, StreamingContext context) :base(info, context)
    {

    }

}

private class PluginBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        return typeof(PluginConfiguration);
    }
}

用法:

var c = new PluginConfiguration() { Name = "Name" };
var p = new MyPluginConfiguration() { Name = "Name", AccessToken = "MyToken" };

BinaryFormatter fmt = new BinaryFormatter();

MemoryStream cms = new MemoryStream();
fmt.Serialize(cms, c);

cms.Position = 0;
PluginConfiguration revc = fmt.Deserialize(cms) as PluginConfiguration;

MemoryStream pms = new MemoryStream();
fmt.Serialize(pms, p);
pms.Position = 0;
MyPluginConfiguration prev = fmt.Deserialize(pms) as MyPluginConfiguration;

//given a stream containing the serialization of MyPluginConfiguration
// serailize it as a the known PluginConfiguration Type

pms.Position = 0;
fmt.Binder = new PluginBinder();
PluginConfiguration PluginFromCustomStream = fmt.Deserialize(pms) as PluginConfiguration;