反射+xml 序列化 实际应用

  上一篇文章中,我记录了我初次使用反射实现一个简单的小程序,这篇文章,我就打算实现我在3天之后上班要实现的一个效果的雏形了。

  我的任务是邮件模版管理模块的开发,具体业务是 我们把系统中要使用到的各个邮件综合起来,并用wcf服务提供客户端调用,由于客户端可能要发送的邮件内容不一样,而又为了统一管理和修改模版方便,我们采用模版引擎去解析模版内容,举一个简单的例子,比如我们的 WinForm 程序有一个发送邮件给客户的功能,以前的做法是直接在这个客户端下的某个目录存放邮件模版在程序中替换占位符得到邮件内容或者干脆直接在代码里边使用字符串拼接的方式去拼接邮件内容然后调用wcf发送邮件,这样就出现了一个问题,各个邮件可能在使用一段时间后就需要针对邮件内容的样式进行修改,就好像我们的网站会有风格更换一样。如果要修改,就得到处去找(N多个子项目)并且逐个替换,也有可能同一个邮件模版在N多个项目中使用,就得重复劳动,这样非常的不方便。所以我们后来想到通过调用wcf获取邮件模版的方式,相同邮件统一去wcf段获取,并且填充邮件数据后发送。这里就牵扯到一个问题,究竟是让客户端去解析模版还是让服务端来解析,很明显,让服务端来解析要好一些,客户端只需要传递相关数据源给wcf,wcf解析后返回真实的邮件内容即可,而模版引擎和wcf的机制从某些方面来讲是一致的,它也需要相应的数据格式才能解析。我们都知道(我是后来才知道)wcf他是不能传递object类型的,模版引擎需要的object类型也是需要有数据格式的。众多的模版,怎么让引擎知道以哪种数据格式来解析模版就是一个新的问题了。

  经过老大提点,我们最终决定采用反射机制来完成这个功能,即客户端给服务器发送xml数据(数据源解析得到的),然后将数据库编译成DLL文件提交到wcf,让wcf有路可寻,所以我今天的实力就是为了实现这一一个功能。

  只是为了实现这个过程,所以wcf我也没用,只关注最需要关注的地方,首先我们看下我模拟的 客户端发送给服务器端的xml数据(该项目中我直接写在xml文件中保存)。

<?xml version="1.0" encoding="utf-8" ?>
<Root>
  <Student ID="1" Name="Eric.z.zhou" Sex="男" Age="26" />
  <Student ID="2" Name="Tom" Sex="男" Age="32" />
  <Student ID="3" Name="Jack" Sex="男" Age="28" />
  <Student ID="4" Name="Tank" Sex="男" Age="29" />
</Root>

相关DLL文件代码如下:

using System.Collections.Generic;
using System.Xml.Serialization;

namespace MyDLL
{
    [XmlRoot("Root", IsNullable = false)]
    public class Root
    {
        [XmlElement("Student")]
        public List<Student> Student { get; set; }
    }

    public class Student
    {
        [XmlAttribute("ID")]
        public int ID { get; set; }
        [XmlAttribute("Name")]
        public string Name { get; set; }
        [XmlAttribute("Sex")]
        public string Sex { get; set; }
        [XmlAttribute("Age")]
        public int Age { get; set; }
    }
}

  编译此类生成DLL文件并提交给服务器端,给定DLL路径以及数据源类型(namespace+className),然后把上边那个xml保存在服务器端的某个目录下,我这里使用 控制台应用程序模拟,所以保存在 bin 目录下,直接看服务器端如何解析:

using System;
using System.IO;
using System.Reflection;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace 反射应用实例V2
{
    class Program
    {
        static void Main(string[] args)
        {
            string xmlString = LoadFromFile();
            Console.WriteLine(xmlString);

            string DllPath = @"\dlls\";
            string DllName = "MyDLL.dll";
            Console.WriteLine("DllPath:{0} \n DLLName:{1}", DllPath, DllName);

            string BaseDirectory = AppDomain.CurrentDomain.BaseDirectory;

            Console.WriteLine("要反射的DLL路径:{0}", BaseDirectory + DllPath + DllName);

            Assembly assembly = Assembly.LoadFrom(BaseDirectory + DllPath + DllName);
            Type type = assembly.GetType("MyDLL.Root");//获得类型
            object obj = System.Activator.CreateInstance(type);

            XmlSerializer ser = new XmlSerializer(type);

            using (TextReader reader = new StringReader(xmlString))
            {
                object o = ser.Deserialize(reader);
               
            }

            Console.ReadKey();
        }

        private static string LoadFromFile()
        {
            XElement xml = XElement.Load(AppDomain.CurrentDomain.BaseDirectory + "/Resource/Students.xml");
            return xml.ToString();
        }


    }
}

结果  

  这样wcf端就拿到了带有格式的数据源,然后交给模版引起去解析处理就可以了,我开始比较好奇,反射出来的 Object 类型有原来的结构么?所以我跟踪了一下,看图:

  如图所示,它是有格式的,其实在这里,我最好还是拿模版引擎去处理一下进行验证才可以下最终结论,不过我在公司写好的模版引擎 NVeloctiy 帮助类 家里没有,而我又懒得再去写一边,所以这一步等去了公司再验证吧。

  这次试验到此结束。

posted @ 2013-04-29 10:18  西安-DB  阅读(1721)  评论(3编辑  收藏  举报