.net Web API自動反序列化xml傳參為C#實體

南山有榛發表於2024-10-19

Program.cs

.net 8.0已經內建了XML解析器,所以直接在services.AddControllers()後呼叫AddXmlSerializerFormatters()即可:

services.AddControllers().AddXmlSerializerFormatters();

定義實體

需要用到幾個特性:

  1. XmlRoot:xml的根節點
  2. XmlElement:xml的成員
    例:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:i="http://i.api.ei.nxyincfuyou.iih/">
	<soapenv:Header/>
	<soapenv:Body>
		<i:apiEntry>
			<i:arg0>SI0084</i:arg0>
			<i:arg1>
				<![CDATA[
				<iihparam>
					<Code_user>00000</Code_user>
					<Code_dep></Code_dep>
					<Code_external>IIH</Code_external>
					<Data>
						<Code_dep></Code_dep>
						<Code_nur>00034</Code_nur>
						<Sd_status>25</Sd_status>
						<Date_b_in></Date_b_in>
						<Date_e_in></Date_e_in>
						<Date_b_out></Date_b_out>
						<Date_e_out></Date_e_out>
						<Date_b_update></Date_b_update>
						<Date_e_update></Date_e_update>
						<Pageinfos>
							<Pageinfo>
								<Pagesize>200</Pagesize>
								<Pageindex>1</Pageindex>
								<Pagecount></Pagecount>
								<Recordscount></Recordscount>
							</Pageinfo>
						</Pageinfos>
					</Data>
				</iihparam>
				]]>
			</i:arg1>
		</i:apiEntry>
	</soapenv:Body>
</soapenv:Envelope>
// 根元素
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class H5_InpatientDataXML
{
    [XmlElement(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public Header Header { get; set; }

    [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public Body Body { get; set; }
}

public class Header
{
    // 你可以新增更多的頭資訊屬性,如果需要的話
}

public class Body
{
    [XmlElement(ElementName = "apiEntry", Namespace = "http://i.api.ei.nxyincfuyou.iih/")]
    public ApiEntry ApiEntry { get; set; }
}

public class ApiEntry
{
    [XmlElement(ElementName = "arg0", Namespace = "http://i.api.ei.nxyincfuyou.iih/")]
    public string Arg0 { get; set; }

    [XmlElement(ElementName = "arg1", Namespace = "http://i.api.ei.nxyincfuyou.iih/")]
    public CData<IihParam> Arg1 { get; set; }
}
// Arg1中的巢狀 XML
[XmlRoot(ElementName = "iihparam")]
public class IihParam
{
    [XmlElement(ElementName = "Code_user")]
    public string CodeUser { get; set; }

    [XmlElement(ElementName = "Code_dep")]
    public string CodeDep { get; set; }

    [XmlElement(ElementName = "Code_external")]
    public string CodeExternal { get; set; }

    [XmlElement(ElementName = "Data")]
    public Data Data { get; set; }
}

public class Data
{
    [XmlElement(ElementName = "Code_dep")]
    public string CodeDep { get; set; }

    [XmlElement(ElementName = "Code_nur")]
    public string CodeNur { get; set; }

    [XmlElement(ElementName = "Sd_status")]
    public string SdStatus { get; set; }

    [XmlElement(ElementName = "Date_b_in")]
    public string DateBIn { get; set; }

    [XmlElement(ElementName = "Date_e_in")]
    public string DateEIn { get; set; }

    [XmlElement(ElementName = "Date_b_out")]
    public string DateBOut { get; set; }

    [XmlElement(ElementName = "Date_e_out")]
    public string DateEOut { get; set; }

    [XmlElement(ElementName = "Date_b_update")]
    public string DateBUpdate { get; set; }

    [XmlElement(ElementName = "Date_e_update")]
    public string DateEUpdate { get; set; }

    [XmlElement(ElementName = "Pageinfos")]
    public PageInfos PageInfos { get; set; }
}

public class PageInfos
{
    [XmlElement(ElementName = "Pageinfo")]
    public List<PageInfo> PageInfoList { get; set; }
}

public class PageInfo
{
    [XmlElement(ElementName = "Pagesize")]
    public string PageSize { get; set; }

    [XmlElement(ElementName = "Pageindex")]
    public string PageIndex { get; set; }

    [XmlElement(ElementName = "Pagecount")]
    public string PageCount { get; set; }

    [XmlElement(ElementName = "Recordscount")]
    public string RecordsCount { get; set; }
}

這裡注意,CDATA區域需要自定義序列化方式以便框架呼叫,CDATA類:

public class CData<T> : IXmlSerializable where T : class
{
    public T Value { get; set; }
    public XmlSchema GetSchema() => null;

    public void ReadXml(XmlReader reader)
    {
        if (reader.IsEmptyElement)
        {
            reader.Read();
            Value = null;
        }
        else
        {
            string content = reader.ReadElementContentAsString();
            if (!string.IsNullOrEmpty(content))
            {
                var serializer = new XmlSerializer(typeof(T));
                using (var stringReader = new StringReader(content))
                {
                    Value = (T)serializer.Deserialize(stringReader);
                }
            }
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        if (Value != null)
        {
            var serializer = new XmlSerializer(typeof(T));
            using (var stringWriter = new StringWriter())
            {
                serializer.Serialize(stringWriter, Value);
                writer.WriteCData(stringWriter.ToString());
            }
        }
    }

    public static implicit operator CData<T>(T value)
    {
        return new CData<T> { Value = value };
    }

    public static implicit operator T(CData<T> cdata)
    {
        return cdata?.Value;
    }
}

另外注意資料型別一般都是string,之前對於PageCount使用了int,測試時發現會報錯。

Controller使用

        /// <summary>
        /// 獲取患者的xml格式資料
        /// </summary>
        /// <param name="xmlData"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("TestXML")]
        public async Task<IActionResult> TestXML([FromBody] H5_InpatientDataXML envelope)
        {
            return Ok(envelope);
        }

相關文章