I have the following code in a controller.
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime Birthday { get; set; }
}
public ActionResult JsonObject()
{
Person[] persons = new Person[]{
new Person{Name="John", Age=26, Birthday=new DateTime(1986,1,1)},
new Person{Name="Tom", Age=10, Birthday=new DateTime(2002, 1, 9)}
};
return Json(persons, JsonRequestBehavior.AllowGet);
}
Normally, I got the result like this:
[{"Name":"John","Age":26,"Birthday":"/Date(504892800000)/"},{"Name":"Tom","Age":10,"Birthday":"/Date(1010505600000)/"}]
That's okay, however, I want to make an option for the user: not to display birthday. So, the expecting result would be like this:
[{"Name":"John","Age":26},{"Name":"Tom","Age":10}]
How can I not to serialize the Birthday property to JSON?
You have two options:
1) Add a [ScriptIgnore] attribute to the Person class:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
[ScriptIgnore]
public DateTime Birthday { get; set; }
}
2) Return an anonymous type that contains only the properties you want:
var toReturn = persons.Select(x => new {x.Name, x.Age});
return Json(toReturn, JsonRequestBehavior.AllowGet);
EDIT: I wasn't aware that the desired columns had to be dynamically chosen. You can use the following because objects and dictionaries are the same thing in Javascript.
First, create an extension that creates a dictionary of your desired properties:
public static class JSONExtensions
{
public static IDictionary<string, object> ToJsonObject(this object instance, string[] includedProperties)
{
var jsonObject = new Dictionary<string, object>();
foreach (var property in instance.GetType().GetProperties())
{
if (includedProperties.Any(x=> x.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase)))
{
jsonObject[property.Name] = property.GetValue(instance);
}
}
return jsonObject;
}
}
Next, use this extension method before serializing:
var toReturn = persons.Select(x => x.ToJsonObject(desiredColumnss));
return Json(toReturn, JsonRequestBehavior.AllowGet);
just define a new class as DTO, which contains only required fields.
public class PersonDTO
{
public string Name { get; set; }
public int Age { get; set; }
}
After that, you can PersonDTO
Related
I have an array of a class MyClassDTO that needs to be used to update items in the MyClass array:
public class MyClass
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
}
public class MyClassDTO
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
}
I was thinking using a dictionary to store the values from the DB and, then, iterate over the updated values and either update an existing value or create a new one. Something like this:
public void UpdateMyClassArray(IEnumerable<MyClassDTO> myClassDTOArray)
{
var currentValuesInDB = GetArray();
var myDictionary = new Dictionary<int, MyClass>();
foreach (var myClass in currentValuesInDB)
myDictionary.Add(myClass.Id, myClass);
var updatedMyClasses = myClassDTOArray
.Select(myClassDTO =>
{
if (myClassDTO.Id is null)
return Mapper.Map<MyClass>(myClassDTO);
int id = myClassDTO.Id.Value;
if (!myDictionary.ContainsKey(id))
return Mapper.Map<MyClass>(myClassDTO);
var storedMyClass = myDictionary[id];
return Mapper.Map(myClassDTO, storedMyClass);
});
SaveChanges(updatedMyClasses);
}
My question is: is there a better way of doing this? Does AutoMapper provide a built-in method for dealing with this case?
I have these:
public class FamilyHead
{
public Guid HeadId { get; set; }
public string Name { get; set; }
}
public class Citizen
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
// more properties
[ForeignKey("FamilyHead")]
public Guid HeadId { get; set; }
public virtual FamilyHead FamilyHead { get; set; }
}
public class CitizenDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
public Guid HeadId
public string HeadName { get; set; }
}
I can manually map it via extension method if it is a single instance:
public static CitizenDTO ToDTO(this Citizen citizen)
{
if (citizen == null) return null;
return new CitizenDTO {
Id = citizen.Id,
Name = citizen.Name,
HeadId = citizen.HeadId,
HeadName = citizen.FamilyHead.Name
}
}
var dto = aCitizen.ToDTO();
But how to map a list of citizens? I think Select() might do the work but I only know how to do it if the model and the dto have a same structure. Like this example:
IEnumerable<int> integers = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<string> strings = integers.Select(i => i.ToString());
So how to map a list of it?
You can use Linq Select() as you used for string in your question, no need to write long extension method
IEnumerable<CitizenDTO> dto = citizens.Select(x => x.ToDTO());
I found the answer before finishing my question. Just iterate through the list and add mapped DTO to it. Silly me
// Extension method
public static IEnumerable<CitizenDTO> ToDTO(this IEnumerable<Citizen> citizens)
{
if (citizen == null) return null;
var dto = new List<CitizenDTO>();
foreach(var citizen in citizens) {
dto.Add(citizen.ToDTO());
}
return dto;
}
// How to use
IEnumerable<CitizenDTO> result = listOfCitizens.ToDTO();
I would like to know, how could I, with AutoMapper, Map one Dto to multiple entities.
Lemme explain.
I've got one Dto, with an enum to describe its type (to avoid having multiple dtos)
Depending on that enum (RelationType here), I would like to map it to the correct Model (Entity, what ever, it's another object that I use in database).
public class BCardDto : IMappedDto
{
public long Id { get; set; }
public BCardRelationType RelationType { get; set; }
public long RelationId { get; set; }
}
Here are is my Model base:
public class BCardModel : IMappedDto
{
public long Id { get; set; }
}
And here the derived model :
public class CardBCardModel : BCardModel
{
// ormlite, ignore that
[Reference]
public CardModel Card { get; set; }
[ForeignKey(typeof(CardModel), ForeignKeyName = "fk_bcard_card")]
public long RelationId { get; set; }
}
How do I map my Dto to the correct Model depending on the enum i've given ?
(I don't wanna use Mapper.Map everywhere but I wanna let mapper do the runtime mapping job)
Here is how I do it for the Model -> Dto
cfg.CreateMap<CardBCardModel, BCardDto>()
.ForMember(s => s.RelationType, expression => expression.UseValue(BCardRelationType.Card))
.IncludeBase<BCardModel, BCardDto>();
Tell me if I do something wrong and explain me why please :)
Thanks by advance,
Blowa.
Let's say you have a setup wherein there is a base class and 2 classes which derive the base class:
public class ModelBase
{
public string Name { get; set; }
}
public class ModelOne : ModelBase { }
public class ModelTwo : ModelBase { }
Let's also say you have a DTO with an enum as below:
public class ModelDto
{
public string Name { get; set; }
public ModelType ModelType { get; set; }
}
public enum ModelType
{
One = 1,
Two = 2
}
So now the task is: How do I map the ModelDto to either ModelOne or ModelTwo depending on the value in ModelDto.ModelType property?
Here is how:
Mapper.Initialize(cfg => cfg.CreateMap<ModelDto, ModelBase>().ConstructUsing(x =>
{
switch (x.ModelType)
{
case ModelType.One:
return new ModelOne { Name = x.Name };
case ModelType.Two:
return new ModelTwo { Name = x.Name };
default:
throw new InvalidOperationException("Unknown ModelType...");
}
}));
Usage
var dto1 = new ModelDto { ModelType = ModelType.One, Name = "ModelOne" };
var dto2 = new ModelDto { ModelType = ModelType.Two, Name = "ModelTwo" };
var one = Mapper.Map<ModelBase>(dto1);
var two = Mapper.Map<ModelBase>(dto2);
Another way to do the mapping is by using dynamic:
public class PersonDto
{
public string Name { get; set; }
}
public class StudentDto : PersonDto
{
public int studentNumber { get; set; }
}
public class EmployeDto : PersonDto
{
public string EmployeId { get; set; }
}
public class Person
{
public string Name { get; set; }
}
public class Student : Person
{
public int StudentNumber { get; set; }
}
public class Employe : Person
{
public string EmployeId { get; set; }
}
Create Map by using:
Mapper.CreateMap<StudentDto, Student>();
Mapper.CreateMap<EmployeDto, Employe>();
Do the Mapping by:
try
{
var student = MapPerson((dynamic) studentDto);
var employe = MapPerson((dynamic) employeDto);
}
catch
{
throw new InvalidOperationException("Unknown ModelType...");
}
And define two Methods
public static Student MapPerson(StudentDto studentDto)
{
return Mapper.Map<StudentDto, Student>(studentDto);
}
public static Employe MapPerson(EmployeDto employeDto)
{
return Mapper.Map<EmployeDto, Employe>(employeDto);
}
The benefit is that you don't need a key and avoid the switch statement
I have a C# list which is of type Person. This list needs to be converted into JSON data format. The Person C# class look like this:
public class Person
{
public int ID { get; set; }
public static int PSID = 1;
public string name { get; set; }
public string nameToken { get; set; }
public double DOB { get; set; }
public List<Award> awards { get; set; }
public List<Link> links { get; set; }
public Person()
{
awards = new List<Award>();
links = new List<Link>();
ID = PSID;
PSID++;
}
}
As I am required to convert a C# list of type Person into JSON. I made another Class in C# called PersonJS. It is exactly like the Person C# class the only difference is that I have removed some of the properties that are not required in the JSON front-end. Namely: nameToken, PSID.
public class PersonJS
{
public int ID { get; set; }
public string name { get; set; }
public double DOB { get; set; }
public List<AwardJS> awards { get; set; }
public List<Link> links { get; set; }
}
One of the properties of PersonJS is a List called awards which is of Type AwardJS. A problem occurs below because I try and equal Person.awards List equal to PersonJS.awards List. However, they are of difference types so it is not possible to equal both lists. The reason why I have put them equal to different types is because the JSON data does not need all of the properties that I have used in C#. So I made two classes Award and AwardJS. The only difference is that Award contains a property called filmWebToken whereas AwardJS does not.
public class Award
{
public int filmID { get; set; }
public int categoryID { get; set; }
public string filmWebToken { get; set; }
}
public class AwardJS
{
public int filmID { get; set; }
public int categoryID { get; set; }
}
In my code I iterate over all of the properties in C# list of type Person and I attempt to create a personjs object and add it to a PersonJS C# list. The PersonJS list will go back to the front-end as JSON. However, because the award property in the class PersonJS is different to the award property in Person I get the error "Cannot implicitly convert type AwardJS to Award". The reason I get this error is because PersonJS does not contain filmWebToken which exists in the Person class. I don't want the filmWebToken to be in the PersonJS list as it is not meant to be a property in my JSON data. However, as there are property fields in Person.Award I still want access to: filmID and CategoryID how can I ignore/by-pass the filmWebToken field. This is what I have tried:
List<Person> allPersons = DataRepository.GetAllPersons(); // contains the C# data
List<PersonJS> personjs = new List<PersonJS>(); // empty to start with
foreach (var person in allPersons)
{
foreach (var award in person.awards)
{
personjs.Add(
new PersonJS
{
ID = person.ID,
links = person.links,
name = person.name,
DOB = person.DOB,
awards = person.awards // The types are not equal: Person contains filmWebToken whereas PersonJS does not
});
}
}
Add a method called ToAwardJS in Award:
public AwardJS ToAwardJS() {
return new AwardJS { filmID = this.filmID, categoryID = this.categoryID };
}
Then when you create the PersonJS object, do:
new PersonJS
{
ID = person.ID,
links = person.links,
name = person.name,
DOB = person.DOB,
awards = person.awards.Select(x => x.ToAwardJS()).ToList(),
});
What serializer are you using? Most provide attributes to specify which members to include in the serialization. For example, the DataContractJsonSerializer uses [DataContract] and [DataMember]. I think Json.net uses [JsonIgnore]. There's no need for multiple classes.
void Main()
{
var jsSer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Person));
var p = new Person {
ID = 1,
name = "John",
DOB = 1234.5,
nameToken = "token"
};
string result = null;
using (var ms = new MemoryStream())
{
jsSer.WriteObject(ms, p);
byte[] json = ms.ToArray();
ms.Close();
result = Encoding.UTF8.GetString(json, 0, json.Length);
}
Console.WriteLine(result);
}
[DataContract]
public class Person
{
//included
[DataMember]
public int ID { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string nameToken { get; set; }
[DataMember]
public double DOB { get; set; }
//ignored
public static int PSID = 1;
public List<string> awards { get; set; }
public List<string> links { get; set; }
public Person()
{
awards = new List<Award>();
links = new List<Link>();
ID = PSID;
PSID++;
}
}
Result:
{"DOB":1234.5,"ID":1,"name":"John","nameToken":"token"}
What is the best way to return only few properties to JSON Result from a collection IEnumerable?
Department object has 7properties I only need to 2 of them in client. Can I do this using C# anonymous types?
public class Department
{
public string DeptId { get; set; }
public string DeptName { get; set; }
public string DeptLoc1 { get; set; }
public string DeptLoc2 { get; set; }
public string DeptMgr { get; set; }
public string DeptEmp { get; set; }
public string DeptEmp2 { get; set; }
}
[HttpGet]
public JsonResult DepartmentSearch(string query)
{
IEnumerable<Department> depts = DeptSearchService.GetDepartments(query);
//Department object has 15 properties, I ONLY need 2 (DeptID and DeptName) in the view via returns JSON result)
return Json(depts, JsonRequestBehavior.AllowGet); // I don’t want all the properties of a department object
}
var deptnames = depts.Select(d => new { d.DeptID, d.DeptName });
Then just use deptnames
Sure, I json serialize anonymous types all the time. Is a sensible plan.
Use Linq projection
untested code
var deptsProjected = from d in depts
select new {
d.DeptId,
d.DeptName
};
return Json(deptsProjected , JsonRequestBehavior.AllowGet);