XML API 请求为数组或子类返回“d3p1”

Posted

技术标签:

【中文标题】XML API 请求为数组或子类返回“d3p1”【英文标题】:XML API Request returns "d3p1" for arrays or sub-classes 【发布时间】:2020-05-29 12:58:44 【问题描述】:

使用 Postman、C#、.NET Framework 4.7

我从 Postman 发出 GET 请求,内容接受设置为“application/xml”,我的 .NET Framework Web API 将以 XML 响应(太棒了!)。当我返回 Request.CreateResponse(HttpStatusCode.OK, myResponse) 时,我不需要手动序列化任何内容,因为 .NET Framework 会序列化我的响应对象。

但是,它似乎包含了我不熟悉的额外内容,我想知道它们是否可以通过 Global.asax 设置或类似设置删除?

xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels" 是我想删除的东西! “d3p1”不是我在创建 XML 时遇到的。我可以以某种方式删除它吗? <error i:nil="true" /> 在某些内容为空时弹出。当它为空时,是否有可能只是出现或不出现?

因此,XML 响应如下所示:

<SimpleResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels">
    <error i:nil="true" />
    <result>
        <bookList xmlns:d3p1="http://schemas.datacontract.org/2004/07/dto.MyModels.Shared">
            <d3p1:Book>
                <d3p1:bookname>Book 1 Name</d3p1:bookname>
                <d3p1:serial>ZMeTaQ1kejh0mJYGHE4+1a4Y2juU6tMDd5zYDqN4tqI=</d3p1:serial>
                <d3p1:id>4</d3p1:id>

            </d3p1:Book>
            <d3p1:Book>
                <d3p1:bookname>Hello World</d3p1:bookname>
                <d3p1:serial>9lM16kho3bgsrG+wRh4ejtZjwrYJwp6FbRqnnZ4CJPA=</d3p1:serial>
                <d3p1:id>5</d3p1:id>
            </d3p1:Book>
            <d3p1:Book>
                <d3p1:bookname>Ding</d3p1:bookname>
                <d3p1:serial>XCqqKB+Wi3i4z6nN1Ry8IHtar6ogojjiqxMfvfgC0qc=</d3p1:serial>
                <d3p1:id>6</d3p1:id>
            </d3p1:Book>
        </bookList>
        <author xmlns:d3p1="http://schemas.datacontract.org/2004/07/dto.Models.android.Shared">
            <d3p1:pictureId>0</d3p1:pictureId>
            <d3p1:websiteurl i:nil="true" />
            <d3p1:email i:nil="true" />
            <d3p1:name>Jo Blogs</d3p1:size>
            <d3p1:age>0</d3p1:size>
        </author>
    </result>
</SimpleResponse>

我的课程看起来像这样:

public string error  get; set;
public class SimpleResponse 

 public List<Book> bookList  get; set; 
 public Author author  get; set; 


public class Book

    public string bookname  get; set; 
    public string serial  get; set; 
    public int id  get; set; 


public class Author

    public string pictureId get; set; 
    public string websiteurl  get; set; 
    public string email  get; set; 
    public string name  get; set; 
    public int age  get; set; 

【问题讨论】:

验证 xml 需要架构。验证正在寻找缺失值,这给出了 nil = true。 【参考方案1】:

xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels" 是我想删除的东西! “d3p1”不是我在创建 XML 时遇到的。我可以以某种方式删除它吗?

属性:

xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels" xmlns:d3p1="http://schemas.datacontract.org/2004/07/dto.MyModels.Shared"

都是XML namespace declarations。第一个为您的 XML 文档建立一个默认的 XML 命名空间;第二个声明了一个命名空间,所有以d3p1: 开头的子元素都属于该命名空间。

从选择的特定命名空间来看,很明显您正在使用DataContractSerializer 进行 XML 序列化。此序列化程序根据 Data Contract Names: Data Contract Namespaces

中记录的规则分配 XML 命名空间

默认情况下,任何给定的 CLR 命名空间(格式为 Clr.Namespace)都映射到命名空间 http://schemas.datacontract.org/2004/07/Clr.Namespace。要覆盖此默认值,请将ContractNamespaceAttribute 属性应用于整个模块或程序集。或者,要控制每种类型的数据协定命名空间,请设置DataContractAttribute 的Namespace 属性。

由于您不希望任何类型的 XML 命名空间,第一个选项似乎是最简单的:将以下属性应用于您的程序集:

[assembly: ContractNamespaceAttribute("", ClrNamespace = "dto.MyModels")]
[assembly: ContractNamespaceAttribute("", ClrNamespace = "dto.MyModels.Shared")]
[assembly: ContractNamespaceAttribute("", ClrNamespace = "dto.Models.Android.Shared")]

或者,您可以将data contract attributes 应用于您的类型:

[DataContract(Name = "Book", Namespace = "")]
public class Book

    [DataMember]
    public string bookname  get; set; 
    [DataMember]
    public string serial  get; set; 
    [DataMember]
    public int id  get; set; 

请注意,数据合约序列化是opt-in,因此您需要将[DataMember] 应用于要序列化的每个成员。

作为最后一种选择,您可以切换到使用没有默认 XML 命名空间的 XmlSerializer。为此,您需要将[XmlSerializerFormat] 应用于您的服务合同,如Manually Switching to the XmlSerializer 所示。

&lt;error i:nil="true" /&gt; 在某些内容为空时弹出。当它为空时是否可以出现或不出现?

这些 null 元素可以通过在引用类型数据成员上设置 DataMemberAttribute.EmitDefaultValue 来删除,如 this answer 中所示的 Can I configure the DataContractSerializer to not create optional (i.e. Nullable<> and List<>) elements in output XML? Darren Clark:

[DataContract(Name = "Book", Namespace = "")]
public class Book

    [DataMember(EmitDefaultValue = false)]
    public string bookname  get; set; 
    [DataMember(EmitDefaultValue = false)]
    public string serial  get; set; 
    [DataMember]
    public int id  get; set; 

您也可以切换到XmlSerializer,默认情况下不输出空引用值。

【讨论】:

感谢您的精彩回复。我还没有将它标记为答案,因为我需要一些时间来处理和测试。非常感谢您的时间和精力! 为了实现我想要的(无命名空间、无 d3p1 和无 nill 值),我添加了 ContractNamespaceAttribute 以清除 clrNamespace 并在 global.asx 中启用了使用 xmlSerializer=true。这很奇怪,很糟糕吗?? @PKCS12 - 没有害处,但是一旦你切换到使用XmlSerializer,就不需要设置ContractNamespaceAttribute了。 omg,非常感谢您指出这一点。我刚刚做了一个完整的 360。我一直都有我想要的解决方案,但是用数据合同序列化把它弄糊涂了 :((

以上是关于XML API 请求为数组或子类返回“d3p1”的主要内容,如果未能解决你的问题,请参考以下文章

在开始和结束时间之间过滤数组或 XML

C# Web API 基于 GET 请求的 XML 或 JSON

如何从 PHP 中获取远程 JSON 或 XML API 数据并将返回对象分配为 PHP 变量?

一个restful api可以返回一个页面作为响应吗?

Web API 接口规范

Spring MVC REST - 根据请求内容类型返回 xml 或 json