基于.NET Core搭建SOAP服务:如何处理SOAP头与PingRq标签属性
实现方案
1. 处理SOAP头(WSSE安全头)
首先定义请求头对应模型,匹配OASIS WSSE规范的命名空间:
using System.Xml.Serialization; [XmlRoot(ElementName = "Security", Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")] public class WsseSecurityHeader { [XmlElement(ElementName = "UsernameToken")] public UsernameTokenInfo UsernameToken { get; set; } } public class UsernameTokenInfo { [XmlElement(ElementName = "Username")] public string Username { get; set; } [XmlElement(ElementName = "Password")] public PasswordInfo Password { get; set; } } public class PasswordInfo { [XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")] public string Type { get; set; } [XmlText] public string Value { get; set; } } // 响应头模型 [XmlRoot(ElementName = "Security", Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")] public class ResponseSecurityHeader { [XmlText] public bool Value { get; set; } }
2. 处理PingRq/PingRS模型的属性
直接给对应字段加XmlAttribute特性标记即可匹配XML节点的属性:
// 请求体模型 [XmlRoot(ElementName = "PingRq", Namespace = "http://www.opentravel.org/OTA/2003/05")] public class PingRq { [XmlAttribute(AttributeName = "EchoToken")] public string EchoToken { get; set; } [XmlAttribute(AttributeName = "TimeStamp")] public DateTime TimeStamp { get; set; } [XmlAttribute(AttributeName = "Version")] public string Version { get; set; } [XmlElement(ElementName = "EchoData")] public string EchoData { get; set; } } // 响应体模型 [XmlRoot(ElementName = "PingRS", Namespace = "http://www.opentravel.org/OTA/2003/05")] public class PingRS { [XmlAttribute(AttributeName = "EchoToken")] public string EchoToken { get; set; } [XmlAttribute(AttributeName = "TimeStamp")] public DateTime TimeStamp { get; set; } [XmlElement(ElementName = "Success")] public object Success { get; set; } = new object(); // 空标签直接赋值空对象即可 [XmlElement(ElementName = "EchoData")] public string EchoData { get; set; } }
3. 定义服务契约与实现
using System.ServiceModel; using System.ServiceModel.Channels; using SoapCore; [ServiceContract(Namespace = "http://www.opentravel.org/OTA/2003/05")] public interface IOTAService { [OperationContract] PingRS Ping([FromHeader] WsseSecurityHeader securityHeader, PingRq request); } public class OTAService : IOTAService { public PingRS Ping(WsseSecurityHeader securityHeader, PingRq request) { // 校验securityHeader中的用户名密码逻辑可在此处实现 // 注入响应头 var responseHeader = new ResponseSecurityHeader { Value = true }; OperationContext.Current.OutgoingMessageHeaders.Add( MessageHeader.CreateHeader( "Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", responseHeader ) ); // 构造响应体 return new PingRS { EchoToken = $"PHOBS89d7ec6d6e{request.EchoToken}", TimeStamp = DateTime.UtcNow, EchoData = request.EchoData }; } }
4. 注册SoapCore服务
.NET 6+ Program.cs配置:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddScoped<IOTAService, OTAService>(); builder.Services.AddSoapCore(); var app = builder.Build(); // 绑定SOAP服务端点,必须指定XmlSerializer才能正确序列化XmlAttribute属性 app.UseSoapEndpoint<IOTAService>("/OTAService.asmx", new SoapEncoderOptions(), SoapSerializer.XmlSerializer); app.Run();
内容的提问来源于stack exchange,提问作者Rémy
相关产品推荐
相关产品推荐

