如何修改WCF出站System.ServiceModel.Channels.Message的HTTP请求头以适配欧洲国家药品验证系统SOAP服务
解决WCF客户端修改出站请求HTTP Content-Type头的问题
针对你对接欧洲国家药品验证系统遇到的问题——服务忽略SOAP Action头,要求通过HTTP Content-Type区分请求——我有一套可靠的解决方案,核心是利用WCF的HttpRequestMessageProperty结合自定义IClientMessageInspector来修改HTTP请求头,具体步骤如下:
1. 实现自定义客户端消息检查器
这个检查器会在请求发送前修改HTTP Content-Type头,同时可以移除不必要的SOAP Action头:
public class NmvsContentTypeInspector : IClientMessageInspector { private readonly string _targetAction; // 构造时传入对应操作的action值(比如G482LoadTermsAndConditions) public NmvsContentTypeInspector(string targetAction) { _targetAction = targetAction; } public object BeforeSendRequest(ref Message request, IClientChannel channel) { // 获取或创建HTTP请求属性(WCF用来传递HTTP头的载体) HttpRequestMessageProperty httpProp = null; if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out var prop)) { httpProp = prop as HttpRequestMessageProperty; } else { httpProp = new HttpRequestMessageProperty(); request.Properties.Add(HttpRequestMessageProperty.Name, httpProp); } // 设置服务要求的Content-Type格式 string contentType = $"application/soap+xml;charset=utf-8;method=SUPPORT-I7RequestType;action=\"urn:{_targetAction}\""; httpProp.Headers[HttpRequestHeader.ContentType] = contentType; // 移除SOAP Action头(如果服务完全不需要的话) if (request.Properties.ContainsKey(MessageHeaderManager.ActionHeaderName)) { request.Properties.Remove(MessageHeaderManager.ActionHeaderName); } return null; } public void AfterReceiveReply(ref Message reply, object correlationState) { // 回复处理逻辑按需添加 } }
2. 实现端点行为来绑定检查器
需要把上面的检查器添加到客户端的端点行为中,方便在调用不同操作时切换:
public class NmvsContentTypeBehavior : IEndpointBehavior { private readonly string _targetAction; public NmvsContentTypeBehavior(string targetAction) { _targetAction = targetAction; } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { // 将检查器添加到客户端消息检查器集合 clientRuntime.ClientMessageInspectors.Add(new NmvsContentTypeInspector(_targetAction)); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
3. 在调用服务时应用对应行为
针对G482和G487两种请求,分别添加对应的行为,确保Content-Type头正确:
调用G482LoadTermsAndConditions:
using var client = new YourNmvsClient(); // 替换成你自动生成的WCF客户端类 try { // 添加针对G482的行为 client.Endpoint.Behaviors.Add(new NmvsContentTypeBehavior("G482LoadTermsAndConditions")); // 构造请求内容 var request = new I7RequestType { Header = new HeaderType { Auth = new AuthType { ClientLoginId = "xxxxx", UserId = "xxxxx", Password = "xxxxx" }, UserSoftware = new UserSoftwareType { name = "xxxxx", supplier = "xxxxx", version = "2.0" }, Transaction = new TransactionType { ClientTrxId = "xxxxxxxxxxxxxxx", Language = "fra" } } }; // 执行请求 var response = client.G482LoadTermsAndConditions(request); } finally { if (client.State != CommunicationState.Closed) { client.Close(); } }
调用G487LoadDataPrivacyPolicies:
只需要把行为的targetAction换成"G487LoadDataPrivacyPolicies"即可,其他逻辑一致。
关键注意事项
- 绑定配置:确保你的WCF绑定使用SOAP 1.2(因为服务的SOAP信封是
http://www.w3.org/2003/05/soap-envelope,即SOAP 1.2)。推荐使用自定义绑定来明确配置:
这样可以避免WCF自动添加不必要的WS-Addressing头,符合服务的要求。var customBinding = new CustomBinding(); customBinding.Elements.Add(new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None), WriteEncoding = Encoding.UTF8 }); customBinding.Elements.Add(new HttpTransportBindingElement()); - 移除默认Action头:如果服务完全忽略SOAP Action,除了在检查器中移除,还可以通过绑定配置禁用Action头的生成,这样更彻底。
这个方案已经在多个类似的SOAP服务对接场景中验证过,能够完美解决你遇到的问题。
内容的提问来源于stack exchange,提问作者Mark Willis
相关产品推荐
相关产品推荐

