.NET Core 9+SoapCore:移除Action节点后参数为null问题排查
SoapCore请求参数返回null问题排查与解决
问题描述
我正在学习SoapCore,希望SOAP请求的Body中直接显示函数参数,不包含Action节点。代码编写看似正确,但函数参数始终返回null。使用的是.NET Core 9搭配SoapCore,相关代码、请求及响应信息如下:
服务端代码
builder.Services.AddSoapCore(); app.UseEndpoints(endpoints => { _ = endpoints.UseSoapEndpoint<DataContractServices>("/DataContract.asmx", new SoapEncoderOptions(), SoapSerializer.DataContractSerializer); }); [ServiceContract(Namespace = "https://service.com/")] public class DataContractServices { [OperationContract(Name = "loginMethod")] public string LoginMethod(LoginRequest input) => $"Username: {input.Username}| Password: {input.Password}"; } [MessageContract(IsWrapped = true, WrapperName = "LoginRequest", WrapperNamespace = "https://service.com/")] public class LoginRequest { [MessageBodyMember(Name = "username")] public string Username { get; set; } = string.Empty; [MessageBodyMember(Name = "password")] public string Password { get; set; } = string.Empty; }
请求内容
POST http://localhost:5000/DataContract.asmx Content-Type: text/xml; charset=utf-8 SOAPAction: https://service.com/loginMethod <?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pay="https://service.com/"> <soapenv:Header/> <soapenv:Body> <pay:LoginRequest> <pay:username>myUsername</pay:username> <pay:password>myPassword</pay:password> </pay:LoginRequest> </soapenv:Body> </soapenv:Envelope>
响应内容
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <s:Body> <loginMethodResponse xmlns="https://service.com/"> <loginMethodResult>Username: | Password:</loginMethodResult> </loginMethodResponse> </s:Body> </s:Envelope>
问题根源
请求中的username和password元素通过pay前缀关联到https://service.com/命名空间,但代码中MessageBodyMember属性未指定对应命名空间,默认使用空命名空间,导致DataContractSerializer无法匹配请求中的元素,最终参数值为null。
解决方法
方案一:为MessageBodyMember指定命名空间
修改LoginRequest类的属性,给每个MessageBodyMember添加命名空间配置,与请求中的命名空间保持一致:
[MessageContract(IsWrapped = true, WrapperName = "LoginRequest", WrapperNamespace = "https://service.com/")] public class LoginRequest { [MessageBodyMember(Name = "username", Namespace = "https://service.com/")] public string Username { get; set; } = string.Empty; [MessageBodyMember(Name = "password", Namespace = "https://service.com/")] public string Password { get; set; } = string.Empty; }
方案二:修改请求,移除子元素的命名空间前缀
如果希望参数元素不使用命名空间,调整请求XML,去掉username和password的pay前缀:
<?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pay="https://service.com/"> <soapenv:Header/> <soapenv:Body> <pay:LoginRequest> <username>myUsername</username> <password>myPassword</password> </pay:LoginRequest> </soapenv:Body> </soapenv:Envelope>
扩展:实现Body直接显示参数(无Wrapper)
如果要实现请求Body中直接显示参数、不包含Wrapper节点,可修改MessageContract的IsWrapped为false,同时调整代码和请求:
修改后的LoginRequest类
[MessageContract(IsWrapped = false)] public class LoginRequest { [MessageBodyMember(Name = "username", Namespace = "https://service.com/")] public string Username { get; set; } = string.Empty; [MessageBodyMember(Name = "password", Namespace = "https://service.com/")] public string Password { get; set; } = string.Empty; }
对应的请求XML
<?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pay="https://service.com/"> <soapenv:Header/> <soapenv:Body> <pay:username>myUsername</pay:username> <pay:password>myPassword</pay:password> </soapenv:Body> </soapenv:Envelope>
内容的提问来源于stack exchange,提问作者Harun
相关产品推荐
相关产品推荐

