【问题标题】:Remove namespace prefix from WCF SOAP response从 WCF SOAP 响应中删除命名空间前缀
【发布时间】:2017-01-05 11:50:05
【问题描述】:

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

当响应一个名为 Ping 的方法时,原始服务器会响应:

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

当我从 C# 控制台应用程序调用原始服务时,PingResult 已正确填充。只需将端点的地址更改为我的新服务并重新运行,服务返回新响应,但 PingResult 为空。我能看到的唯一区别是原始节点和我的节点是 PingResult 节点上的“ns1”前缀。我猜这会在客户端触发反序列化。

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

谢谢。

【问题讨论】:

  • 能不能mock服务,返回一个没有命名空间的xml文字串,看看客户端能不能反序列化?
  • @Crowcoder 这正是我现在正在做的事情,干杯。
  • @Crowcoder 发送删除了命名空间前缀的 xml 字符串被客户端完美地反序列化。如果 wcf 工作流程中有一点我可以在发送之前编辑 xml,那将是完美的。

标签: c# web-services wcf soap


【解决方案1】:

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

实现一个消息监听器。您有机会处理 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 参数在回复中的重要性,但您可以阅读有关如何构建它的值:

Use the Actionproperty to control the action of the method's input message. Because WCF uses this action to dispatch an incoming message to the appropriate method, messages used within a contract operation must have unique actions. The default action value is a combination of the contract namespace (the default value is "http://tempuri.org/"), the contract name (interface name or the class name, if no explicit service interface is used), the operation name, and an additional string ("Response") if the message is a correlated response. You can override this default with the Action property.

更新

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

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

  ...

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

...

【讨论】:

  • 被接受为答案,因为它确实回答了上面的问题,但最后我不需要做任何这些,因为我从客户端的 wsdl 重新生成了服务器,它解决了我遇到的所有问题试图复制。谢谢!