Reputation: 928
We're redoing a legacy application using .Net MVC 5. Part of the application generates an XML feed which other applications use.
We've built a model called Call
[XmlRoot("record")]
public class Call
{
[XmlIgnore]
public int ID { get; set; }
[XmlIgnore]
public string CustomerInitials { get; set; }
[XmlIgnore]
public string Prefix { get; set; }
[XmlIgnore]
public string Code { get; set; }
[XmlIgnore]
public string CustomerNumber { get; set; }
[XmlElement("starttime")]
public DateTime Entry { get; set; }
[XmlElement("endtime")]
public DateTime Exit { get; set; }
[XmlElement("cnumber")][NotMapped]
public string Number
{
get { return Prefix + Code + CustomerNumber; }
}
}
With a controller:
public class CallsController : ApiController
{
private DbContext db = new DbContext();
// GET: api/Calls
public IQueryable<Call> GetCalls()
{
return db.Calls;
}
}
Which produces an XML feed of:
<ArrayOfCall xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Call>
<starttime>2016-01-15T14:45:24.447</starttime>
<endtime>2016-01-15T15:45:24.447</endtime>
</Call>
<Call>
<starttime>2016-01-15T15:46:35.637</starttime>
<endtime>2016-01-15T16:46:35.637</endtime>
</Call>
</ArrayOfCall>
However, I need to customize the XML feed to provide the following output:
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<RECORD>
<CNUMBER>593042401</CNUMBER>
<STARTTIME>2016-01-15T14:45:24.447</STARTTIME>
<ENDTIME>2016-01-15T15:45:24.447</ENDTIME>
</RECORD>
<RECORD>
<CNUMBER>593042401</CNUMBER>
<STARTTIME>2016-01-15T15:46:35.637</STARTTIME>
<ENDTIME>2016-01-15T16:46:35.637</ENDTIME>
</RECORD>
</DATA>
The XmlRoot data annotation is not followed and the CNumber is not included in my XML feed. The calls should display as <record>
in the XML feed with the root being <data>
. How do I resolve these issues? Am I going about this the wrong way? Should I be using a View Model instead?
Upvotes: 1
Views: 251
Reputation: 317
1.- The Data class:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace StackOverflow
{
public class Call
{
[XmlIgnore]
public int ID { get; set; }
[XmlIgnore]
public string CustomerInitials { get; set; }
[XmlIgnore]
public string Prefix { get; set; }
[XmlIgnore]
public string Code { get; set; }
[XmlIgnore]
public string CustomerNumber { get; set; }
[XmlElement("CNUMBER")]
public string Number
{
get { return Prefix + Code + CustomerNumber; }
}
[XmlElement("STARTTIME")]
public DateTime Entry { get; set; }
[XmlElement("ENDTIME")]
public DateTime Exit { get; set; }
}
[XmlRoot(ElementName = "DATA")]
public class Data
{
[XmlElement("RECORD")]
public List<Call> Calls;
}
}
2.- Using your example data:
// 1.- Data
var data = new Data();
var calls = new List<Call>
{
new Call
{
Entry = new DateTime(2016, 1, 15, 14, 45, 24, 447),
Exit = new DateTime(2016, 1, 15, 15, 45, 24, 447)
},
new Call
{
Entry = new DateTime(2016, 1, 15, 15, 46, 35, 637),
Exit = new DateTime(2016, 1, 15, 16, 46, 35, 637)
}
};
data.Calls = new List<Call>(calls);
// 2.- Serialize the objet to byte[]
var dataByteArray = new XmlSerializerHelper<Data>().ObjectToByteArray(data, Encoding.GetEncoding("UTF-8"), true);
// 3.- Save the byte[] to disk
File.WriteAllBytes("D:/xml.xml", dataByteArray);
3.- The serializer helper:
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace StackOverflow
{
public class XmlSerializerHelper<T> where T : class
{
private readonly XmlSerializer _serializer;
public XmlSerializerHelper()
{
_serializer = new XmlSerializer(typeof(T));
}
public byte[] ObjectToByteArray(T obj, Encoding encoding = null, bool ignoreNAmespaces = false)
{
var settings = GetSettings(encoding);
using (var memoryStream = new MemoryStream())
{
using (var writer = XmlWriter.Create(memoryStream, settings))
{
if (ignoreNAmespaces)
{
var serializerNamespaces = new XmlSerializerNamespaces();
serializerNamespaces.Add("", "");
_serializer.Serialize(writer, obj, serializerNamespaces);
}
else
{
_serializer.Serialize(writer, obj);
}
}
return memoryStream.ToArray();
}
}
private XmlWriterSettings GetSettings(Encoding encoding)
{
return new XmlWriterSettings
{
Encoding = encoding ?? Encoding.GetEncoding("ISO-8859-1"),
Indent = true,
IndentChars = "\t",
NewLineChars = Environment.NewLine,
ConformanceLevel = ConformanceLevel.Document
};
}
}
}
4.- Output:
<?xml version="1.0" encoding="utf-8"?>
<DATA>
<RECORD>
<STARTTIME>2016-01-15T14:45:24.447</STARTTIME>
<ENDTIME>2016-01-15T15:45:24.447</ENDTIME>
</RECORD>
<RECORD>
<STARTTIME>2016-01-15T15:46:35.637</STARTTIME>
<ENDTIME>2016-01-15T16:46:35.637</ENDTIME>
</RECORD>
</DATA>
Cheers
Upvotes: 2
Reputation: 512
To create XML that would match the what you are wanting you could create an Object named Data which could provide a list that would hold Records.
public class Data{
public List<Record> Records{get;set;}
}
Currently you are returning an array of Calls.
Upvotes: 0