XmlReader повреждается на BOM UTF-8

У меня есть следующий 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 не отправляется через. В моем обработчике запросов я сериализирую объект ответа и передаю его обратно как строку. Процесс сериализации добавляет BOM UTF-8 к передней стороне строки, которая заставляет тот же код повреждаться при парсинге ответа.

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);

но не было ясно вообще из моего исследования, что BOM был недопустим в фактической строке XML; посмотрите, например, c# Обнаруживают xml, кодирующий от Массива байтов?

7
задан Community 23 May 2017 в 12:17
поделиться

4 ответа

Строка xml не должна (!) Содержать спецификацию, спецификация допускается только в байтовых данных (например, потоках), которые закодированы с помощью UTF-8. Это связано с тем, что строковое представление не закодировано, а уже представляет собой последовательность символов Юникода.

Таким образом, кажется, что вы загрузили неверную строку, которая находится в коде, который вы, к сожалению, не предоставили.

Редактировать:

Спасибо за размещение кода сериализации.

Вы должны записывать данные не в 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();
}
6
ответ дан 6 December 2019 в 14:00
поделиться

В моем обработчике запросов я сериализую объект ответа и отправляю его обратно в виде строки. Процесс сериализации добавляет спецификацию UTF-8 в начало строки, что приводит к сбою того же кода при синтаксическом анализе ответа.

Итак, вы хотите предотвратить добавление спецификации как часть процесса сериализации. К сожалению, вы не предоставляете свою логику сериализации.

Что вам нужно сделать, так это предоставить экземпляр UTF8Encoding , созданный с помощью конструктора UTF8Encoding (bool) , чтобы отключить создание спецификации, и передать этот экземпляр Encoding . к каким бы методам вы не использовали, которые генерируют вашу промежуточную строку.

9
ответ дан 6 December 2019 в 14:00
поделиться

Спецификация не должна быть в строке.
Спецификации используются для обнаружения кодировки необработанного байтового массива; им нечего делать в реальной строке.

Откуда берется струна?
Вероятно, вы читаете его с неправильной кодировкой.

0
ответ дан 6 December 2019 в 14:00
поделиться

Строки в C# кодируются как UTF-16, поэтому BOM будет неверным. Как правило, всегда кодируйте XML в байтовые массивы и декодируйте его из байтовых массивов.

0
ответ дан 6 December 2019 в 14:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: