1

Using Postman, C#, .NET Framework 4.7

I make a GET request from Postman with content-accept set to "application/xml" and my .NET Framework Web API will respond with XML (brilliant!). I have not needed to serialize anything manually as .NET Framework serializes my response object with when I return Request.CreateResponse(HttpStatusCode.OK, myResponse).

However, it seems to include extra things which I am not familiar with and I am wondering if they can be removed via Global.asax settings or similar?

  • xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels" is something I would like to remove!
  • "d3p1" is not something I have come across when creating XML. Can I remove it somehow?
  • <error i:nil="true" /> pops up when something is null. Is it possible to just be or just not appear when it is null?

So, The XML response looks like this:

<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>

My classes look something like this:

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; }
}
dbc
  • 104,963
  • 20
  • 228
  • 340
PKCS12
  • 407
  • 15
  • 41
  • The schema is needed to validate the xml. The validation is finding missing values which is giving the nil = true. – jdweng Feb 13 '20 at 20:38

1 Answers1

2

xmlns="http://schemas.datacontract.org/2004/07/dto.MyModels" is something I would like to remove!
"d3p1" is not something I have come across when creating XML. Can I remove it somehow?

The attributes:

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

are both XML namespace declarations. The first establishes a default XML namespace for your XML document; the second declares a namespace to which all child elements prefaced with d3p1: belong.

From the specific namespace chosen, it's apparent you are using DataContractSerializer for XML serialization. This serializer assigns XML namespaces according to rules documented in Data Contract Names: Data Contract Namespaces

By default, any given CLR namespace (in the format Clr.Namespace) is mapped to the namespace http://schemas.datacontract.org/2004/07/Clr.Namespace. To override this default, apply the ContractNamespaceAttribute attribute to the entire module or assembly. Alternatively, to control the data contract namespace for each type, set the Namespace property of the DataContractAttribute.

Since you don't want an XML namespace for any of your types, the first option would appear to be the easiest: apply the following attributes to your assembly:

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

Alternatively, you could apply data contract attributes to your types:

[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; }
}

Note that data contract serialization is opt-in so you will need to apply [DataMember] to each member to be serialized.

As a final alternative, you could switch to using XmlSerializer which has no default XML namespace. To do that you will need to apply [XmlSerializerFormat] to your service contract as shown in Manually Switching to the XmlSerializer.

<error i:nil="true" /> pops up when something is null. Is it possible to just be or just not appear when it is null?

These null elements can be removed by setting DataMemberAttribute.EmitDefaultValue on reference type data members as shown in this answer to Can I configure the DataContractSerializer to not create optional (i.e. Nullable<> and List<>) elements in output XML? by 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; }
}

Alternatively you could switch to XmlSerializer which does not output null reference values by default.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thank you for your amazing response. I have not marked it as answer yet as I need a bit of time to process and also test things out. Much appreciated for your time and effort! – PKCS12 Feb 18 '20 at 10:21
  • In order to achieve what I wanted (no namespaces, no d3p1 and no nill values) I added ContractNamespaceAttribute to clear the clrNamespace AND also turned on use xmlSerializer=true in global.asx. Is that weird and is it bad?? – PKCS12 Mar 02 '20 at 12:21
  • 1
    @PKCS12 - It's not harmful, but once you have switched to using `XmlSerializer`, setting `ContractNamespaceAttribute` becomes unnecessary. – dbc Mar 02 '20 at 19:47
  • omg, thank you so much for pointing this out. I just did a full 360. I had the solution to what I wanted all along but had muddled it with data contract serialization :(( – PKCS12 Mar 03 '20 at 16:17