Home > other >  Issues Deserializing complex XML into objects C# .NET Core 6 MVC Web App with API controller
Issues Deserializing complex XML into objects C# .NET Core 6 MVC Web App with API controller

Time:07-05

This will be a long question as there is a lot of code to show to determine what the root cause of the problem is and for others to be able to run the code to help solve the issue.

The issue that I am having is that when I deserialize the XML (using XmlReader and XmlSerializer), all the objects are there and the hierarchy is correct, but all the values are null or default (for numerical types).

The users of the application download Rubrics they have created from Blackboard (Learning Management System), which exports them as standard binary stream files (.dat), and then they upload that file to my MVC Web Application.

Here is an example of the XML contained within one of these files, and the example that I have been using to debug the problem:

<?xml version="1.0" encoding="UTF-8"?>
<LEARNRUBRICS>
  <Rubric id="_24301_1">
    <Title value="Lesson 10 Assignment"/>
    <Description value="Students are solving the kth smallest algorithm problem and implementing a Java solution to it."/>
    <ContactName value=""/>
    <Version value="1"/>
    <CreatorId value="_73949_1"/>
    <Type value="NUMERIC"/>
    <Status value="ACTIVE"/>
    <Public value="false"/>
    <DeletedIndicator value="false"/>
    <MaxValue value="100.00000"/>
    <Keywords value=""/>
    <DATES>
        <CREATED value="2022-06-25 09:04:39 EDT"/>
        <UPDATED value="2022-06-25 09:04:39 EDT"/>
    </DATES>
    <RubricRows>
        <Row id="_104569_1">
            <Header value="grid.row1.label"/>
            <Position value="0"/>
            <Percentage value="15.000000000000000"/>
            <RubricColumns>
                <Column>
                    <Header value="grid.column1.label"/>
                    <Position value="0"/>
                    <Cell id="_382286_1">
                        <CellDescription value="Did novice work for formatting"/>
                        <NumericPoints value="2.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="13.333330000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column2.label"/>
                    <Position value="1"/>
                    <Cell id="_382287_1">
                        <CellDescription value="Did competent work for formatting"/>
                        <NumericPoints value="4.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="26.666660000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column3.label"/>
                    <Position value="2"/>
                    <Cell id="_382288_1">
                        <CellDescription value="Proficient work for formatting"/>
                        <NumericPoints value="8.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="53.333330000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="Expert"/>
                    <Position value="3"/>
                    <Cell id="_382289_1">
                        <CellDescription value="Expert work for formatting"/>
                        <NumericPoints value="15.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="100.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
            </RubricColumns>
        </Row>
        <Row id="_104570_1">
            <Header value="grid.row2.label"/>
            <Position value="1"/>
            <Percentage value="20.000000000000000"/>
            <RubricColumns>
                <Column>
                    <Header value="grid.column1.label"/>
                    <Position value="0"/>
                    <Cell id="_382290_1">
                        <CellDescription value="Did novice work for organization"/>
                        <NumericPoints value="5.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="25.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column2.label"/>
                    <Position value="1"/>
                    <Cell id="_382291_1">
                        <CellDescription value="Did competent work for organization"/>
                        <NumericPoints value="10.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="50.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column3.label"/>
                    <Position value="2"/>
                    <Cell id="_382292_1">
                        <CellDescription value="Proficient work for organization"/>
                        <NumericPoints value="15.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="75.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="Expert"/>
                    <Position value="3"/>
                    <Cell id="_382293_1">
                        <CellDescription value="Expert work for organization"/>
                        <NumericPoints value="20.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="100.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
            </RubricColumns>
        </Row>
        <Row id="_104571_1">
            <Header value="grid.row3.label"/>
            <Position value="2"/>
            <Percentage value="20.000000000000000"/>
            <RubricColumns>
                <Column>
                    <Header value="grid.column1.label"/>
                    <Position value="0"/>
                    <Cell id="_382294_1">
                        <CellDescription value="Did novice work for Grammar"/>
                        <NumericPoints value="7.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="35.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column2.label"/>
                    <Position value="1"/>
                    <Cell id="_382295_1">
                        <CellDescription value="Did competent work for Grammar"/>
                        <NumericPoints value="12.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="60.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column3.label"/>
                    <Position value="2"/>
                    <Cell id="_382296_1">
                        <CellDescription value="Proficient work for Grammar"/>
                        <NumericPoints value="16.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="80.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="Expert"/>
                    <Position value="3"/>
                    <Cell id="_382297_1">
                        <CellDescription value="Expert work for Grammar"/>
                        <NumericPoints value="20.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="100.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
            </RubricColumns>
        </Row>
        <Row id="_104572_1">
            <Header value="Syntax"/>
            <Position value="3"/>
            <Percentage value="35.000000000000000"/>
            <RubricColumns>
                <Column>
                    <Header value="grid.column1.label"/>
                    <Position value="0"/>
                    <Cell id="_382298_1">
                        <CellDescription value="Did novice work for Syntax"/>
                        <NumericPoints value="5.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="14.285710000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column2.label"/>
                    <Position value="1"/>
                    <Cell id="_382299_1">
                        <CellDescription value="Did competent work for Syntax"/>
                        <NumericPoints value="15.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="42.857140000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column3.label"/>
                    <Position value="2"/>
                    <Cell id="_382300_1">
                        <CellDescription value="Proficient work for Syntax"/>
                        <NumericPoints value="25.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="71.428570000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="Expert"/>
                    <Position value="3"/>
                    <Cell id="_382301_1">
                        <CellDescription value="Expert work for Syntax"/>
                        <NumericPoints value="35.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="100.000000000000000"/>
                        <PercentageMax  value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
            </RubricColumns>
        </Row>
        <Row id="_104573_1">
            <Header value="Detail"/>
            <Position value="4"/>
            <Percentage value="10.000000000000000"/>
            <RubricColumns>
                <Column>
                    <Header value="grid.column1.label"/>
                    <Position value="0"/>
                    <Cell id="_382302_1">
                        <CellDescription value="Did novice work for Detail"/>
                        <NumericPoints value="2.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="20.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column2.label"/>
                    <Position value="1"/>
                    <Cell id="_382303_1">
                        <CellDescription value="Did competent work for Detail"/>
                        <NumericPoints value="4.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="40.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="grid.column3.label"/>
                    <Position value="2"/>
                    <Cell id="_382304_1">
                        <CellDescription value="Proficient work for Detail"/>
                        <NumericPoints value="8.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="80.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
                <Column>
                    <Header value="Expert"/>
                    <Position value="3"/>
                    <Cell id="_382305_1">
                        <CellDescription value="Expert work for Detail"/>
                        <NumericPoints value="10.000000000000000"/>
                        <NumericStartPointRange value="0.000000000000000"/>
                        <NumericEndPointRange value="0.000000000000000"/>
                        <Percentage value="100.000000000000000"/>
                        <PercentageMax value="0.000000000000000"/>
                        <Percentagemin value="0.000000000000000"/>
                    </Cell>
                </Column>
            </RubricColumns>
        </Row>
    </RubricRows>
   </Rubric>
 </LEARNRUBRICS>

