如何在使用传统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;
以下是一些我发现有用的链接:
http://weblogs.asp.net/paolopia/writing-a-wcf-message-inspector