简体   繁体   中英

C# design pattern for objects built using XML

I want to create a winform application in C# (.Net 4.0) which gets xml configuration file name using file dialog. I am new to design pattern and want to use it in this small application. I have read lots of examples about various design patterns but could not figure out what to use. Here is a description of this application.

This application will run various jobs. XML configuration file may contain multiple jobs. Each job contains multiple tasks. Task can be 1) Run SQL query 2) Search Text File etc and I am planning to add more tasks in the future like checking existence of file. Each task has common properties like Name, Description, Enabled. Each task also has settings specific to its own. For example "Run SQL Query" task contains connectionstring, query and query parameter in XML where as "Search Text File" task contains list of file(s) and text to search. so my resultant XML configuration file would look like this

<root>
  <jobs>
    <job>
      <name>My first job</name>
      <description>my first job log description</description>
      <tasks>
        <task>
          <name>Get employee</name>
          <description>gets a list of all employees</description>
          <type>SQLTask</type>
          <enabled>true</enabled>
          <settings>
            <connectionstring>myconnectionstring</connectionstring>
            <query>GetAllEmployees</query>
            <params>
              <param name="Dept">HR</param>
              <param name="EmpType">Permanent</param>
            </params>
          </settings>
        </task>
        <task>
          <name>Search process log</name>
          <description>searches process log for ERROR</description>
          <type>FileSearchTask</type>
          <enabled>true</enabled>
          <settings>
            <files>
              <file>c:\process\*.log</file>
              <file>c:\event\*.log</file>
            </files>
            <searchtoken>ERROR</searchtoken>
          </settings>
        </task>
      </tasks>
    </job>
    <job>ANOTHER JOB ...
    <job>
  </jobs>
</root>

This application is also responsible for creating an XML file. So I should be able to somehow save the object into XML file format as well.

Easy method that I can think of is to create an abstract class called Task with constructor taking XML as a parameter. Use TaskFactory.GetInstance(XMLDocument) to create a concrete object. In constructor of SQLTask and SearchTextFileTask (concrete object derived from Task object), it deserialize object including the setting (each task type will have its own setting object). The problem with this design would be what if I want to replace XML with for example database storage. I am not sure if I am thinking in the right direction. I would appreciate, if someone can give a stub code with all necessary classes/interfaces.

Recently I did something similar for database synchronisation between c# and a remote web server. My approach was using XML [de]serialisation and C#'s Reflection namespace to dynamically create 'unknown' classes from XML.

I am providing below some samples of this code. Unfortunately I don't think it will be exactly what you need, but hopefully it might give you some ideas, if nothing else:

Note: I created an interface called iSyncable to provide a few 'ground rules' for any classes which might need synchronising - this was also important as the sync routine checks for classes implementing this interface as a means of deciding what to send (eg if (typeof(iSyncable).IsAssignableFrom(type)) ).

The following iterates over the class 'Hook.MySql', searching for any members whose classes are 'iSyncable' in order to decide if it should serialise to XML. If found, Reflection is used to create a copy of the member/class dynamically ( dynamic cls = Activator.CreateInstance(type, Hook.MySql); ):

MemberInfo[] members = Hook.MySql.GetType().GetMembers();
foreach (MemberInfo member in members)
{
    if (member.MemberType == MemberTypes.Field) {
        fi = (FieldInfo)member;
        type = (fi).FieldType;
        if (typeof(iSyncable).IsAssignableFrom(type))
        {
            dynamic cls = Activator.CreateInstance(type, Hook.MySql);
            MemberInfo[] members2 = type.GetMembers();
            type2 = null;
            foreach (MemberInfo member2 in members2)
            {
                if (member2.Name == "Items")
                {
                    pi = (PropertyInfo)member2;
                    type2 = pi.PropertyType;
                    break;
                }
            }
            if (type2 != null)
            {
                XML = clsXml.Serialize(fi.GetValue(Hook.MySql), cls.XMLParent, type2);
            }
        }
    }
}

Obviously this is tailored somewhat to my project, but there are a number of useful techniques used which should be transferable.

This is my C# code to serialise the object created above in to XML:

public static string Serialize(dynamic o, string rootAttr, bool OmitXmlDeclaration = false, Type typeType = null)
{
    if (typeType == null) typeType = o.GetType();
    StringBuilder sb = new StringBuilder();
    XmlWriterSettings xws = new XmlWriterSettings();
    xws.OmitXmlDeclaration = OmitXmlDeclaration;
    using (XmlWriter writer = XmlWriter.Create(sb, xws))
    {
        try
        {
            new XmlSerializer(o.GetType(), null, new Type[] { typeType }, new XmlRootAttribute(rootAttr), "").Serialize(writer, o);
            //new XmlSerializer(o.GetType(), new XmlRootAttribute(rootAttr)).Serialize(writer, o);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            Console.WriteLine(e.InnerException);
            Console.WriteLine(e.StackTrace);
        }
    }
    return fstr;
}

I hope this goes some way to helping. Let me know if you need anything else.

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