Specify JsonConverters with attributes in Json.net? - json.net

I am receiving JSON data to my server with dates represented like this:
{
"startDate": {
"d": "/Date(1346454000000)/"
},
"slots": [
{
"d": "/Date(1347058800000)/"
},
{
"d": "/Date(1347145200000)/"
}
]
}
Its serialized to a simple object:
public class SlotsVm
{
public DateTime StartDate { get; set; }
public DateTime[] Slots { get; set; }
}
Because the date format is strange, I had to write a custom JsonConverter to process it. To deserialize, I use code like this:
var slotsVm = JsonConvert.DeserializeObject<SlotsVm>(body,
new CustomDateTimeConverter());
If possible, I would like the need for the converter to be defined on the SlotsVm class, rather than in the code that actually makes the conversion. This is possible for the startDate property using attributes:
[JsonConverter(typeof(CustomDateTimeConverter))]
public DateTime StartDate { get; set; }
but it is not possible for Slots, which is an array instead of a simple DateTime.
It would be best for me to be able to define the converters that the class needs on the class itself:
[JsonConverters(typeof(CustomDateTimeConverter), ...]
public class PutDealVm
{
}
but there doesn't seem to be a way to do this.
Can you think of a solution? Is there some way to define converters for a class that I have missed? Alternatively, is it possible to define the converter that an array should user for each of its elements?

What about something like this? I appreciate that this may not directly answer your question, but I was too lazy to recreate the CustomDateTimeConverter class, so came up with this instead, which is arguably simpler, as there is no need for a custom converter.
string json = "{\"startDate\": {\"d\": \"/Date(1346454000000)/\"},\"slots\": [{\"d\": \"/Date(1347058800000)/\"},{\"d\": \"/Date(1347145200000)/\"}]}";
SlotsVmDeserialized slotsVmDeserialized =
JsonConvert.DeserializeObject<SlotsVmDeserialized>(json);
SlotsVm slotsVm = new SlotsVm()
{
Slots = slotsVmDeserialized.Slots.Select(d => d.Date),
StartDate = slotsVmDeserialized.StartDate.Date
};
....
public class SlotsVm
{
public DateTime StartDate { get; set; }
public IEnumerable<DateTime> Slots { get; set; }
}
public class SlotsVmDeserialized
{
public DateObject StartDate { get; set; }
public IEnumerable<DateObject> Slots { get; set; }
}
public class DateObject
{
[JsonProperty("d")]
public DateTime Date { get; set; }
}
What I've done here is firstly deserialized to the SlotsVmDeserialized class, which is used to hold a single DataObject and an IEnumerable of them. The DateObject class is essentially my alternative/workaround to the custom converter. I could have done all this without any attributes by removing [JsonProperty("d")] and renaming Data to D.
Once deserialized, I then create a new SlotsVm object based on the properties of the SlotsVmDeserialized object.

Related

How to specify default property values for owned entity types in Entity Framework Core 2.0?

I have a simple POCO type, say something like
public class OwnedEntity {
public string stringProperty { get; set; }
public decimal decimalProperty { get; set; }
public bool boolProperty { get; set; }
public int intProperty { get; set; }
}
and an actual entity with an OwnedEntity reference
public class SomeEntity {
public string Id { get; set; }
public OwnedEntity OwnedEntity { get; set; }
}
I set up the relationship like described in the documentation using EF Core's Fluent API:
protected override void OnModelCreating (ModelBuilder builder) {
base.OnModelCreating (builder);
builder.Entity<SomeEntity> ().OwnsOne (e => e.OwnedEntity);
}
I can't find anything on how to define default-values for all the properties of OwnedEntity. I tried to initialize the properties like this:
public class OwnedEntity {
public string stringProperty { get; set; } = "initial"
public decimal decimalProperty { get; set; } = -1M;
public bool boolProperty { get; set; } = false;
public int intProperty { get; set; } = -1;
}
but with no effect. Same goes with the [DefaultValueAttribute] (but that was to expect since it's explicitly mentioned).
There's a bit of information on how to handle initial values for regular entities:
modelBuilder.Entity<SomeOtherEntity>()
.Property(e => e.SomeIntProperty)
.HasDefaultValue(3);
But since I'm facing an Owned Entity Type, I can't access the type via Entity<T>.
Is there a way of doing what I'm looking for?
Some things worth mentioning:
I have a solid amount of specific entities where most of them are using the OwnsOne relation
Declaring all OwnedEntity-properties in a base class is not an option since not all the entities have those properties
I`m using EF Core 2.0.3 and ASP.NET Core MVC 2.0.4
Edit:
Originally, I wanted to have newly created SomeEntity instances to come with preset properties for all of the 'embedded' SomeEntity.OwnedEntity properties.
But looking at how my associated controller works, it all makes sense... I have the following methods for the 'Create' operation:
[HttpGet]
public IActionResult Create () {
return View (nameof (Create));
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create (SomeEntity model) {
context.Add (model);
await context.SaveChangesAsync ();
// redirect etc.
}
Which means that no object is created for the [HttGet] overload of Create and all the HTML inputs linked to properties (via asp-for) are initially empty. Okay. So I guess the proper way of doing this is to manually create a new instance of SomeEntity and pass it to the Create view like this:
[HttpGet]
public IActionResult Create () {
return View (nameof (Create), new SomeEntity());
}
Is this the right approach then or are there some more things to keep in mind?
Assuming you understand what EF Core Default Values are for, and just looking for equivalent of Entity<T>().Property(...) equivalent.
The owned entities are always configured for each owner type by using the ReferenceOwnershipBuilder<TEntity,TRelatedEntity> class methods. To access this class you either use the result of OwnsOne method, or use the OwnsOne overload taking second argument of type Action<ReferenceOwnershipBuilder<TEntity,TRelatedEntity>>.
For instance, using the second approach:
builder.Entity<SomeEntity>().OwnsOne(e => e.OwnedEntity, ob =>
{
ob.Property(e => e.stringProperty)
.HasDefaultValue("initial");
ob.Property(e => e.decimalProperty)
.HasDefaultValue(-1M);
// etc.
});

Validating that a Reason field is filled if Date field is today

I use ASP.NET MVC4 in my solution. I have the ViewModel below where I would like to validate that the field EmergencyReason is filled only if the field Date is today. I try this:
public class LoadingViewModel
{
public DateTime Date { get; set; }
[RequiredIf("Date", Comparison.IsEqualTo, DateTime.Today)]
public string EmergencyReason { get; set; }
...
}
It doesn't work. The third argument of RequiredIf must be a constant expression, ...
Any idea how can I force the user to enter an EmergencyReason only if Date field is today?
Thanks.
You seem to be using some non-standard RequiredIf attribute which is not part of the standard ASP.NET MVC 4 package.
As you know C# allows you to only pass constant values to attributes. So one possibility is to write a custom attribute:
public class RequiredIfEqualToTodayAttribute: RequiredIfAttribute
{
public RequiredIfEqualToTodayAttribute(string field)
: base(field, Comparison.IsEqualTo, DateTime.Today)
{
}
}
and then:
public class LoadingViewModel
{
public DateTime Date { get; set; }
[RequiredIfEqualToToday("Date")]
public string EmergencyReason { get; set; }
...
}
C# doesn't support DateTime literals, a workaround for this is to use a String like this, but it won't resolve your problem. I suggest you move the validation code inside the Controller and return a ModelState.AddModelError("EmergencyReason", "Emergency Reason is required")

ASP.NET MVC3 EF model Inheritance Cannot implicitly convert type

I am sure i am just missing some pretty basic here, but i can't seem to figur it out.. maybe because its been a while since i have been on the .NET platform.
Anyway, I have this database structure i the ASP.NET MVC3 framework where i have "Coruse", "Tool" and "ToolADL"(Inheritance from Tool). A "Course" can have one-or-more "Tools" where one of the "Tool"-types is "ToolADL".
Models/Course.cs:
public class Course {
[Key]
public int CourseID { get; set; }
[Required(ErrorMessage = "{0} er påkrævet")]
[Display(Name = "Værktøj")]
public virtual ICollection<Tool> Tools { get; set; }
}
Models/Tool.cs:
public abstract class Tool {
public Tool(){
Priority = 0;
}
[Key]
public int ToolID { get; set; }
[Required]
public int CourseID { get; set; }
[Required]
public int Priority { get; set; }
}
Models/ToolADL.cs:
public class ToolADL : Tool {
[Required]
public string Image { get; set; }
}
aaand the Models/ProjectContext:
public class ProjectContext : DbContext {
// Course context
public DbSet<Course> Courses { get; set; }
// Tools
public DbSet<Tool> Tools { get; set; }
// ToolADL
public DbSet<ToolADL> ToolADLs { get; set; }
}
Now when i try to create the controller and connect to DbContext and the Model to it so the entity framwork can do its magic, I get the following error in the ToolADL controller Details function (and others) where time i use "find()":
ToolADLController.Details(int):
private ProjectContext db = new ProjectContext();
public ViewResult Details(int id){
ToolADL tooladl = db.Tools.Find(id);
return View(tooladl);
}
Error 1 Cannot implicitly convert type 'Project.Models.Tool'
to 'caREhab_community.Models.ToolADL'. An explicit conversion exists
(are you missing a cast?) C:\Users\Thor\Documents\Visual Studio
2010\Projects\Project\Project\Project\ToolADLController.cs 29 31 Project
(I changed the name of the orginal project to "Project")
I simply cannot figur out what I am doing wrong, Is it wrong types, some really basic about Inheritance i left out or something else?
Hope some kind soul can tell me why I am an idiot and can't figure this out :)
If object that is returned by db.Tools.Find(id) is of type ToolADL then you should do:
ToolADL tooladl = db.Tools.Find(id) as ToolADL;
After that You'll have your object or null.
If it's not of type ToolADL then you can't do this because:
When You have:
public class A { }
public class B : A { }
You can not do something like this:
A a = new A();
B b = a;
This is in fact a basic truth about inheritance.
You might change this implicit conversion to explicit on by doing:
B b = (B)a;
Then your code would compile but You would get a runtime exception:
Unable to cast object of type 'A' to type 'B'.
To make it work You would have to specify an explicit conversion like this:
public class A
{
public static explicit operator B(A a)
{
return new B();
}
}
But this will give you yet another compile time error:
'A.explicit operator B(A)': user-defined conversions to or from a
derived class are not allowed

Map all properties of a class using reflection

I have two domain classes
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string HouseName { get; set; }
public string StreetName { get; set; }
public string PinCode { get; set; }
}
I want to map object of Employee class to another class.
I am using reflection to map empData object to another object. The code i used is
private void GetValues(object empData)
{
System.Type type = empData.GetType();
foreach (PropertyInfo pInfo in type.GetProperties())
{
//do some stuff using this pInfo.
}
}
I could easily map all the properties except the Address property in the emp object which is an object of another class.
So how can i map all the properties irrespective of its type ? i.e, if address contains object of another class it should also get mapped.
Can't you use AutoMapper for mapping classes?
You can know the type of property you are mapping by
if (propertyInfo.PropertyType == typeof(Address))
{ // do now get all properties of this object and map them}
Assuming that you want to be able to do this on any type of object and not just this specific one, you should use some sort of recursive solution. However if it's just for this object - why are you even using reflection? To me it just adds unnecessary complexity to something as simple as mapping six properties to another set of objects.
If you want to get more concrete help with code examples, you'll have to give us some more context. Why does a method named "GetValues" has a return type of void? I have a hard time coding up an example with that in mind. :)

C# serializing Class to XML where one of class properties is DateTime. How to make this property in ISO format?

I'm serializing class which contains DateTime property.
public DateTime? Delivered { get; set; }
After serializing Delivered node contains DateTime formatted like this:
2008-11-20T00:00:00
How can I change this property to make it look like this:
2008-11-20 00:00:00
Thanks in advance
The hack I use for odd formatting during XmlSerialization is to have a special property that is only used during XmlSerialization
//normal DateTime accessor
[XmlIgnore]
public DateTime Delivered { get; set; }
//special XmlSerialization accessor
[XmlAttribute("DateTime")]
public string XmlDateTime
{
get { return this.Delivered.ToString("o"); }
set { this.Delivered = new DateTime.Parse(value); }
}
Take a look at XmlAttributeOverrides class.

Resources