验证使用MessageInspector WCF Web服务XML正文正文、WCF、MessageInspector、XML

2023-09-04 06:37:31 作者:小屌丝何患无妻

我有一个内置针对其使用的XmlSerializer 串行一个pre-现有的XSD架构一个WCF Web服务。

I have a built a WCF web service against a pre-existing XSD schema which uses the XmlSerializer serializer.

我想验证传入的请求和这pre-现有的模式传出请求。 MSDN 包含如何能够使用WCF MessageInspectors来完成一个工作的例子。所描述的技术包括创建一个的XmlReader 在正文内容:

I would like to validate incoming requests and outgoing requests against this pre-existing schema. MSDN contains a worked example of how this can be accomplished using WCF MessageInspectors. The technique described involves creating an XmlReader at the body contents:

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

,然后使用验证对 SchemaSet 使用 XMLDictionaryReader 此阅读器创建。

And then using validating against the SchemaSet using an XMLDictionaryReader create from this reader.

我也遇到一个问题,即我的XML主体内容包含 XSI的几个实例:类型=XSD:字符串对元素。命名空间prefixes为 XSI XSD 通过WCF对生成的主体元素,所以我的验证失败,因为 XSD 未声明的。

I have encountered a problem whereby my xml body contents contains several instances of xsi:type="xsd:string" against elements. The namespace prefixes for xsi and xsd are generated by WCF against the body element and so my validation fails due to xsd not being declared.

示例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 宣布进入人体?

推荐答案

好吧,我知道这个问题是问很久以前,但我只是在相同的问题来了,所以我想我会在这里发表我的发现。

Okay, I know this question was asked long ago but I just came across the same issue so I thought I'd post my findings here.

由于XSI和XSD的命名空间是人体元素中,message.GetReaderAtBodyContents()方法将不会返回有效的XML。我发现处理这两种方式。

Since the xsi and xsd namespaces are on the Body element, the message.GetReaderAtBodyContents() method will not return valid xml. I found two ways to deal with this.

首先,你可以用在包含XSI和XSD的命名空间,那么你可以提取该内部XML你自己的元素呼叫。这会导致使用时的命名空间为合格。

First, you can wrap the call in your own element containing the xsi and xsd namespaces then you can extract the inner xml from that. This causes the namespaces to be qualified when used.

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插入读卡器进行验证。

If you inspect the innerBody you'll see that the xsi and xsd namespaces have been qualified on each node that uses them so you can load the innerBody into a reader for validation.

二,你可以阅读整个邮件转换为XML并提取正文内容同上。这将有同样的效果如上,但将处理所有的命名空间body元素的。

Second, you can just read the entire message into xml and extract the body contents as above. This will have the same effect as above but will handle any namespaces on the Body element.

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,所以我可以提取Body元素的内部XML。将所得的xml将合格中的相同的第一种方法

Here I just loaded the entire message into a string builder then loaded that into an XmlDocument so I could extract the inner xml of the Body element. The resulting xml will be qualified the same as in the first approach.