Проверка тела XML веб-службы WCF с использованием MessageInspector - PullRequest
0 голосов
/ 01 февраля 2010

У меня есть встроенный веб-сервис WCF против существующей схемы XSD, в которой используется сериализатор XmlSerializer.

Я хотел бы проверить входящие и исходящие запросы по этой ранее существующей схеме. MSDN содержит рабочий пример того, как это можно сделать с помощью WCF MessageInspectors. Описанная методика включает создание XmlReader в содержимом тела:

XmlReader bodyReader = message.GetReaderAtBodyContents().ReadSubtree();

И затем с помощью проверки SchemaSet с использованием XMLDictionaryReader создания из этого считывателя.

Я столкнулся с проблемой, из-за которой содержимое моего тела xml содержит несколько экземпляров xsi:type="xsd:string" против элементов. Префиксы пространства имен для xsi и xsd генерируются WCF для элемента body, поэтому моя проверка не пройдена из-за того, что xsd не был объявлен.

Пример XML-сообщения:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
        <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://www.abc.com/Service/Response</Action>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <foo xmlns="http://www.abc.com">
            <aaa xsi:type="xsd:string">true</aaa>
        </foo>
    </s:Body>
</s:Envelope>

Ошибка проверки:

"The value 'xsd:string' is invalid according to its schema type 'QName' - 'xsd' is an undeclared namespace."

Существуют ли какие-либо параметры конфигурации WCF, которые позволяют мне вставить эти xmlns объявления в тело?

1 Ответ

1 голос
/ 18 июля 2012

Хорошо, я знаю, что этот вопрос задавался давно, но я только что столкнулся с той же проблемой, поэтому я решил опубликовать свои выводы здесь.

Поскольку пространства имен xsi и xsd находятся в элементе Body, метод message.GetReaderAtBodyContents () не будет возвращать действительный xml. Я нашел два способа справиться с этим.

Сначала вы можете заключить вызов в свой собственный элемент, содержащий пространства имен xsi и xsd, а затем извлечь из него внутренний xml. Это приводит к тому, что пространства имен уточняются при использовании.

XmlReader bodyReader = message.GetReaderAtBodyContents();
// Next we wrap the possibly invalid body contents (because of missing namespaces) into our own wrapper with the namespaces specified
XmlDocument bodyDoc = new XmlDocument();
MemoryStream bodyMS = new MemoryStream();
XmlWriter w = XmlWriter.Create(bodyMS, new XmlWriterSettings {Indent = true, IndentChars = "  ", OmitXmlDeclaration = true});
w.WriteStartElement("body");
w.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
w.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
while (xdr.NodeType != XmlNodeType.EndElement && xdr.LocalName != "Body" && xdr.NamespaceURI != "http://schemas.xmlsoap.org/soap/envelope/")
{
    if (xdr.NodeType != XmlNodeType.Whitespace)
    {
        w.WriteNode(xdr, true);
    }
    else
    {
        xdr.Read();
    }
}
w.WriteEndElement();
w.Flush();
bodyMS.Position = 0;
bodyDoc.Load(bodyMS);
XmlNode bodyNode = bodyDoc.SelectSingleNode("body");
string innerBody = bodyNode.InnerXml;

Если вы осмотрите innerBody, вы увидите, что пространства имен xsi и xsd были квалифицированы на каждом узле, который их использует, поэтому вы можете загрузить innerBody в считыватель для проверки.

Во-вторых, вы можете просто прочитать все сообщение в xml и извлечь содержимое тела, как указано выше. Это будет иметь тот же эффект, что и выше, но будет обрабатывать любые пространства имен в элементе Body.

StringBuilder sb = new StringBuilder();
using (System.Xml.XmlWriter xw = System.Xml.XmlWriter.Create(sb))
{
    message.WriteMessage(xw);
}
string theWholeMessage = sb.ToString();
XmlDocument wholeBodyDoc = new XmlDocument();
wholeBodyDoc.LoadXml(theWholeMessage);
XmlNamespaceManager wholeNS = new XmlNamespaceManager(new NameTable());
wholeNS.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
XmlNode wholeBodyNode = wholeBodyDoc.SelectSingleNode("//s:Body", wholeNS);
string innerBody = wholeBodyNode.InnerXml;

Здесь я просто загрузил все сообщение в построитель строк, а затем загрузил его в XmlDocument, чтобы я мог извлечь внутренний xml элемента Body. Полученный xml будет квалифицирован так же, как и в первом подходе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...