Since I am using XmlReader and XmlSerializer to deserialize this XML into objects, I have created models for those objects specifically for the deserialization, so that I can then create the corresponding database entity models and save them to the database. Here are the deserialization models I have created, starting from the XmlRootElement LEARNRUBRICS object:

LEARNRUBRICS Class

using System.Xml.Serialization;

namespace RiverhawkRubric.Models.DeserializationModels;

[Serializable, XmlRoot("LEARNRUBRICS")]
public class LEARNRUBRICS
{
    [XmlElement]
    public Rubric Rubric { get; set; }

    public LEARNRUBRICS() { }
}

Rubric Class

using System.Xml.Serialization;

namespace RiverhawkRubric.Models.DeserializationModels;

[Serializable]
[XmlType]
public class Rubric
{
    [XmlAttribute]
    public string Title { get; set; }

    [XmlAttribute]
    public string Description { get; set; }

    [XmlIgnore]
    public string ContactName { get; set; }

    [XmlIgnore]
    public int Version { get; set; }

    [XmlIgnore]
    public string CreatorId { get; set; }

    [XmlAttribute]
    public string Type { get; set; }

    [XmlIgnore]
    public string Status { get; set; }

    [XmlIgnore]
    public string Public { get; set; }

    [XmlIgnore]
    public bool DeletedIndicator { get; set; }

