简体   繁体   English

使用旧版SOAP服务时如何创建自定义XML名称空间属性?

[英]How can I create custom XML namespace attributes when consuming a legacy SOAP service?

I have a legacy Tibco SOAP service that I need to get some data from. 我有一个旧的Tibco SOAP服务,我需要从中获取一些数据。 Unfortunately this service is very particular about the XML namespace attributes on the request message. 不幸的是,该服务对于请求消息上的XML名称空间属性非常特殊。 I have also run into this sort of problem when consuming services from PeopleSoft ( https://en.wikipedia.org/wiki/PeopleCode ). 在使用PeopleSoft( https://en.wikipedia.org/wiki/PeopleCode )的服务时,我也遇到了此类问题。

I got the .wsdl from the service and created a service reference. 我从服务获得.wsdl并创建了服务引用。

Out of the box, the XML request message that .Net produces is: .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>

What actually works is (I figured this out using SoapUI): 实际起作用的是(我使用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>

Notice the absence of the xsi and xsd prefixes within the body tag. 请注意,body标记中没有xsi和xsd前缀。

Q: How can I get .Net to send the correct XML short of hand rolling the XML document and manually sending it to the service? 问:如何使.Net在不滚动XML文档并将其手动发送到服务的情况下发送正确的XML?

A: I was able to modify the XML request before sending it out by implementing IClientMessageInspector. 答:我可以通过实现IClientMessageInspector来修改XML请求,然后再将其发送出去。

First I had to extend WCF by implementing IClientMessageInspector. 首先,我必须通过实现IClientMessageInspector来扩展WCF。 This allowed me to gain access to the request object and modify the XML request message. 这使我能够访问请求对象并修改XML请求消息。 These classes don't need to be in any particular location within you solution (as far as I know). 这些类不必位于解决方案中的任何特定位置(据我所知)。

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

I did put the method that specifically deals with the XML in this service in the same class as the service: 我确实将专门处理服务中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

To get this all to work when the service is called you will need to modify your web.config or app.config. 为了使所有这些在调用服务时正常工作,您将需要修改web.config或app.config。 On your endpoint declaration you will need to specify a behaviorConfiguration element like so: 在端点声明上,您将需要指定一个behaviorConfiguration元素,如下所示:

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

You will also need to specify the extension and the behavior as well: 您还需要指定扩展名和行为:

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

Note here that the extension name needs to be exactly what is returned by: 请注意,扩展名必须与返回的名称完全相同:

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

Here are a few links that I found helpful: 以下是一些对我有用的链接:

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/01440583-d406-4426-8667-63c6eda431fa/remove-xmlnsxsi-and-xmlnsxsd-from-soap-request-body-tag-aspnet?论坛= WCF

https://social.msdn.microsoft.com/Forums/vstudio/en-US/51547537-fdae-4837-9bd1-30e445d378e9/removing-xmlnsxsihttpwwww3org2001xmlschemainstance-and?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 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 https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageinspector(v=vs.100).aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM