EDIT
XML Input would look like this
<?xml version="1.0" encoding="UTF-8"?>
<Object1>
<field1>Hello</field1>
<field2>
<field3>World</field3>
<field4>
<field5>Test</field5>
<field6>Test2</field6>
</field4>
</field2>
</Object1>
I am a bit stuck on how to get my API to accept a complex XML object
For example, I have a class that is like this
public class Object1
{
public string field1 {get; set;}
public Object2 field2 {get; set;}
}
public class Object2
{
public string field3 {get; set;}
public Object3 field4 {get; set;}
}
public class Object3
{
public string field5 {get; set;}
public string field6 {get; set;}
}
In my startup.cs file, I added this
services.AddControllers().AddXmlDataContractSerializerFormatters()
.AddXmlSerializerFormatters();
I then got the error that it could not deserialize the input.
So I added these Attributes to the object
[DataContract(Namespace = "")]
[XmlRoot]
public class Object1
{
[DataMember(Name = "field1")]
public string field1 {get; set;}
[DataMember(Name = "field2")]
public Object2 field2 {get; set;}
}
[DataContract(Name = "field2", IsReference = true)]
public class Object2
{
[DataMember(Name = "field3")]
public string field3 {get; set;}
[DataMember(Name = "field4")]
public Object3 field4 {get; set;}
}
[DataContract(Name = "field3", IsReference = true)]
public class Object3
{
[DataMember(Name = "field5")]
public string field5 {get; set;}
[DataMember(Name = "field6")]
public string field6 {get; set;}
}
So now when I send the XML object over, it is now able to be somewhat worked on. I can get the field1 value and it looks like the field2 object is no longer null, but everything inside of it is null.
I am not sure how to approach this properly. Anything I am missing?
My Controller looks like this
[HttpPost]
[Consumes("application/xml")]
public async Task<IActionResult> UpdateObject([FromBody]Object1 object1)
{
var testObject1 = object1.field1; // this value is not null because it is a string datatype and not like the one below which is slightly more complex
var testObject2 = object1.field2; //this is not null but the properties inside the object are null
}
CodePudding user response:
You need set the DataContractAttribute.Namespace for Object2 and Object3 as well:
[DataContract(Namespace = "", Name = "field2", IsReference = true)]
public class Object2
{
[DataMember(Name = "field3")]
public string field3 {get; set;}
[DataMember(Name = "field4")]
public Object3 field4 {get; set;}
}
[DataContract(Namespace = "", Name = "field3", IsReference = true)]
public class Object3
{
[DataMember(Name = "field5")]
public string field5 {get; set;}
[DataMember(Name = "field6")]
public string field6 {get; set;}
}
Demo fiddle #1 here.
Notes:
With the data contract serializer, if you do not explicitly specify a namespace for a data contract object, a default is assigned as explained in the docs:
By default, data contracts for a particular type are assigned a namespace that comes from the common language runtime (CLR) namespace of that type.
By default, any given CLR namespace (in the format Clr.Namespace) is mapped to the namespace
http://schemas.datacontract.org/2004/07/Clr.Namespace.The default namespace logic of
DataContractSerializerdiffers fromXmlSerializer. Objects are not assigned to a namespace by default byXmlSerializer, so your original model works as-is with that serializer. Demo fiddle #2 here.If you would prefer to use
XmlSerializerinstead ofDataContractSerializerI believe you could removeAddXmlDataContractSerializerFormatters()leaving onlyAddXmlSerializerFormatters().An easy way to debug problems with deserialization is to serialize your model and compare the actual results with content you are trying to deserialize. If I attempt to serialize an instance of your current
Object1model, I get:<?xml version="1.0" encoding="utf-16"?> <Object1 xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <field1>Hello</field1> <field2 xmlns:d2p1="http://schemas.datacontract.org/2004/07/" z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"> <d2p1:field3>World</d2p1:field3> <d2p1:field4 z:Id="i2"> <d2p1:field5>Test</d2p1:field5> <d2p1:field6>Test2</d2p1:field6> </d2p1:field4> </field2> </Object1>From which it can be seen that the namespace
d2p1:for the elements ofObject2andObject3is wrong. (The precise namespace chosen, herehttp://schemas.datacontract.org/2004/07/, will depend on the CLR namespace of your model, which is not shown in your question.)Demo fiddle #3 here.
Your XML elements do not have
z:Id="xxx"orz:ref="xxx"attributes, so I don't see any need to enable theIsReferencereference tracking mechanism.