    [XmlAttribute]
    public double MaxValue { get; set; }

    [XmlIgnore]
    public string Keywords { get; set; }

    [XmlIgnore]
    public List<DateTime> DATES { get; set; }

    [XmlElement]
    public RubricRows RubricRows { get; set; }

    public Rubric() { }
}

RubricRows Class

using System.Xml.Serialization;

namespace RiverhawkRubric.Models.DeserializationModels;

[Serializable]
[XmlType]
public class RubricRows
{
    [XmlElement]
    public Row[] Row { get; set; }
}

Row Class

using System.Xml.Serialization;

namespace RiverhawkRubric.Models.DeserializationModels;

[Serializable]
[XmlType]
public class Row
{
    [XmlAttribute]
    public string Header{ get; set; }

    [XmlAttribute]
    public int Position { get; set; }

    [XmlAttribute]
    public double Percentage { get; set; }

    [XmlElement]
    public RubricColumns RubricColumns { get; set; }

    public Row() { } 
}

RubricColumns Class

using System.Xml.Serialization;

namespace RiverhawkRubric.Models.DeserializationModels;

[Serializable]
[XmlType]
public class RubricColumns
{
    [XmlElement]
    public Column[] Column { get; set; }

    public RubricColumns() { }
}

Cloumn Class

using System.Xml.Serialization;

namespace RiverhawkRubric.Models.DeserializationModels;

[Serializable]
[XmlType]
public class Column
{
    [XmlAttribute]
    public string Header { get; set; }

    [XmlAttribute]
    public int Position { get; set; }

    [XmlElement]
    public Cell Cell { get; set; }

    public Column() { }
}

Cell Class

using System.Xml.Serialization;

namespace RiverhawkRubric.Models.DeserializationModels;

[Serializable]
[XmlType]
public class Cell
{
    [XmlAttribute]
    public string CellDescription { get; set; }

    [XmlAttribute]
    public double NumericPoints { get; set; }

    [XmlAttribute]
    public double NumericStartPointRange { get; set; }

    [XmlAttribute]
    public double NumericEndPointRange { get; set; }

    [XmlAttribute]
    public double Percentage { get; set; }

    [XmlAttribute]
    public double PercentageMax { get; set; }

    [XmlAttribute]
    public double Percentagemin { get; set; }

    public Cell() { }
}

The user uses a standard form to upload the file to the API controller.

@{
ViewData["Title"] = "Upload Rubric";
}

<div >
  <h1 >Upload Rubric</h1>
</div>
<div >
  <div >
    <form method="post" enctype="multipart/form-data" asp-controller="UploadRubric" asp-action="Upload">
        <div >
            <label >Upload Rubric</label>
            <input type="file" name="rubric" />
        </div>    
        <div >
            <button type="submit" >Upload</button>
        </div>
    </form>
</div>

I pass the file to the API controller as an IFormFile and begin processing it. I check to ensure it is one of two file types (.dat and .xml) and that it is not an empty file and if it meets both criteria I pass it on to be deserialized.

[HttpPost]
[Route("upload")]
[ProducesResponseType(200)]
[ProducesResponseType(406)]
[ProducesResponseType(422)]
[ProducesResponseType(500)]
public async Task<IActionResult> Upload([FromForm]IFormFile rubric)
{
    //check file is valid file type and not empty file
    if (!IsValidFileFormat(rubric))
    {
        //if file is not .dat or .xml return 422 Unprocessable Entity
        return UnprocessableEntity();
    }
    else if(rubric.Length <= 0)
    {
        //if empty file return 411 Length Required
        return StatusCode(StatusCodes.Status411LengthRequired);
    }
    bool successful = false;

    // deserialize XmlDocument object to db objects and save to db
    successful = DeserializeXml(rubric);
    if (successful)
    {
        // if deserialization was successful return 200 with XML content
        return Ok(/*rubricXml.OuterXml*/);
    }
    else
    {
        // if deserialization was not successful return 500 Internal Server Error
        return StatusCode(StatusCodes.Status500InternalServerError) ;
    }
  
}

