简体   繁体   中英

Deserialise XML Documents to .NET Objects with types from dynamically loaded assemblies

I'm working on a project whereby I have a series of configuration classes in a core assembly and I want to enable users to be able to create the instances of config objects by creating XML documents.

For this I'm thinking of creating xsd files for the base classes.

My next problem is that I have some assemblies that are loaded dynamically and not know at design time. They'd all implement a common set of interfaces.

The big question is how could I create a object graph instantiating nested types from dynamically loaded assemblies?

Eg

<mycoreobject>
  <somethings>
  <ass1:plugintype1 att="aaa"/> //implementing ISomthing from dynamically loaded assembly
  </somethings>
</mycoreobject>

The end result I'd want a core mycoreobject object with a list of ISomethings which are actually instantiated as the types from their respective assemblies.

In XAML we do something similar by defining the namespaces, each referring to a specific assembly. Where in the case of my example ass1 would be an alias for the externals assembly.

The more I'm writing this, the more I'm assuming I'm just going to have to analyse the XML content and construct the object graph manually?

Any tips, ideas or solutions welcome.

Tia

Sam

Like so?

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
public class MyBase
{
}
public class ConcreteType : MyBase
{
    [XmlAttribute("att")]
    public string Value { get; set; }
}
[XmlRoot("mycoreobject")]
public class SomeRoot
{
    public List<MyBase> Items { get; set; }
}
static class Program
{
    static void Main()
    {
        XmlAttributeOverrides xao = new XmlAttributeOverrides();
        XmlAttributes extraTypes = new XmlAttributes();
        extraTypes.XmlArray = new XmlArrayAttribute("somethings");
        // assume loaded dynamically, along with name/namespace
        extraTypes.XmlArrayItems.Add(new XmlArrayItemAttribute("plugintype1",
            typeof(ConcreteType)) { Namespace = "my-plugin-namespace" });
        xao.Add(typeof(SomeRoot), "Items", extraTypes);

        // important: need to cache and re-use "ser", or will leak assemblies
        XmlSerializer ser = new XmlSerializer(typeof(SomeRoot), xao);

        //example 1: writing
        var obj = new SomeRoot { Items = new List<MyBase> { new ConcreteType { Value = "abc" } } };
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");
        ns.Add("ass1", "my-plugin-namespace");
        ser.Serialize(Console.Out, obj, ns);

        // example 2: reading
        string xml = @"<mycoreobject xmlns:ass1=""my-plugin-namespace"">
  <somethings>
  <ass1:plugintype1 att=""aaa""/>
  </somethings>
</mycoreobject>";

        obj = (SomeRoot)ser.Deserialize(new StringReader(xml));
        var foundIt = (ConcreteType)obj.Items.Single();
        Console.WriteLine();
        Console.WriteLine(foundIt.Value); // should be "aaa"       
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM