移除手动WSDL包装标签,CoreWCF端点匹配旧WSDL配置问题
解决CoreWCF中SOAP端点匹配旧WSDL的问题
需将旧.NET 4.7应用升级到.NET Core,用CoreWCF重新实现SOAP端点,必须严格匹配客户端使用的旧WSDL。VS导入旧WSDL时因依赖ServiceModel无法直接使用,修改引用后OperationContract输入参数始终为空,故手动定义服务契约、操作契约及数据成员,但生成的XML结构与旧WSDL不符。
客户端发送的目标XML结构
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.test.me/method/"> <SOAP-ENV:Body> <ns1:method1> <msgContBody> <par1>Hello</par1> <descPar1>Desc of Hello</descPar1> <par2>World</par2> <descPar2>Desc of World</descPar2> <arrayPar> <Id>1</Id> <Desc>one</Desc> </arrayPar> <arrayPar> <Id>2</Id> <Desc>two</Desc> </arrayPar> <arrayPar> <Id>3</Id> <Desc>three</Desc> </arrayPar> </msgContBody> </ns1:method1> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
当前生成的不符合结构的XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.test.me/method/"> <soapenv:Header/> <soapenv:Body> <ns1:method1> <!--Optional:--> <ns1:request> <!--Zero or more repetitions:--> <rootPar> <!--Optional:--> <par1>?</par1> <!--Optional:--> <descPar1>?</descPar1> <!--Optional:--> <par2>?</par2> <!--Optional:--> <descPar2>?</descPar2> <!--Optional:--> <arrayPar> <!--Zero or more repetitions:--> <arrayPar> <!--Optional:--> <Id>1</Id> <!--Optional:--> <Desc>one</Desc> </arrayPar> <arrayPar> <!--Optional:--> <Id>2</Id> <!--Optional:--> <Desc>two</Desc> </arrayPar> <arrayPar> <!--Optional:--> <Id>3</Id> <!--Optional:--> <Desc>three</Desc> </arrayPar> </arrayPar> </rootPar> </ns1:request> </ns1:method1> </soapenv:Body> </soapenv:Envelope>
需要修正的问题
- 移除多余的
request包装标签 - 移除
arrayPar的外层包装标签,直接生成多个<arrayPar>元素
当前代码实现
[ServiceContract(Namespace = "http://www.test.me/method/")] public interface IMeService { [OperationContract] Task<myResponse> method1Async(myRequest request); } public class MeService: IMeService { public async Task<myResponse> method1Async(myRequest request) { // 业务逻辑实现 return await Task.FromResult(new myResponse()); } } [MessageContract(WrapperNamespace = "http://www.test.me/method/", WrapperName = "method1")] public class myRequest { [MessageBodyMember(Name = "rootPar")] public rootPar[] rootPar; } [DataContract(Namespace = "")] public class rootPar { [DataMember(Name = "par1")] public string par1{ get; set; } [DataMember(Name = "descPar1")] public string descPar1{ get; set; } [DataMember(Name="par2")] public string par2{ get; set; } [DataMember(Name = "descPar2")] public string descPar2{ get; set; } [DataMember] public arrPar[] arrPar{ get; set; } } [DataContract(Namespace = "")] public class arrPar { [DataMember(Name="Id")] public string Id{ get; set; } [DataMember(Name = "Desc")] public string Desc{ get; set; } } // 补充定义myResponse [MessageContract(WrapperNamespace = "http://www.test.me/method/", WrapperName = "method1Response")] public class myResponse { // 根据旧WSDL定义响应结构 [MessageBodyMember(Name = "result")] public string Result { get; set; } }
修正后的代码实现
[ServiceContract(Namespace = "http://www.test.me/method/")] public interface IMeService { [OperationContract] Task<myResponse> method1Async(myRequest request); } public class MeService: IMeService { public async Task<myResponse> method1Async(myRequest request) { // 业务逻辑实现,此时request.MsgContBody可正确接收客户端参数 return await Task.FromResult(new myResponse()); } } // 匹配客户端的method1包裹结构,直接将msgContBody作为消息体成员 [MessageContract(WrapperNamespace = "http://www.test.me/method/", WrapperName = "method1")] public class myRequest { // Name对应客户端的msgContBody标签,类型为单个rootPar(客户端中是单个msgContBody节点) [MessageBodyMember(Name = "msgContBody", Namespace = "")] public rootPar MsgContBody; } [DataContract(Namespace = "")] public class rootPar { [DataMember(Name = "par1", Order = 1)] public string Par1 { get; set; } [DataMember(Name = "descPar1", Order = 2)] public string DescPar1 { get; set; } [DataMember(Name = "par2", Order = 3)] public string Par2 { get; set; } [DataMember(Name = "descPar2", Order = 4)] public string DescPar2 { get; set; } // 指定DataMember的Name为arrayPar,序列化时直接生成多个<arrayPar>节点,无需外层包装 [DataMember(Name = "arrayPar", Order = 5, IsRequired = false)] public arrPar[] ArrayPar { get; set; } } [DataContract(Namespace = "")] public class arrPar { [DataMember(Name = "Id", Order = 1)] public string Id { get; set; } [DataMember(Name = "Desc", Order = 2)] public string Desc { get; set; } } // 响应契约同样匹配旧WSDL结构 [MessageContract(WrapperNamespace = "http://www.test.me/method/", WrapperName = "method1Response")] public class myResponse { [MessageBodyMember(Name = "msgContBodyResponse", Namespace = "")] public rootResponse ResponseBody { get; set; } } [DataContract(Namespace = "")] public class rootResponse { // 根据旧WSDL定义响应字段 [DataMember(Name = "code")] public string Code { get; set; } [DataMember(Name = "message")] public string Message { get; set; } }
关键修正点说明
- MessageContract调整:将
myRequest的MessageBodyMember名称改为msgContBody,与客户端XML节点名一致,且类型设为单个rootPar(客户端中msgContBody是单个节点,而非数组)。 - 数组字段修正:
rootPar中的数组字段ArrayPar,通过[DataMember(Name = "arrayPar")]指定序列化后的节点名,这样CoreWCF会直接生成多个<arrayPar>节点,不会额外添加外层包装。 - 命名空间与顺序:所有数据契约的
Namespace设为空,与客户端XML中的非命名空间节点匹配;添加Order属性确保节点顺序与旧WSDL一致。 - 参数接收验证:修正后客户端发送的XML会正确绑定到
request.MsgContBody,不会出现参数为空的问题。
内容的提问来源于stack exchange,提问作者dpope
相关产品推荐
相关产品推荐

