c# - C# 生成没有 XML 根元素的 SOAP 信封
问题描述
我正在使用Message.CreateMessage
创建一个Message
并将其发送到 WCF 服务端点,但我创建的每条消息都以它开头<?xml version="1.0" encoding="utf-16"?>
,导致服务拒绝我的消息Operation is not supported
。SOAP 1.1 标准指出,这The Envelope is the top element of the XML document representing the message.
可能就是服务拒绝我的消息的原因。不同MessageVersion
的 s 不会更改生成的 XML,并且构造函数确实接受 aBodyWriter
但 XML 正文不会导致我的问题,它是根元素。
有没有一种方法可以在没有 XML 根元素的情况下生成一个Message
with ?Message.CreateMessage
编码
internal static Message CreateGetMessage(string id)
{
const string Get = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Get";
const string Rm = "http://schemas.microsoft.com/2006/11/ResourceManagement";
/* unnecessary code removed to create simplest example */
var message = Message.CreateMessage(MessageVersion.Default, Get);
if (message.Headers.FindHeader("ResourceReferenceProperty", Rm) <= 0)
{
message.Headers.Add(MessageHeader.CreateHeader("ResourceReferenceProperty", Rm, id));
}
return message;
}
生成的 SOAP 信封
<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2004/09/transfer/Get</a:Action>
<ResourceReferenceProperty xmlns="http://schemas.microsoft.com/2006/11/ResourceManagement">8f2a4ecc-e3dc-1a4c-5a28-4a4a7a8e6644</ResourceReferenceProperty>
</s:Header>
<s:Body />
</s:Envelope>
所需的 SOAP 信封
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2004/09/transfer/Get</a:Action>
<ResourceReferenceProperty xmlns="http://schemas.microsoft.com/2006/11/ResourceManagement">8f2a4ecc-e3dc-1a4c-5a28-4a4a7a8e6644</ResourceReferenceProperty>
</s:Header>
<s:Body />
</s:Envelope>
调试
解决方案
可以使用.NET提供的Message Formatter自定义SOAP消息,在服务端实现IDispatchMessageFormatter接口,在客户端实现IClientMessageFormatter接口。这是推荐的方法。
还有一个消息检查器来修改 SOAP 消息。这是消息检查器的示例。
public class CustomMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
MessageHeader header = MessageHeader.CreateHeader("UserAgent", "http://User", "User1");
request.Headers.Add(header);
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
MessageHeader header1 = MessageHeader.CreateHeader("Testreply", "http://Test", "Test");
reply.Headers.Add(header1);
}
}
[AttributeUsage(AttributeTargets.Interface)]
public class CustomBehavior : Attribute, IContractBehavior
{
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.MessageInspectors.Add(new CustomMessageInspector());
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
return;
}
}
将 CustomBehavior 添加到您的服务合同中以应用。
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[CustomBehavior]
如果消息拦截器修改了服务合约定义的消息体,内容验证会失败,所以建议只修改消息头。
推荐阅读
- c++ - 发布版本中的 C++ 未来错误值
- bash - 编写 bash 脚本将 postgres 查询结果转储到文件中
- python-3.x - 需要帮助找出此代码有什么问题。[2 用户名和密码]
- python - 代码在输出末尾留下随机字符串
- javascript - 使用渐变文本更改元素的 HTML 内容不会在 chrome 中重新呈现
- hive - ST_Aggr_Union 失败,没有匹配方法异常
- html - 我的标题被包含在我的主要标签中
- javascript - 将 Vue 应用程序挂载到主 Vue 应用程序的容器中
- swagger - Swagger 2 相对路径引用没有得到解决
- android - CameraX - 找不到相机设备支持的表面组合 - Id:null。可能试图绑定太多用例