WCF兼容RPC.Encoded格式SOAP请求改造问题咨询
解决WCF兼容RPC.Encoded格式SOAP请求的方案
核心问题
WCF默认仅支持Document/Literal格式的SOAP请求,而旧ASMX服务常用的RPC.Encoded不在默认支持范围内,因此需要通过配置调整或自定义消息处理来兼容。
方案一:通过自定义绑定启用RPC.Encoded支持
使用CustomBinding替代默认的BasicHttpBinding,手动配置消息编码和传输规则,匹配RPC.Encoded的格式要求:
- 在服务配置文件(如
web.config或app.config)中添加自定义绑定:
<system.serviceModel> <bindings> <customBinding> <binding name="RpcEncodedCompatibleBinding"> <!-- 指定SOAP版本为1.1(旧ASMX默认版本),启用文本编码 --> <textMessageEncoding messageVersion="Soap11"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> </textMessageEncoding> <httpTransport /> </binding> </customBinding> </bindings> <services> <service name="YourNamespace.YourWcfService"> <!-- 使用自定义绑定配置 --> <endpoint address="" binding="customBinding" bindingConfiguration="RpcEncodedCompatibleBinding" contract="YourNamespace.IYourWcfContract" /> </service> </services> </system.serviceModel>
- 同步调整服务契约的命名空间和操作动作,确保与旧ASMX完全一致:
[ServiceContract(Namespace = "http://your-old-asmx-namespace/")] public interface IYourWcfContract { // Action需匹配旧ASMX方法的SOAP动作地址 [OperationContract(Action = "http://your-old-asmx-namespace/YourMethodName", ReplyAction = "*")] YourResponseType YourMethodName(YourRequestType requestParams); }
方案二:自定义消息拦截器手动解析转换
如果配置调整无法解决问题,可通过IDispatchMessageInspector拦截请求,手动解析RPC.Encoded格式并转换为WCF可识别的结构:
- 实现消息拦截器:
public class RpcEncodedMessageInspector : IDispatchMessageInspector { public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { // 读取原始SOAP请求流 var buffer = request.CreateBufferedCopy(int.MaxValue); var originalMsg = buffer.CreateMessage(); var stream = new MemoryStream(); var xmlWriter = XmlWriter.Create(stream); originalMsg.WriteMessage(xmlWriter); xmlWriter.Flush(); stream.Position = 0; // 解析RPC.Encoded格式的XML节点 var xmlDoc = new XmlDocument(); xmlDoc.Load(stream); var nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); nsMgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/"); nsMgr.AddNamespace("asmx", "http://your-old-asmx-namespace/"); // 提取目标方法的参数节点(示例:旧方法名为GetModuleData) var methodNode = xmlDoc.SelectSingleNode("//soap:Body/asmx:GetModuleData", nsMgr); if (methodNode != null) { // 构造WCF期望的消息结构 var newMsg = Message.CreateMessage(originalMsg.Version, originalMsg.Headers.Action); var bodyWriter = new CustomRpcBodyWriter(methodNode); newMsg = Message.CreateMessage(newMsg.Version, newMsg.Headers.Action, bodyWriter); // 替换原始请求消息 request = newMsg; } buffer.Close(); return null; } public void BeforeSendReply(ref Message reply, object correlationState) { // 如需调整回复格式为RPC.Encoded,可在此处理 } } // 自定义消息体写入器 public class CustomRpcBodyWriter : BodyWriter { private readonly XmlNode _methodNode; public CustomRpcBodyWriter(XmlNode methodNode) : base(true) { _methodNode = methodNode; } protected override void OnWriteBodyContents(XmlWriter writer) { _methodNode.WriteTo(writer); } }
- 注册拦截器到服务行为:
public class RpcEncodedBehavior : IServiceBehavior { public void ApplyDispatchBehavior(ServiceDescription serviceDesc, ServiceHostBase serviceHost) { foreach (var channelDispatcher in serviceHost.ChannelDispatchers) { foreach (var endpointDispatcher in ((ChannelDispatcher)channelDispatcher).Endpoints) { endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new RpcEncodedMessageInspector()); } } } public void AddBindingParameters(ServiceDescription serviceDesc, ServiceHostBase serviceHost, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) { } public void Validate(ServiceDescription serviceDesc, ServiceHostBase serviceHost) { } }
- 在服务启动时添加行为:
var serviceHost = new ServiceHost(typeof(YourWcfService)); serviceHost.Description.Behaviors.Add(new RpcEncodedBehavior()); serviceHost.Open();
关键注意事项
- 确保WCF契约的命名空间、方法名、参数名与旧ASMX完全一致,RPC.Encoded对名称匹配的要求极为严格;
- 若旧ASMX服务启用了身份验证或加密,需同步在WCF绑定中配置对应安全规则。
内容的提问来源于stack exchange,提问作者VKM
相关产品推荐
相关产品推荐

