从 WCF SOAP 响应中删除命名空间前缀

问题描述 投票:0回答:2

我正在实现 WCF 服务来替换现有的 SOAP 服务。访问此服务的客户端无法更改(除了指向新服务器的配置)。

当响应 Ping 方法时,原始服务器响应:

enter image description here

使用 WCF 重新创建方法,我已经设法接近:

enter image description here

当我从 C# 控制台应用程序调用原始服务时,PingResult 已正确填充。 只需将端点地址更改为我的新服务并重新运行,该服务就会返回新响应,但 PingResult 为空。我可以看到原始版本和我的版本之间唯一不同的是 PingResult 节点上的“ns1”前缀。 我猜这会导致客户端的反序列化失败。

所以我的问题是,如何从 PingResult 中删除 ns1 前缀?

谢谢。

c# web-services wcf soap
2个回答
2
投票

您可以尝试这个,我以前从未更改过消息,所以我不确定它是否完全像这样工作,但我已经这样做来记录消息。

实现消息监听器。您有机会处理

BeforeSendReply
方法,您可以在该方法中访问消息并能够更改它。

然后用属性

[MessageListenerBehavior]

来装饰你的合约实现类
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace YourNamespace
{
    public class MessageListenerBehavior : Attribute, IDispatchMessageInspector, IServiceBehavior
    {
        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            return null;
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {

            Message msg = reply.CreateBufferedCopy(int.MaxValue).CreateMessage();

            try
            {
                //Setup StringWriter to use as input for our StreamWriter
                //This is needed in order to capture the body of the message, because the body is streamed.
                using (StringWriter stringWriter = new StringWriter())
                using (XmlWriter xmlTextWriter = XmlWriter.Create(stringWriter))
                {
                    msg.WriteMessage(xmlTextWriter);
                    xmlTextWriter.Flush();
                    xmlTextWriter.Close();

                    string thexml = stringWriter.ToString();

                    XDocument doc = XDocument.Parse(thexml);
                    // alter the doc here...........
                       Message newMsg = Message.CreateMessage(MessageVersion.Soap11, "http://..something", doc.ToString());

                reply = newMsg;
            }
            catch (Exception ex) { //handle it }
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {

        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                foreach (var endpoint in dispatcher.Endpoints)
                {
                    endpoint.DispatchRuntime.MessageInspectors.Add(new MessageListenerBehavior());
                }
            }
        }

        public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            //throw new NotImplementedException();
        }
    }

    public class WcfMessgeLoggerExtension : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get
            {
                return typeof(MessageListenerBehavior);
            }
        }

        protected override object CreateBehavior()
        {
            return new MessageListenerBehavior();
        }
    }
}

当你这样做时

Message.CreateMessage
我不知道
Action
参数在回复中有多重要,但你可以阅读如何构建它的值:

使用Action属性来控制方法输入消息的操作。由于 WCF 使用此操作将传入消息分派到适当的方法,因此协定操作中使用的消息必须具有唯一的操作。默认操作值是合约命名空间(默认值为“http://tempuri.org/”)、合约名称(接口名称或类名称,如果没有使用显式服务接口)、操作的组合如果消息是相关响应,则还包含名称和附加字符串(“响应”)。您可以使用 Action 属性覆盖此默认值。

更新

我在

system.serviceModel
配置中也有这些项目:

  <serviceBehaviors>
    <behavior name="MessageListenerBehavior">
      <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>
  </serviceBehaviors>

  ...

<services>
  <service behaviorConfiguration="MessageListenerBehavior" name="... your service name...">

...


0
投票

我能够通过装饰复杂对象中的每个 DataMember 来解决此问题。

public class StatusCode
{
    [DataMember]
    [XmlElement(ElementName = "code", Namespace = "")]
    public string code { get; set; }
}

这将 WSDL 的 XML 输出更改为:

<tem:code></tem:code>

致:

<code></code>

XML 的 POST 也有效。

这是唯一对我有用的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.