我怎样才能消费的传统SOAP服务时创建自定义XML命名空间的属性? [英] How can I create custom XML namespace attributes when consuming a legacy SOAP service?
问题描述
我有一个传统的Tibco SOAP服务,我需要从中获取一些数据。不幸的是这种服务是非常讲究的请求消息中的XML命名空间属性。我也碰到这样的问题,从消费仁科服务时( https://en.wikipedia.org/维基/的PeopleCode )。
I have a legacy Tibco SOAP service that I need to get some data from. Unfortunately this service is very particular about the XML namespace attributes on the request message. I have also run into this sort of problem when consuming services from PeopleSoft (https://en.wikipedia.org/wiki/PeopleCode).
我从服务的.wsdl并创建了服务的参考。
I got the .wsdl from the service and created a service reference.
开箱即用,即净生成XML请求消息是:
Out of the box, the XML request message that .Net produces is:
<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):
What actually works is (I figured this out using 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前缀。
Notice the absence of the xsi and xsd prefixes within the body tag.
问:我怎样才能得到净送手的正确XML短期滚动XML文档,并手动将其发送到服务
推荐答案
答:我能够通过实施IClientMessageInspector它发送之前修改XML请求
首先,我不得不通过实施IClientMessageInspector延长WCF。这让我来访问请求对象和修改XML请求消息。这些类并不需要在你的解决方案中的任何特定位置(据我所知)。
First I had to extend WCF by implementing IClientMessageInspector. This allowed me to gain access to the request object and modify the XML request message. 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
我没把那个在在同一类为服务这个服务的XML专门处理方法:
I did put the method that specifically deals with the XML in this service in the same class as the service:
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元素:
To get this all to work when the service is called you will need to modify your web.config or app.config. On your endpoint declaration you will need to specify a behaviorConfiguration element like so:
<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:
http://weblogs.asp.net/paolopia/writing-a-wcf -message巡视员
这篇关于我怎样才能消费的传统SOAP服务时创建自定义XML命名空间的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!