.NET 6+中能否配置XmlSerializer接受空字符?
.NET 7中XmlSerializer兼容空字符序列化解决方案
问题背景
以下是最小复现代码:
using System; using System.IO; using System.Xml.Serialization; public class Program { public class C { public string S { get; set; } } public static void Main() { var serializer = new XmlSerializer(typeof(C)); C data = new C() { S = "a\0b" }; using (var sw = new StringWriter()) { serializer.Serialize(sw, data); Console.WriteLine(sw.ToString()); } } }
不同.NET版本表现
- 在.NET Framework 4.x 和 .NET 5中,代码会生成包含空字符转义的XML输出:
<?xml version="1.0" encoding="utf-16"?> <C xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <S>a�b</S> </C>
- 在.NET 6和7中,会抛出异常:
Unhandled exception. System.InvalidOperationException: There was an error generating the XML document. ---> System.ArgumentException: '.', hexadecimal value 0x00, is an invalid character. at System.Xml.XmlEncodedRawTextWriter.WriteElementTextBlock(Char* pSrc, Char* pSrcEnd) at System.Xml.XmlEncodedRawTextWriter.WriteString(String text) at System.Xml.XmlWellFormedWriter.WriteString(String text) at System.Xml.Serialization.XmlSerializationWriter.WriteElementString(String localName, String ns, String value, XmlQualifiedName xsiType) at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterC.Write2_C(String n, String ns, C o, Boolean isNullable, Boolean needType) at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterC.Write3_C(Object o) at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) --- End of inner exception stack trace --- at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id) at Program.Main()
空字符本身不属于XML规范中的有效字符,.NET 6+的行为变更符合规范,但如果你的场景是仅内部使用XmlSerializer序列化/反序列化,不在意XML合规性,则需要解决这个兼容性问题(已知反序列化时,给XmlTextReader设置Normalization = false即可解析转义后的空字符)。
核心需求:在.NET 7中让XmlSerializer接受空字符并生成转义后的XML
解决方案
XmlSerializer没有直接的配置项允许空字符,但可以通过自定义XmlWriter绕过有效性检查,手动处理空字符转义:
1. 自定义XmlWriter类
public class NullAllowedXmlTextWriter : XmlTextWriter { public NullAllowedXmlTextWriter(TextWriter writer) : base(writer) { } public override void WriteString(string text) { if (string.IsNullOrEmpty(text)) { base.WriteString(text); return; } int startIndex = 0; for (int i = 0; i < text.Length; i++) { char currentChar = text[i]; // 处理空字符,转义为� if (currentChar == '\0') { if (i > startIndex) base.WriteString(text.Substring(startIndex, i - startIndex)); base.WriteRaw("�"); startIndex = i + 1; } // 保留默认的XML特殊字符转义逻辑 else if (currentChar is '<' or '>' or '&' or '"' or '\'') { if (i > startIndex) base.WriteString(text.Substring(startIndex, i - startIndex)); base.WriteCharEntity(currentChar); startIndex = i + 1; } } // 写入剩余的正常字符 if (startIndex < text.Length) base.WriteString(text.Substring(startIndex)); } }
2. 使用自定义XmlWriter进行序列化
修改序列化代码,替换默认的写入器:
public static void Main() { var serializer = new XmlSerializer(typeof(C)); C data = new C() { S = "a\0b" }; using (var sw = new StringWriter()) using (var xmlWriter = new NullAllowedXmlTextWriter(sw)) { serializer.Serialize(xmlWriter, data); Console.WriteLine(sw.ToString()); } }
修改后,在.NET 7中就能生成与旧版本一致的XML输出,且能和你现有的反序列化逻辑兼容。
注意:此方式生成的XML不符合官方规范,仅适合内部自用场景,不要用于和第三方XML系统交互。
内容的提问来源于stack exchange,提问作者Heinzi
相关产品推荐
相关产品推荐

