在2010年之前,XML是最流行的数据交换标准,直至今天,仍然有许多系统使用XML交换数据。NewLife.Core 很早就提供了XML序列化支持,主要用于配置文件。

Nuget包:NewLife.Core

源码:https://github.com/NewLifeX/X/tree/master/NewLife.Core/Serialization/Xml

视频:https://www.bilibili.com/video/BV1NN4y1P7B8


基本用法

NewLife.Serialization.Xml 类主要成员如下:

/// <summary>深度</summary>
public Int32 Depth { get; set; }

/// <summary>处理器列表</summary>
public List<IXmlHandler> Handlers { get; }

/// <summary>使用特性</summary>
public Boolean UseAttribute { get; set; }

/// <summary>使用注释</summary>
public Boolean UseComment { get; set; }

/// <summary>当前名称</summary>
public String CurrentName { get; set; }

// 写入一个对象
Boolean Write(Object value, String name = null, Type type = null);

// 读取指定类型对象
Object Read(Type type);
T Read<T>();
Boolean TryRead(Type type, ref Object value);


Xml配置文件

Xml至今仍然是很多系统配置文件的优先选择,最主要是因为它支持注释。

先来看一个SysConfig配置类的文件内容:

<?xml version="1.0" encoding="utf-8"?>
<Sys>
  <!--用于标识系统的英文名-->
  <Name>StarServer</Name>
  <!--系统版本-->
  <Version>1.0.7558.41644</Version>
  <!--用户可见的名称-->
  <DisplayName>星尘分布式服务</DisplayName>
  <!--公司-->
  <Company>新生命开发团队</Company>
  <!--应用实例。单应用多实例部署时用于唯一标识实例节点-->
  <Instance>3</Instance>
  <!--开发者模式-->
  <Develop>true</Develop>
  <!--启用-->
  <Enable>true</Enable>
  <!--安装时间-->
  <InstallTime>2020-09-10 23:08:42</InstallTime>
</Sys>

它的模型类是这样的:

/// <summary>系统设置。提供系统名称、版本等基本设置</summary>
[DisplayName("系统设置")]
[XmlConfigFile("config\\sys.config", 15_000)]
public class SysConfig : XmlConfig<SysConfig>
{
    #region 属性
    /// <summary>系统名称</summary>
    [DisplayName("系统名称")]
    [Description("用于标识系统的英文名")]
    public String Name { get; set; } = "";

    /// <summary>系统版本</summary>
    [DisplayName("系统版本")]
    public String Version { get; set; } = "";

    /// <summary>显示名称</summary>
    [DisplayName("显示名称")]
    [Description("用户可见的名称")]
    public String DisplayName { get; set; } = "";

    /// <summary>公司</summary>
    [DisplayName("公司")]
    public String Company { get; set; } = "";

    /// <summary>应用实例。单应用多实例部署时用于唯一标识实例节点</summary>
    [DisplayName("应用实例。单应用多实例部署时用于唯一标识实例节点")]
    public Int32 Instance { get; set; }

    /// <summary>开发者模式</summary>
    [DisplayName("开发者模式")]
    public Boolean Develop { get; set; } = true;

    /// <summary>启用</summary>
    [DisplayName("启用")]
    public Boolean Enable { get; set; } = true;

    /// <summary>安装时间</summary>
    [DisplayName("安装时间")]
    public DateTime InstallTime { get; set; } = DateTime.Now;
    #endregion
}

配置类需要继承 XmlConfig<T> 基类,然后直接通过静态属性Current读写。头部 XmlConfigFile 特性指定配置文件放在 config\sys.config,然后每15秒重新读取一次配置文件,确保SysConfig.Current得到最新的配置信息。

// 读取
var set = SysConfig.Current;
var name = set.Name;

// 保存
set.DisplayName = "星尘服务";
set.Save();

如果配置文件不存在,会自动创建新文件,并写入默认值;

如果配置文件字段有增减,或者注释内容有改变,下一次读写时自动覆盖;


XmlConfig基类有个 OnLoad 方法可以重载,子类通过重载 OnLoad 可以在每次加载配置文件之后,校验配置数据是否有错漏,并加以修正。

例如魔方配置文件:

        /// <summary>加载时触发</summary>
        protected override void OnLoaded()
        {
#if __CORE__
            if (StartPage.IsNullOrEmpty()) StartPage = "/Admin/User/Info";
#else
            if (StartPage.IsNullOrEmpty()) StartPage = System.Web.HttpRuntime.AppDomainAppVirtualPath.EnsureEnd("/") + "Admin/User/Info";
#endif

            var web = Runtime.IsWeb;

            //if (AvatarPath.IsNullOrEmpty()) AvatarPath = web ? "..\\Avatars" : "Avatars";
            if (DefaultRole.IsNullOrEmpty() || DefaultRole == "3") DefaultRole = "普通用户";

            if (JwtSecret.IsNullOrEmpty() || JwtSecret.Split(':').Length != 2) JwtSecret = $"HS256:{Rand.NextString(16)}";

            // 取版权信息
            if (Copyright.IsNullOrEmpty())
            {
                var asm = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly();
                if (asm != null)
                {
                    var att = asm.GetCustomAttribute<AssemblyCopyrightAttribute>();
                    if (att != null)
                    {
                        Copyright = att.Copyright;
                    }
                }
            }

            base.OnLoaded();
        }

该代码用于给部分配置属性增加默认值。


IsNew 属性用于判断是否首次新建的配置文件,当配置文件不存在,首次访问需要新建时,IsNew 为 true,其它时候都是false。


总结

当今最流行数据交换格式是Json,几乎没有新系统继续使用Xml作为数据交换。

新的配置系统独立实现了Xml读写,也不再需要这里的Xml序列化,作为兼容,只需要把基类从XmlConfig<T>修改为Config<T>即可。