.NET ASMX/WCF服务响应额外<MyServiceResult>标签移除咨询
我之前也碰到过一模一样的情况——第三方系统对SOAP结构的兼容性要求特别苛刻,.NET默认给响应加的那个包装标签直接导致对接失败。下面分ASMX和WCF两种场景给你具体的解决办法:
ASMX服务解决方案
ASMX默认会把Web方法的返回值包装在方法名+Result的标签里,要去掉这个标签,需要通过属性控制序列化行为:
定义响应实体类并指定XmlRoot
给你的响应根类加上[XmlRoot]属性,明确指定它的名称和命名空间,和目标SOAP结构完全一致:[XmlRoot("MyServiceResponse", Namespace = "http://aaaa")] public class MyServiceResponse { [XmlElement("Resultado", Namespace = "http://aaaa")] public Resultado Resultado { get; set; } [XmlElement("CodigoTransaccion", Namespace = "http://aaaa")] public string CodigoTransaccion { get; set; } } public class Resultado { [XmlElement("ResultMajor", Namespace = "http://aaaa")] public string ResultMajor { get; set; } [XmlElement("ResultMinor", Namespace = "http://aaaa")] public string ResultMinor { get; set; } [XmlElement("ResultMessage", Namespace = "http://aaaa")] public string ResultMessage { get; set; } }修改WebMethod属性
在你的Web方法上添加[SoapDocumentMethod],设置ParameterStyle = SoapParameterStyle.Bare,告诉ASMX不要自动包装返回值:[WebMethod] [SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare, ResponseNamespace = "http://aaaa")] public MyServiceResponse MyService() { var response = new MyServiceResponse { Resultado = new Resultado { ResultMajor = "OK", ResultMinor = "OK", ResultMessage = "Success!" }, CodigoTransaccion = "123456" }; return response; }这样ASMX返回的SOAP响应就会完全匹配你要的结构,不会多出
MyServiceResult标签。
WCF服务解决方案
WCF默认使用DataContractSerializer时,也会自动给返回值添加包装标签。要精准控制SOAP结构,我们需要使用MessageContract来定义响应:
用MessageContract定义响应结构
MessageContract允许你直接映射SOAP Body里的元素,完全避免自动包装:[MessageContract(WrapperName = "MyServiceResponse", WrapperNamespace = "http://aaaa")] public class MyServiceResponseMessage { [MessageBodyMember(Namespace = "http://aaaa")] public Resultado Resultado { get; set; } [MessageBodyMember(Namespace = "http://aaaa")] public string CodigoTransaccion { get; set; } } [DataContract(Namespace = "http://aaaa")] public class Resultado { [DataMember(Name = "ResultMajor", Order = 1)] public string ResultMajor { get; set; } [DataMember(Name = "ResultMinor", Order = 2)] public string ResultMinor { get; set; } [DataMember(Name = "ResultMessage", Order = 3)] public string ResultMessage { get; set; } }修改服务契约和实现
服务契约里的方法直接返回这个MessageContract类,同时确保契约的命名空间和目标一致:[ServiceContract(Namespace = "http://aaaa")] public interface IMyService { [OperationContract] MyServiceResponseMessage MyService(); } public class MyService : IMyService { public MyServiceResponseMessage MyService() { return new MyServiceResponseMessage { Resultado = new Resultado { ResultMajor = "OK", ResultMinor = "OK", ResultMessage = "Success!" }, CodigoTransaccion = "123456" }; } }配置文件注意事项
确保你的WCF绑定使用basicHttpBinding(如果是SOAP1.1场景),并且不要启用任何自动包装的配置。如果还是有问题,可以给服务契约加上[XmlSerializerFormat]属性,强制使用XmlSerializer来序列化,它对旧SOAP结构的兼容性更好。
为什么会出现这个额外标签?
简单来说,.NET的ASMX和WCF默认会遵循SOAP的“文档/包裹”(Document/Wrapped)样式,把方法的输入输出参数都包装在一个与方法名相关的标签里。而Java的JAX-WS默认可以直接映射到裸(Bare)样式,所以不会有这个额外标签。我们上面的配置就是把.NET的序列化行为改成了裸样式,从而匹配第三方系统的要求。
内容的提问来源于stack exchange,提问作者Roque Santos




