如何用C#输入对象生成SOAP请求并反序列化SOAP响应为C#对象
实现SOAP请求生成与响应反序列化(基于C#)
需求说明
需要完成两项核心任务:
- 基于C#
CustomerRequest对象动态生成符合指定格式的SOAP请求 - 将返回的SOAP响应解析并反序列化为C#
CustomerResponse对象
一、从CustomerRequest生成SOAP请求
输入的CustomerRequest类
public class CustomerRequest { public int CustomerID { get; set; } public string CustomerName { get; set; } public string CustomerNum { get; set; } }
实现方式1:字符串模板替换(简单直接)
利用预定义的SOAP请求模板,把CustomerRequest的属性值替换到对应位置,适合结构固定的场景:
public string GenerateSoapRequest(CustomerRequest request) { var soapTemplate = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:bsvc=""urn:com.workday/bsvc""> <soapenv:Header> <bsvc:Workday_Common_Header> <bsvc:Include_Reference_Descriptors_In_Response>1</bsvc:Include_Reference_Descriptors_In_Response> </bsvc:Workday_Common_Header> </soapenv:Header> <soapenv:Body> <bsvc:Get_Customers_Request bsvc:version=""v42.0""> <bsvc:Request_References> <bsvc:Customer_Reference bsvc:Descriptor=""?""> <bsvc:ID bsvc:type=""Customer_ID"">{0}</bsvc:ID> <bsvc:Customer_Name>{1}</bsvc:Customer_Name> <bsvc:Customer_Num>{2}</bsvc:Customer_Num> </bsvc:Customer_Reference> </bsvc:Request_References> <bsvc:Response_Group> <bsvc:Include_Reference>1</bsvc:Include_Reference> <bsvc:Include_Customer_Data>1</bsvc:Include_Customer_Data> <bsvc:Include_Customer_Balance>1</bsvc:Include_Customer_Balance> <bsvc:Include_Customer_Activity_Detail>1</bsvc:Include_Customer_Activity_Detail> </bsvc:Response_Group> </bsvc:Get_Customers_Request> </soapenv:Body> </soapenv:Envelope>"; return string.Format(soapTemplate, request.CustomerID, request.CustomerName, request.CustomerNum); }
实现方式2:XmlSerializer序列化SOAP实体类(规范可控)
先定义与SOAP请求结构完全对应的实体类,再通过XmlSerializer序列化生成请求,适合需要动态调整请求结构的场景:
// SOAP信封实体类 [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public class SoapEnvelope { [XmlElement(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public SoapHeader Header { get; set; } [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public SoapBody Body { get; set; } } public class SoapHeader { [XmlElement(ElementName = "Workday_Common_Header", Namespace = "urn:com.workday/bsvc")] public WorkdayCommonHeader WorkdayCommonHeader { get; set; } } public class WorkdayCommonHeader { [XmlElement(ElementName = "Include_Reference_Descriptors_In_Response", Namespace = "urn:com.workday/bsvc")] public string IncludeReferenceDescriptorsInResponse { get; set; } = "1"; } public class SoapBody { [XmlElement(ElementName = "Get_Customers_Request", Namespace = "urn:com.workday/bsvc")] public GetCustomersRequest GetCustomersRequest { get; set; } } public class GetCustomersRequest { [XmlAttribute(AttributeName = "version", Namespace = "urn:com.workday/bsvc")] public string Version { get; set; } = "v42.0"; [XmlElement(ElementName = "Request_References", Namespace = "urn:com.workday/bsvc")] public RequestReferences RequestReferences { get; set; } [XmlElement(ElementName = "Response_Group", Namespace = "urn:com.workday/bsvc")] public ResponseGroup ResponseGroup { get; set; } } public class RequestReferences { [XmlElement(ElementName = "Customer_Reference", Namespace = "urn:com.workday/bsvc")] public CustomerReference CustomerReference { get; set; } } public class CustomerReference { [XmlAttribute(AttributeName = "Descriptor", Namespace = "urn:com.workday/bsvc")] public string Descriptor { get; set; } = "?"; [XmlElement(ElementName = "ID", Namespace = "urn:com.workday/bsvc")] public ID Id { get; set; } [XmlElement(ElementName = "Customer_Name", Namespace = "urn:com.workday/bsvc")] public string CustomerName { get; set; } [XmlElement(ElementName = "Customer_Num", Namespace = "urn:com.workday/bsvc")] public string CustomerNum { get; set; } } public class ID { [XmlAttribute(AttributeName = "type", Namespace = "urn:com.workday/bsvc")] public string Type { get; set; } = "Customer_ID"; [XmlText] public string Value { get; set; } } public class ResponseGroup { [XmlElement(ElementName = "Include_Reference", Namespace = "urn:com.workday/bsvc")] public string IncludeReference { get; set; } = "1"; [XmlElement(ElementName = "Include_Customer_Data", Namespace = "urn:com.workday/bsvc")] public string IncludeCustomerData { get; set; } = "1"; [XmlElement(ElementName = "Include_Customer_Balance", Namespace = "urn:com.workday/bsvc")] public string IncludeCustomerBalance { get; set; } = "1"; [XmlElement(ElementName = "Include_Customer_Activity_Detail", Namespace = "urn:com.workday/bsvc")] public string IncludeCustomerActivityDetail { get; set; } = "1"; } // 生成SOAP请求的方法 public string GenerateSoapRequestWithSerializer(CustomerRequest request) { var soapEnvelope = new SoapEnvelope { Header = new SoapHeader(), Body = new SoapBody { GetCustomersRequest = new GetCustomersRequest { RequestReferences = new RequestReferences { CustomerReference = new CustomerReference { Id = new ID { Value = request.CustomerID.ToString() }, CustomerName = request.CustomerName, CustomerNum = request.CustomerNum } } } } }; var serializer = new XmlSerializer(typeof(SoapEnvelope)); using var stringWriter = new StringWriter(); serializer.Serialize(stringWriter, soapEnvelope); return stringWriter.ToString(); }
二、将SOAP响应反序列化为CustomerResponse
目标CustomerResponse类
public class CustomerResponse { public int CustomerID { get; set; } public string WID { get; set; } public string CustomerCategory { get; set; } public string PaymentType { get; set; } public decimal YTDSalesAmt { get; set; } public decimal TotalBalance { get; set; } }
实现方式1:XPath提取字段(轻量高效)
直接解析SOAP响应XML,通过XPath定位需要的字段值,适合只需要提取部分字段的场景:
public CustomerResponse DeserializeSoapResponse(string soapResponse) { var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(soapResponse); var nsManager = new XmlNamespaceManager(xmlDoc.NameTable); nsManager.AddNamespace("env", "http://schemas.xmlsoap.org/soap/envelope/"); nsManager.AddNamespace("wd", "urn:com.workday/bsvc"); var response = new CustomerResponse(); // 提取CustomerID var customerIdNode = xmlDoc.SelectSingleNode("//wd:ID[@wd:type='Customer_ID']", nsManager); if (customerIdNode != null) int.TryParse(customerIdNode.InnerText, out response.CustomerID); // 提取WID var widNode = xmlDoc.SelectSingleNode("//wd:ID[@wd:type='WID']", nsManager); if (widNode != null) response.WID = widNode.InnerText; // 提取YTD销售额 var ytdSalesNode = xmlDoc.SelectSingleNode("//wd:YTD_Sales_Amount", nsManager); if (ytdSalesNode != null) decimal.TryParse(ytdSalesNode.InnerText, out response.YTDSalesAmt); // 提取总余额 var totalBalanceNode = xmlDoc.SelectSingleNode("//wd:Total_Balance", nsManager); if (totalBalanceNode != null) decimal.TryParse(totalBalanceNode.InnerText, out response.TotalBalance); // 注:CustomerCategory和PaymentType在示例响应中未出现,需根据实际响应结构补充XPath return response; }
实现方式2:XmlSerializer序列化响应实体类(规范完整)
定义与SOAP响应结构对应的实体类,通过XmlSerializer反序列化后映射到CustomerResponse,适合需要完整解析响应的场景:
// SOAP响应信封实体类 [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public class SoapResponseEnvelope { [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public SoapResponseBody Body { get; set; } } public class SoapResponseBody { [XmlElement(ElementName = "Get_Customers_Response", Namespace = "urn:com.workday/bsvc")] public GetCustomersResponse GetCustomersResponse { get; set; } } public class GetCustomersResponse { [XmlAttribute(AttributeName = "version", Namespace = "urn:com.workday/bsvc")] public string Version { get; set; } [XmlElement(ElementName = "Request_References", Namespace = "urn:com.workday/bsvc")] public ResponseRequestReferences RequestReferences { get; set; } [XmlElement(ElementName = "Response_Data", Namespace = "urn:com.workday/bsvc")] public ResponseData ResponseData { get; set; } } public class ResponseRequestReferences { [XmlElement(ElementName = "Customer_Reference", Namespace = "urn:com.workday/bsvc")] public ResponseCustomerReference CustomerReference { get; set; } } public class ResponseCustomerReference { [XmlElement(ElementName = "ID", Namespace = "urn:com.workday/bsvc")] public List<ResponseID> IDs { get; set; } } public class ResponseID { [XmlAttribute(AttributeName = "type", Namespace = "urn:com.workday/bsvc")] public string Type { get; set; } [XmlText] public string Value { get; set; } } public class ResponseData { [XmlElement(ElementName = "Customer", Namespace = "urn:com.workday/bsvc")] public Customer Customer { get; set; } } public class Customer { [XmlElement(ElementName = "Customer_Balance_Data", Namespace = "urn:com.workday/bsvc")] public CustomerBalanceData CustomerBalanceData { get; set; } } public class CustomerBalanceData { [XmlElement(ElementName = "YTD_Sales_Amount", Namespace = "urn:com.workday/bsvc")] public decimal YtdSalesAmount { get; set; } [XmlElement(ElementName = "Total_Balance", Namespace = "urn:com.workday/bsvc")] public decimal TotalBalance { get; set; } } // 反序列化方法 public CustomerResponse DeserializeSoapResponseWithSerializer(string soapResponse) { var serializer = new XmlSerializer(typeof(SoapResponseEnvelope)); using var stringReader = new StringReader(soapResponse); var envelope = (SoapResponseEnvelope)serializer.Deserialize(stringReader); var response = new CustomerResponse(); // 提取CustomerID和WID var customerIds = envelope.Body.GetCustomersResponse.RequestReferences.CustomerReference.IDs; response.CustomerID = int.Parse(customerIds.First(id => id.Type == "Customer_ID").Value); response.WID = customerIds.First(id => id.Type == "WID").Value; // 提取余额数据 var balanceData = envelope.Body.GetCustomersResponse.ResponseData.Customer.CustomerBalanceData; response.YTDSalesAmt = balanceData.YtdSalesAmount; response.TotalBalance = balanceData.TotalBalance; // 注:CustomerCategory和PaymentType需根据实际响应结构补充实体类属性 return response; }
内容的提问来源于stack exchange,提问作者Rita
相关产品推荐
相关产品推荐

