【问题标题】:How can I create custom XML namespace attributes when consuming a legacy SOAP service?使用旧版 SOAP 服务时,如何创建自定义 XML 命名空间属性?
【发布时间】:2015-03-30 17:01:58
【问题描述】:

我有一个旧的 Tibco SOAP 服务,我需要从中获取一些数据。不幸的是,该服务非常关注请求消息上的 XML 命名空间属性。在使用 PeopleSoft (https://en.wikipedia.org/wiki/PeopleCode) 的服务时,我也遇到过此类问题。

我从服务中获取了 .wsdl 并创建了服务引用。

开箱即用,.Net 生成的 XML 请求消息是:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <getLocation xmlns="http://customNamespaceHere">
            <context>
                <source>SysAdmin</source>
            </context>
            <Address>
                <address1>123 Main St</address1>
                <city>New York</city>
                <state>NY</state>
                <country>US</country>
            </Address>
        </getLocation>
    </s:Body>
</s:Envelope>

实际可行的是(我使用 SoapUI 解决了这个问题):

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <getLocation xmlns="http://customNamespaceHere">
            <context>
                <source>SysAdmin</source>
            </context>
            <Address>
                <address1>123 Main St</address1>
                <city>New York</city>
                <state>NY</state>
                <country>US</country>
            </Address>
        </getLocation>
    </s:Body>
</s:Envelope>

注意 body 标记中没有 xsi 和 xsd 前缀。

问:如何让 .Net 发送正确的 XML,而不是手动滚动 XML 文档并手动将其发送到服务?

【问题讨论】:

    标签: c# xml wcf soap


    【解决方案1】:

    答:通过实现 IClientMessageInspector,我能够在发送 XML 请求之前对其进行修改。

    首先我必须通过实现 IClientMessageInspector 来扩展 WCF。这使我能够访问请求对象并修改 XML 请求消息。这些类不需要在您的解决方案中的任何特定位置(据我所知)。

    public class ExtendedClientMessageInspector : IClientMessageInspector
    {
        // Here we can alter the xml request body before it gets sent out.
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            return TibcoService.ModifyGetLocationRequest(ref request);
    
        } // end
    
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            return;
    
        } //end
    
    } // end class
    
    public class ExtendedEndpointBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            return;
    
        } // end
    
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new ExtendedClientMessageInspector());
    
        } // end
    
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            return;
    
        } // end
    
        public void Validate(ServiceEndpoint endpoint)
        {
            return;
    
        } // end
    
    } // end class
    
    public class EndpointBehaviorExtensionElement : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new ExtendedEndpointBehavior();
    
        } // end
    
        public override Type BehaviorType
        {
            get
            {
                return typeof(ExtendedEndpointBehavior);
            }
    
        } // end
    
    } // end class
    

    我确实将 this 服务中专门处理 XML 的方法放在了与服务相同的类中:

    public static Message ModifyGetLocationRequest(ref Message request)
    {
        // Initialize objects
        var xmlDocument = new XmlDocument();
        var memoryStream = new MemoryStream();
        var xmlWriter = XmlWriter.Create(memoryStream);
        var xmlAttribute = xmlDocument.CreateAttribute("xmlns", "api", "http://www.w3.org/2000/xmlns/");
    
        xmlAttribute.Value = "http://customNamespaceHere";
    
        // Write the xml request message into the memory stream
        request.WriteMessage(xmlWriter);
    
        // Clear the xmlWriter
        xmlWriter.Flush();
    
        // Place the pointer in the memoryStream to the beginning 
        memoryStream.Position = 0;
    
        // Load the memory stream into the xmlDocument
        xmlDocument.Load(memoryStream);
    
        // Remove the attributes from the second node down form the top
        xmlDocument.ChildNodes[1].ChildNodes[1].Attributes.RemoveAll();
    
        // Reset the memoryStream object - essentially nulls it out
        memoryStream.SetLength(0);
    
        // ReInitialize the xmlWriter
        xmlWriter = XmlWriter.Create(memoryStream);
    
        // Write the modified xml request message (xmlDocument) to the memoryStream in the xmlWriter
        xmlDocument.WriteTo(xmlWriter);
    
        // Clear the xmlWriter
        xmlWriter.Flush();
    
        // Place the pointer in the memoryStream to the beginning 
        memoryStream.Position = 0;
    
        // Create a new xmlReader with the memoryStream that contains the xmlDocument
        var xmlReader = XmlReader.Create(memoryStream);
    
        // Create a new request message with the modified xmlDocument
        request = Message.CreateMessage(xmlReader, int.MaxValue, request.Version);
    
        return request;
    
    } // end
    

    要在调用服务时让这一切正常工作,您需要修改 web.config 或 app.config。在您的端点声明中,您需要指定一个 behaviorConfiguration 元素,如下所示:

    <client>
        <endpoint address="http://1.2.3.4:1234/InventoryBinding"
              binding="basicHttpBinding" bindingConfiguration="HttpSoapBinding"
              contract="TibcoSvc.InventoryPort" name="InventoryPort" 
              behaviorConfiguration="clientInspectorsAdded" />    
    </client>
    

    您还需要指定扩展名和行为:

    <system.serviceModel>
    
        <extensions>
            <behaviorExtensions>
                <add name="ExtendedEndpointBehavior" type="Sample.Integrations.EndpointBehaviorExtensionElement, Sample.Integrations, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
            </behaviorExtensions>
        </extensions>
    
        <behaviors>
            <endpointBehaviors>
                <behavior name="clientInspectorsAdded">
                    <ExtendedEndpointBehavior />
                </behavior>
            </endpointBehaviors>
        </behaviors>
    
    </system.serviceModel>
    

    在此请注意,扩展名必须与所返回的完全一致:

    var foo = typeof(<PutYourNamespaceHereNoAngleBrackets>.EndpointBehaviorExtensionElement).AssemblyQualifiedName; 
    

    这里有一些我觉得很有帮助的链接:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/01440583-d406-4426-8667-63c6eda431fa/remove-xmlnsxsi-and-xmlnsxsd-from-soap-request-body-tag-aspnet?forum=wcf

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/51547537-fdae-4837-9bd1-30e445d378e9/removing-xmlnsxsihttpwwww3org2001xmlschemainstance-and?forum=wcf

    http://weblogs.asp.net/paolopia/writing-a-wcf-message-inspector

    https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageinspector(v=vs.100).aspx

    【讨论】:

      猜你喜欢
      • 2022-01-17
      • 1970-01-01
      • 2019-12-22
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 1970-01-01
      • 1970-01-01
      • 2011-03-17
      相关资源
      最近更新 更多