I am experimenting with using xml as a database for small CMS, like gallery or staff profiles
etc
however being all subsonic minded i am stuck on how i bind my xml document to a modelclass
so that i can then use that class for strongly typed views:
here is my model class:
[XmlRoot("employee")]
public class EmployeesModel
{
[Required]
[DisplayName("Name: ")]
[XmlElement("employeeName")]
public string employeeName { get; set; }
[Required]
[DisplayName("Position: ")]
[XmlElement("employeePosition")]
public string employeePosition { get; set; }
[Required]
[DisplayName("Description")]
[XmlElement("employeeDescription")]
public string employeeDescription { get; set; }
[Required]
[DisplayName("Photo: ")]
[XmlElement("employeePhoto")]
public string employeePhoto { get; set; }
[Required]
[DisplayName("ID: ")]
[XmlElement("employeeID")]
public int employeeID { get; set; }
}
and here is my code:
XDocument xmlDoc = XDocument.Load(Server.MapPath("~/App_Data/employees.xml"));
var model = (from xml in xmlDoc.Descendants("employee")
select xml) as IEnumerable<EmployeesModel>;
return View(model);
the XML
<?xml version="1.0" encoding="utf-8" ?>
<employees>
<employee>
<employeeName>David parker</employeeName>
<employeePosition>Senior Web Developer</employeePosition>
<employeeDescription>This is a test description<br>feele free to add something here.</employeeDescription>
<employeePhoto>mypic.jpg</employeePhoto>
<employeeID>1</employeeID></employee></employees>
the xml side work but model is always empty, however i get no runtime erros when trying to bind, i know there is more i should do here but i need some help.
for clarity i am using asp.net mvc 2 rc 2
thanks
You need to deserialize the XML into objects. You cannot simply cast XML as objects. When you say as IEnumerable<EmployeesModel>, you'll get a null since the types aren't compatible. Your code could look something like this:
var serializer = new XmlSerializer(typeof(EmployeesModel));
var model =
from xml in xmlDoc.Descendants("employee")
select serializer.Deserialize(xml.CreateReader()) as EmployeesModel;
Another option you could consider is to project the XElements into EmployeesModel objects, like this:
var model =
from xml in xmlDoc.Descendants("employee")
select new EmployeesModel {
employeeName = (string)xml.Element("employeeName"),
employeePosition = (string)xml.Element("employeePosition"),
employeeDescription = (string)xml.Element("employeeDescription"),
employeePhoto = (string)xml.Element("employeePhoto"),
employeeID = (int)xml.Element("employeeID"), };
As you can see, that can get tedious. However, it may be appropriate. If your XML file represents all employee data but your view shows only a subset of the data or the data in a different structure, you probably don't want your view model to be a direct copy of the contents of your data store.
If you want make binding xml to model class, you can use templay on codeplex.
Further you can do some process on your model class and their childrens.
https://templay.codeplex.com/
Related
Let me preface by saying I'm very new to C# development so if the solution seems obvious I apologize.
I'm getting a JSON string back from a user and I need to filter a list of C# objects based on what the JSON string contains. The JSON can only have fields that my C# model has but I don't know what fields the JSON string will contain. My C# model looks something like this:
public class Enrollment {
public int Year { get; set; }
public int NumEnrolls { get; set; }
public int DaysIntoEnrollment { get; set; }
public string Name { get; set; }
}
The JSON will have one or more of these properties with values to filter out. It could look like this:
{
"Year": ["2020", "2019"],
"Name": ["CourseA", "CourseB"],
"DaysIntoEnrollment": "20"
}
I need to filter my list of Enrollment objects based on the above JSON. So I would want the end result to have all Enrollment objects that don't contain a Year of 2020 or 2019 for example.
I've gotten a filter to work with linq on a single property but my real model has much more properties that can be filtered and I'm looking for a compact solution that will work regardless of which properties are included in the JSON. This is what I have working
public void GetFilteredData(string filters) {
var enrollList = new List<Enrollments>(); // Pretend this contains a list of valid Enrollment data
var json = JObject.Parse(filters); // filters string is in the json format from above
var propsToFilter =
from p in json["Year"]
select p;
var filtered = enrollList.Where(e => !propsToFilter.Contains(e.Year.ToString())));
}
Is there a simple way to do this without manually going through each property like I did above?
I want to save a list of dates in an xml, I want to use dataset to achieve the task, I do the same to a database using Entity Framework. This allows me to access the dates using event.eventDates.start
but in the dataset I cannot achieve it.
public class Event
{
[Key]
public string id { get; set; }
public virtual ICollection<Date> eventDates { get; set; }
}
Date class
public class Date
{
public DateTime start { get; set; }
public DateTime end { get; set; }
}
When using entity framework I can access the eventDates Object using event.eventDates.start
I mapped the data from the sql database in the dataset builder the relations look like this
I want the xml file to be in this format
<?xml version="1.0" standalone="yes"?>
<db xmlns="http://tempuri.org/LocalDB.xsd">
<Event>
<id>ID</id>
<eventdates>
<date>
<startdate></startdate>
<enddate></enddate>
<date>
<date>
<startdate></startdate>
<enddate></enddate>
<date>
</eventdates>
</Event>
</db>
Is there any way to achieve that using datasets?
I'm new to C# any help would be appreciated
This code works, based on generate xml files based on my c# classes. I would rename your classes to something else than "Event" and "Date". These names are too generic and are usually protected by the system. ICollection is not serializable. Read XML serialization of interface property. You can use DTO or you can change the collection type (i.e. with List<>) and with XML serialization attributes avoid circular references and/or disable lazy load (i.e. use eagerly load using Include method) or the risk is that you serialize the whole database.
Program.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace EFToXml
{
public class MyEvent
{
public string Id { get; set; }
public virtual List<MyDate> EventDates { get; set; }
}
public class MyDate
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var myDate1 = new MyDate
{
Start = DateTime.Now,
End = DateTime.Now.AddDays(1)
};
var eventDates = new List<MyDate> { myDate1 };
var myEvent = new MyEvent
{
Id = "1",
EventDates = eventDates
};
XmlSerializer serializer = new XmlSerializer(typeof(MyEvent));
serializer.Serialize(File.Create(#"C:\Users\<UserName>\Source\Repos\myEvents.xml"), myEvent);
}
}
}
myEvents.xml:
<?xml version="1.0"?>
<MyEvent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Id>1</Id>
<EventDates>
<MyDate>
<Start>2019-11-24T21:52:04.5032671+01:00</Start>
<End>2019-11-25T21:52:04.5194026+01:00</End>
</MyDate>
</EventDates>
</MyEvent>
If i understand correctly, you just want to reproduce EntityFramework's behavior using DataSets.
You can achieve exactly same thing simply creating DataSet (using integrated VisualStudio designer) with proper tables, fields and relations:
later on you can access your data using code like this:
var ds = new DataSet1();
var ue = ds.UserEvents.FirstOrDefault();
var ued = ue.GetChildRows("FK_UserEvents_EventDates")
.Cast<DataSet1.EventDatesRow>();
var date = ued.FirstOrDefault().Date;
Next thing to do is serialization - it's quite easy:
Serialization example
I have a DTO and a Domain project in my solution and an MVC front end with web api to expose data.
I have the web api controller set up and the action is getting my DTO object back from the DataService. That's all great, however, I want xml to be returned and I want some of the values to be in xml attributes e.g.
<root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<lookups>
<lookup category="General" field="Alert Type" value="Lack of Transparency" entityid="2273"/>
<lookup category="General" field="Alert Type" value="Unfair Terms " entityid="2274"/>
<lookup category="General" field="Alert Type" value="Operator Concerns" entityid="2275"/>
...
</lookups>
<paymentmethods />
<affiliates />
</root>
The Lookup class is as follows:
[Serializable]
[XmlSerializerFormat]
public class Lookup
{
[XmlAttribute("category")]
public String Category { get; set; }
[XmlAttribute("field")]
public String Field { get; set; }
[XmlAttribute("value")]
public String Value { get; set; }
[XmlAttribute("entityid")]
public String EntityId { get; set; }
public Lookup(String Category, String Field, String Value, int? EntityId = null)
{
this.Category = Category;
this.Field = Field;
this.Value = Value;
this.EntityId = (EntityId != null ? EntityId.ToString() : null);
}
public Lookup() { }
}
initially I had my DTO objects (e.g Lookup, PaymentMethod and Affiliates) with my viewmodels, but moved them into my DTO project.
I have set UseXmlSerializer = true in my global.asax
Before moving the objects from hy viewmodels folder to the DTO project, it was working and I was getting the desired XML. AFTER moving, it appears to be ignoring the XmlSerializerFormat and using DataContractSerliazer.
So using DataMember attributes, I can format the xml, but obviously I can't set some properties to be serialised as xml attributes
Any thoughts on why it seems to be ignoring the [XmlSerializerFormat] and [XmlAttribute("field")] attributes?
I've read a few SO posts like:
XmlSerializer ignores [XmlAttribute] in WebApi and
How can you control .NET DataContract serialization so it uses XML attributes instead of elements?
I found the solution to this here:
http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#xml_pertype
Setting the xml Serializer in the Global.asax to work on a specific type worked for me :
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
xml.SetSerializer<FullResponseRoot>(new XmlSerializer(typeof(FullResponseRoot)));
where FullResponseRoot is the name of the object that I am serialising (the classes mentioned above are properties of FullResponseRoot)
FullResponseRoot forms the root node of the generated xml
My web api is returning a set of objects which are differ from the Domain object. Forexample, I my domain has an Employee class but I don't want to expose all the members of the Employee class in my api so I created another class called EmployeeApiModel.
Now my WebApi is returning a List of EmployeeApiModel but I want to be able to specify the name to which it should serialize to. That is instead of <EmployeeApiModel> tag in the xml, I want to get <Employee> but without changing the fact that the underlying class which is being serialized is EmployeeApiModel.
How can I achieve this?
Technically, Web Api support both json and xml based on content negotiation mechanism, Json is the default format, if you want to receive xml, just put on header:
Accept: application/xml
To understand more content negotiation, access this
Since you want your api support both json and xml, you should use DataContract and DataMember Attribute for serialization for your model: EmployeeApiModel, something like:
[DataContract(Name = "Employee")]
public class EmployeeApiModel
{
[DataMember(Name = "Name2")]
public string Name { get; set; }
[DataMember]
public string Email { get; set; }
}
See more on this blog-post
You can control the output of your serialized XML by using various Attribute tags.
[XmlRoot("Employee")]
Public class EmployeeApiModel
{
[XmlElement("fname")]
public string FirstName { get; set; }
public string LastName { get; set; }
public int age { get; set; }
}
this will produce XML like:
<Employee>
<fname>John</fname>
<LastName >Smith</LastName >
<age>24</age>
</RootElementsName>
You can read more about the various XML modifiers here: http://msdn.microsoft.com/en-us/library/e123c76w.
If you want to use existing XML modifiers for JSON, check out this post: Serialize .Net object to json, controlled using xml attributes
I'm in charge to migrate our own DAL to a solution based on Entity Framework 4 but, before I can do it, I need to be sure it's possible to translate all our "constructs" to this new technology.
One of the biggest issues I'm having is the possibility to read a field and build a custom type. Valid examples could be a bit mask saved in a BIGINT field, a list of mail addresses saved as a CSV list in a NVARCHAR field or an XML field containing aggregated data not worth to have their own table/entity. Basically the serialization mechanism is not fixed.
Let's take the classic "Address" example.
public class Address
{
public string Street {get; set;}
public string City {get; set;}
public string Zip {get; set;}
public string Country {get; set;}
}
and let's suppose we want to save it in an XML field using this template:
<address>
<street>Abrahamsbergsvägen, 73</street>
<city>Stockholm</city>
<zip>16830</zip>
<country>Sweden</country>
</address>
The question basically is: does exist a method to override how EF4 serializes and deserializes the content of a field mapped to a property of an entity?
I found this solution. It's not as clean as I wished but it seems it's impossible to get anything better.
given this base entity,
public class Institute
{
public int InstituteID { get; set; }
public string Name { get; set; }
// other properties omitted
}
I added in the database an XML field called Data containing some strings using this simple template
<values>
<value>Value 1</value>
<value>Value 2</value>
<value>Value 3</value>
</values>
In the entity I added these properties and I mapped the database field "Data" to the property "DataRaw".
protected string DataRaw
{
get
{
if (_Data == null)
return _DataRaw;
else
return new XElement("values", from s in Data select new XElement("value", s)).ToString();
}
set
{
_DataRaw = value;
}
}
private string _DataRaw;
private string[] _Data;
public string[] Data
{
get
{
if (_Data == null)
{
_Data = (from elem in XDocument.Parse(_DataRaw).Root.Elements("value")
select elem.Value).ToArray();
}
return _Data;
}
set
{
_Data = value;
}
}
This solution works. Here is the sample code:
class Program
{
static void Main(string[] args)
{
var ctx = new ObjectContext("name=TestEntities");
var institute = ctx.CreateObjectSet<Institute>().First();
System.Console.WriteLine("{0}, {1}", institute.InstituteID, institute.Name);
foreach (string data in institute.Data)
System.Console.WriteLine("\t{0}", data);
institute.Data = new string[] {
"New value 1",
"New value 2",
"New value 3"
};
ctx.SaveChanges();
}
}
Does anyone have a better solution?
Entity Framework does NOT serializes or deserializes entities nor it controls how the serialization should take place in other layers or modules of your application.
What you need to do is to simply open your POCO(s) and annotate their Properties with appropriate attributes that will be taken into account at the time of serialization when you want to ship them to your other application layers.