XmlReader在UTF-8 BOM上中断

我的应用程序中有以下XML解析代码:

public static XElement Parse(string xml, string xsdFilename) { var readerSettings = new XmlReaderSettings { ValidationType = ValidationType.Schema, Schemas = new XmlSchemaSet() }; readerSettings.Schemas.Add(null, xsdFilename); readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation; readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings; readerSettings.ValidationEventHandler += (o, e) => { throw new Exception("The provided XML does not validate against the request's schema."); }; var readerContext = new XmlParserContext(null, null, null, XmlSpace.Default, Encoding.UTF8); return XElement.Load(XmlReader.Create(new StringReader(xml), readerSettings, readerContext)); } 

我用它来解析发送到我的WCF服务的字符串到XML文档,用于自定义反序列化。

当我读入文件并通过网络发送它们时(请求),它工作正常; 我已经确认没有发送BOM。 在我的请求处理程序中,我正在序列化一个响应对象并将其作为字符串发送回来。 序列化过程将UTF-8 BOM添加到字符串的前面,这会导致在解析响应时中断相同的代码。

 System.Xml.XmlException : Data at the root level is invalid. Line 1, position 1. 

在过去一小时左右的研究中,似乎XmlReader应该遵守BOM。 如果我从字符串的前面手动删除BOM,则响应xml解析正常。

我错过了一些明显的东西,或者至少是一些阴险的东西?

编辑:这是我用来返回响应的序列化代码:

 private static string SerializeResponse(Response response) { var output = new MemoryStream(); var writer = XmlWriter.Create(output); new XmlSerializer(typeof(Response)).Serialize(writer, response); var bytes = output.ToArray(); var responseXml = Encoding.UTF8.GetString(bytes); return responseXml; } 

如果只是xml错误地包含BOM的问题,那么我将切换到

 var responseXml = new UTF8Encoding(false).GetString(bytes); 

但是根据我的研究,根本不清楚实际的XML字符串中的BOM是非法的; 请参阅例如c#从字节数组中检测xml编码?

xml字符串不得(!)包含BOM,BOM仅允许在使用UTF-8编码的字节数据(例如流)中。 这是因为字符串表示不是编码的,而是已经是一系列unicode字符。

因此,您似乎加载了错误的字符串,这是您不幸未提供的代码。

编辑:

感谢您发布序列化代码。

您不应该将数据写入MemoryStream,而应该写入StringWriter,然后可以将其转换为带有ToString的字符串。 由于这避免了通过字节表示,因此它不仅更快,而且避免了这些问题。

像这样的东西:

 private static string SerializeResponse(Response response) { var output = new StringWriter(); var writer = XmlWriter.Create(output); new XmlSerializer(typeof(Response)).Serialize(writer, response); return output.ToString(); } 

在我的请求处理程序中,我正在序列化一个响应对象并将其作为字符串发送回来。 序列化过程将UTF-8 BOM添加到字符串的前面,这会导致在解析响应时中断相同的代码。

因此,您希望防止在序列化过程中添加BOM。 不幸的是,您没有提供序列化逻辑。

您应该做的是提供通过UTF8Encoding(bool)构造函数创建的UTF8Encoding实例来禁用BOM的生成,并将此Encoding实例传递给您正在使用的生成中间字符串的任何方法。

BOM首先不应该在字符串中。
BOM用于检测原始字节数组的编码; 他们没有生意在一个实际的字符串中。

字符串是什么来的?
你可能用错误的编码读它。

C#中的字符串被编码为UTF-16,因此BOM将是错误的。 作为一般规则,始终将XML编码为字节数组并从字节数组中对其进行解码。