我正在实现 WCF 服务来替换现有的 SOAP 服务。访问此服务的客户端无法更改(除了指向新服务器的配置)。
当响应 Ping 方法时,原始服务器响应:
使用 WCF 重新创建方法,我已经设法接近:
当我从 C# 控制台应用程序调用原始服务时,PingResult 已正确填充。 只需将端点地址更改为我的新服务并重新运行,该服务就会返回新响应,但 PingResult 为空。我可以看到原始版本和我的版本之间唯一不同的是 PingResult 节点上的“ns1”前缀。 我猜这会导致客户端的反序列化失败。
所以我的问题是,如何从 PingResult 中删除 ns1 前缀?
谢谢。
您可以尝试这个,我以前从未更改过消息,所以我不确定它是否完全像这样工作,但我已经这样做来记录消息。
实现消息监听器。您有机会处理
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
参数在回复中有多重要,但你可以阅读如何构建它的值:
更新
我在
system.serviceModel
配置中也有这些项目:
<serviceBehaviors>
<behavior name="MessageListenerBehavior">
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
...
<services>
<service behaviorConfiguration="MessageListenerBehavior" name="... your service name...">
...
我能够通过装饰复杂对象中的每个 DataMember 来解决此问题。
public class StatusCode
{
[DataMember]
[XmlElement(ElementName = "code", Namespace = "")]
public string code { get; set; }
}
这将 WSDL 的 XML 输出更改为:
<tem:code></tem:code>
致:
<code></code>
XML 的 POST 也有效。
这是唯一对我有用的解决方案。