如何在使用传统SOAP服务时创建自定义XML命名空间属性?

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

我从服务中获得了.wsdl并创建了一个服务引用。

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

    SysAdmin  
123 Main St New York NY US

实际上是什么(我用SoapUI想出来):

     SysAdmin  
123 Main St New York NY US

请注意body标记中缺少xsi和xsd前缀。

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

答:我可以通过实现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 

我确实把与服务中的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元素,如下所示:

    

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

               

请注意,扩展名称必须与返回的内容完全相同:

 var foo = typeof(.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?论坛= 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