问询:.NET如何在WSDL生成的代理中移除请求空标签?
移除Web服务请求中的空标签:代理代码层的实现方案
嗨,这个需求我太熟悉了——改WSDL确实是合规的做法,但还要和外部伙伴同步验证,成本不低。其实在生成的代理代码里,完全可以通过拦截序列化后的请求内容来移除空标签,不用动WSDL,下面给你两种最常用的简便方案:
方案一:针对传统ASMX代理(SoapHttpClientProtocol)
如果你的代理类是用wsdl.exe生成的、继承自SoapHttpClientProtocol的传统ASMX代理,可以重写GetWebRequest方法,在请求发送前修改XML内容:
- 找到生成的代理类,添加以下重写方法:
protected override WebRequest GetWebRequest(Uri uri) { WebRequest request = base.GetWebRequest(uri); if (request is HttpWebRequest httpRequest) { httpRequest.ContentLength = 0; // 先清空默认长度,后续重新计算 using (MemoryStream ms = new MemoryStream()) { // 序列化请求对象到内存流 var requestType = this.GetType().GetMethod("YourRequestMethod").GetParameters()[0].ParameterType; XmlSerializer serializer = new XmlSerializer(requestType); serializer.Serialize(ms, yourRequestObject); // 替换为实际请求对象变量 ms.Position = 0; // 加载XML并移除空标签(无内容且无子元素的节点) XDocument doc = XDocument.Load(ms); doc.Descendants().Where(e => string.IsNullOrWhiteSpace(e.Value) && !e.HasElements).Remove(); // 将修改后的XML写入请求流 using (Stream requestStream = httpRequest.GetRequestStream()) { doc.Save(requestStream); httpRequest.ContentLength = requestStream.Length; } } } return request; }
注意:要替换代码里的YourRequestMethod和yourRequestObject为你实际调用的请求方法与参数对象。
方案二:针对WCF代理(ClientBase)
如果是用SvcUtil.exe生成的WCF代理,可以通过实现IClientMessageInspector来拦截SOAP消息并修改XML:
- 创建消息检查器类:
public class RemoveEmptyTagsInspector : IClientMessageInspector { public object BeforeSendRequest(ref Message request, IClientChannel channel) { // 将Message转换为XDocument MemoryStream ms = new MemoryStream(); XmlWriter writer = XmlWriter.Create(ms); request.WriteMessage(writer); writer.Flush(); ms.Position = 0; XDocument doc = XDocument.Load(ms); // 移除所有空标签 doc.Descendants().Where(e => string.IsNullOrWhiteSpace(e.Value) && !e.HasElements).Remove(); // 将修改后的XML转换回Message ms.SetLength(0); writer = XmlWriter.Create(ms); doc.Save(writer); writer.Flush(); ms.Position = 0; XmlReader reader = XmlReader.Create(ms); request = Message.CreateMessage(reader, int.MaxValue, request.Version); return null; } public void AfterReceiveReply(ref Message reply, object correlationState) { // 无需处理响应,留空即可 } }
- 创建行为类,将检查器添加到代理行为中:
public class RemoveEmptyTagsBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.ClientMessageInspectors.Add(new RemoveEmptyTagsInspector()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
- 在创建代理实例时绑定该行为:
using (var client = new YourWcfProxyClient()) { client.Endpoint.Behaviors.Add(new RemoveEmptyTagsBehavior()); // 调用服务方法 client.YourServiceMethod(yourRequest); }
额外小技巧:利用部分类避免代码覆盖
如果代理类是自动生成的,不想手动修改生成的文件,可以用**部分类(partial class)**来扩展逻辑——把重写方法或自定义行为放在单独的文件里,这样重新生成时代码不会被覆盖。
补充:如果临时需要快速生效,也可以修改生成的实体类,给字段/属性添加
[XmlElement(IsNullable = false)]属性,让XmlSerializer直接跳过空标签序列化,但这种方式每次重新生成代理都要重复操作,适合短期场景。
内容的提问来源于stack exchange,提问作者Rich T.
相关产品推荐
相关产品推荐