Then in the DeserializeXml(IFormFile rubric) method, I create an instance of my root element and then use a MemoryStream to copy the file to, using XmlReader and I deserialize it using XmlSerializer:

private bool DeserializeXml(IFormFile rubric)
{
    try
    {
        LEARNRUBRICS rubricXML = null;
        
        using (MemoryStream stream = new())
        {
            rubric.CopyTo(stream);
            stream.Position = 0;
            XmlReader xmlReader = XmlReader.Create(stream);
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(LEARNRUBRICS));
            rubricXML = (LEARNRUBRICS)xmlSerializer.Deserialize(xmlReader);
            stream.Close();
        }

        //I stopped my logic here, so that I can run the app in debug mode
        //Pass it the file and then see what the rubricXML local variable's
        //state is before the return true statement.
        return true;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex.Message, ex.InnerException);
        throw new Exception(ex.Message, ex.InnerException);
    }          
}

I have a breakpoint set at the return true; statement at the end of the DeserializeXml(IFormFile) method and when I run the application in debug mode and upload the file, the LEARNRUBRICS deserialized object has all of the child objects populated, the correct number of rows and columns and cells, but all the values are either null or the default.

I know that the XML is complex, as are the deserialized models, but if anyone has any insight as to why this might be happening, please let me know.

CodePudding user response:

You need add a middle class :

public class MiddleClass
{
    [XmlAttribute]
    public string value { get; set; }
}

Then change your model (change all the properties declared with [XmlAttribute]):

[Serializable, XmlRoot("LEARNRUBRICS")]
public class LEARNRUBRICS
{
    [XmlElement]
    public Rubric Rubric { get; set; }
    public LEARNRUBRICS() { }
}
[Serializable]
[XmlType]
public class Rubric
{
    public MiddleClass Title { get; set; }
    public MiddleClass Description { get; set; }
    [XmlIgnore]
    public string ContactName { get; set; }
    [XmlIgnore]
    public int Version { get; set; }
    [XmlIgnore]
    public string CreatorId { get; set; }

    public MiddleClass Type { get; set; }

    [XmlIgnore]
    public string Status { get; set; }
    [XmlIgnore]
    public string Public { get; set; }
    [XmlIgnore]
    public bool DeletedIndicator { get; set; }

    public MiddleClass MaxValue { get; set; }

    [XmlIgnore]
    public string Keywords { get; set; }
    [XmlIgnore]
    public List<DateTime> DATES { get; set; }
    [XmlElement]
    public RubricRows RubricRows { get; set; }

    public Rubric() { }
}
[Serializable]
[XmlType]
public class RubricRows
{
    [XmlElement]
    public Row[] Row { get; set; }
}
[Serializable]
[XmlType]
public class Row
{
    public MiddleClass Header { get; set; }
    public MiddleClass Position { get; set; }
    public MiddleClass Percentage { get; set; }

    [XmlElement]
    public RubricColumns RubricColumns { get; set; }
    public Row() { }
}
[Serializable]
[XmlType]
public class RubricColumns
{
    [XmlElement]
    public Column[] Column { get; set; }
    public RubricColumns() { }
}
[Serializable]
[XmlType]
public class Column
{
    public MiddleClass Header { get; set; }
    public MiddleClass Position { get; set; }

    [XmlElement]
    public Cell Cell { get; set; }
    public Column() { }
}
[Serializable]
[XmlType]
public class Cell
{
    public MiddleClass CellDescription { get; set; }
    public MiddleClass NumericPoints { get; set; }
    public MiddleClass NumericStartPointRange { get; set; }
    public MiddleClass NumericEndPointRange { get; set; }
    public MiddleClass Percentage { get; set; }
    public MiddleClass PercentageMax { get; set; }
    public MiddleClass Percentagemin { get; set; }
    public Cell() { }
}
  • Related