Issue with MVC 3 model binder for propery which is a list of inherited objects - json

The issue is very similar to this post
How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?
However instead of trying to serialize a string manually we are attempting to use the model binding in MVC 3. So here is the scenario
[DataContract]
public class Company
{
[DataMember]
public List<Person> Employees { get; set; }
}
[DataContract]
public class Person
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
[DataContract]
[KnownType(typeof(Person))]
public class Employee : Person
{
[DataMember]
public string Department { get; set; }
[DataMember]
public string JobTitle { get; set; }
}
[DataContract]
[KnownType(typeof(Person))]
public class Artist : Person
{
[DataMember]
public string Skill { get; set; }
}
public JsonResult PopulateCompany()
{
Company model = new Company();
model.Employees = new List<Person>
{
new Employee(),
new Employee(),
new Artist(),
};
return Json(model, JsonRequestBehavior.AllowGet);
// in the View the model is correctly deserialized. E.g. we can see the properties from Artist
}
public ActionResult PopulateCompany(Company model)
{
// the returned model is also being populated except the Person object is being added to the Employees and we can no longer access the properties of Artist.
return View(model);
}
Thank you.

The model binding process involve first initializing the model. In your case it initializes an instance of Company with a property List<Person> Employees. Based on the values that are posted back, if a key/value pair is found that matches a Person (e.g. Persons[0].FirstName: "Ian") then a new instance of Person is initialized and its properties are set and added to the collection.
The DefaultModelBinder has no way of knowing that you want to initialize a different concrete type.
The easy solution is to use a view model containing collection properties of each type (e.g. public List<Employees> Employees { get; set; }; public List<Artist> Artists { get; set; }; etc).
The alternative (difficult) solution is to create a custom ModelBinder that will generate concrete types based on values in the model. This article (the section on Abstract Model Binder) is a good start for learning how to create a custom ModelBinder

Related

C# JSON data serialized and binded to DataGridView

I have this data class for storing data parsed from JSON formatted web data (using Json.NET library):
[Serializable()]
public class MovieData
{
public string FilePath { get; set; }
public string OrigName { get; set; }
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "year")]
public int Year { get; set; }
[JsonProperty(PropertyName = "genres")]
public string[] Genres { get; set; }
}
The next class is for to be able serialize collection of MovieData objects:
[Serializable()]
[XmlRoot("MovieCollection")]
public class MovieCollection
{
[XmlArray("Movies")]
[XmlArrayItem("Movie", typeof(Movie))]
public List<Movie> movies = new List<MovieData>();
}
Finally, I need to bind such a collection of MovieData to DataGridView (or single MovieData object to DataGridViewRow), like:
dgvMovies.DataSource = movieCollection.movies;
Is it possible to bind it without hard-setting of DataGridViewColumn collection before? Native data types are not problem, problem is string[] Genres array, which I need to format it in DataGridView in some way, like:
"genres[0] / genres[0] / ... genres[n]"
At this moment, while simply setting DataSource to collectin, this array is ignored (is not displayed anyway).
In MovieData class, you can add the following property :
public string GenresAsString
{
get { return String.Join("/", Genres); }
set { Genres = value.Split('/'); }
}
You will surely have to improve the setter to make it more resilient (triming, removing empty genres) if you plan to let the user modify this value.
Else you can remove the setter.

best way to exclude some parameters in a modelview when editing a page

I know there are a couple of options to exclude/include some parameters in a modelview like using bind or using interfaces. However I have some problems when I am trying to implement nested IEnumerable variables. For example:
public class TestViewModel()
{
public int Id { get; set; }
public IEnumerable<Organisation> KPI { get; set; }
}
public class Organisation
{
public string Id { get; set; }
public string Name {get; set;}
public DateTime StartDate {get; set;}
public IEnumerable<Regiod> CategoryValues { get; set; }
}
public class Region
{
public System.Guid Id { get; set; }
public System.Int32 RegionId { get; set; }
public int Value { get; set; }
public System.String RegionName { get; set; }
}
[HttpGet]
public ActionResult edit(int id)
{
var model = new TestViewModel();
// Do something to populate the model
view(model)
}
In the view page (razor) all fields are disabled or hidden, except field Value in Region class and StartDate in Organization. My action Code is something like:
[HttpPost]
public ActionResult edit(TestViewModel model)
{
// Do something to populate the model
}
Everything works fine, unless somebody uses for example fiddler to set other disabled or hidden values, so those fields will be updated.
What I am after is to update just enabled fields and exclude the rest even somebody tries to set a value for them.
I tried bind[Exclude and Include], but my problem is I can bind 2 values from different classes. I tried UpdateModel(model, include) and it didn't work.
Any advice would be appreciated.

How to omit Get only properties in servicestack json serializer?

I have an object which I am de-serializing using ToJson<>() method from ServiceStack.Text namespace.
How to omit all the GET only propeties during serialization? Is there any attribute like [Ignore] or something that I can decorate my properties with, so that they can be omitted?
Thanks
ServiceStack's Text serializers follows .NET's DataContract serializer behavior, which means you can ignore data members by using the opt-out [IgnoreDataMember] attribute
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
[IgnoreDataMember]
public string IsIgnored { get; set; }
}
An opt-in alternative is to decorate every property you want serialized with [DataMember]. The remaining properties aren't serialized, e.g:
[DataContract]
public class Poco
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public string IsIgnored { get; set; }
}
Finally there's also a non-intrusive option that doesn't require attributes, e.g:
JsConfig<Poco>.ExcludePropertyNames = new [] { "IsIgnored" };
Dynamically specifying properties that should be serialized
ServiceStack's Serializers also supports dynamically controlling serialization by providing conventionally named ShouldSerialize({PropertyName}) methods to indicate whether a property should be serialized or not, e.g:
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
public string IsIgnored { get; set; }
public bool? ShouldSerialize(string fieldName)
{
return fieldName == "IsIgnored";
}
}
More examples in ConditionalSerializationTests.cs
For nullable members, you also have the ability to set it to null before serializing.
This is particularly useful if you want to create a single view/api model that is re-used for several API calls. The service can touch it up before setting it on the response object.
Example:
public SignInPostResponse Post(SignInPost request)
{
UserAuthentication auth = _userService.SignIn(request.Domain, true, request.Username, request.Password);
// Map domain model ojbect to API model object. These classes are used with several API calls.
var webAuth = Map<WebUserAuthentication>(auth);
// Exmaple: Clear a property that I don't want to return for this API call... for whatever reason.
webAuth.AuthenticationType = null;
var response = new SignInPostResponse { Results = webAuth };
return response;
}
I do wish there was a way to dynamically control the serialization of all members (including non-nullable) on a per endpoint fashion.

Entity Framework - Code First using custom constructors for many to many relationships

As far as I did research on defining many to many relations with Code First, I guess that custom constructors in the entity classes are only needed for the purpose of being able to create a new instance of an entity plus the n:m-related entity AT ONCE.
At the moment I have my classes defined like this:
public class Person
{
public Person()
{
Events = new HashSet<Event>();
}
public int PersonId { get; set; }
public virtual ICollection<Event> Events { get; set; }
}
public class Event
{
public Event()
{
Persons = new HashSet<Person>();
}
public int EventId { get; set; }
public virtual ICollection<Person> Persons { get; set; }
}
However, if my application will never offer the possibility to create a new Person during creating a new Event, can I simply omit the custom constructor for Events?
public class Event
{
public int EventId { get; set; }
public virtual ICollection<Person> Persons { get; set; }
}
Will the many to many relation still work fine?
If you do that you'll get a NullReferenceException when you create a new event and try to add Persons to it.
var #event = new Event();
event.Persons.Add(new Person()); //NullReferenceException here
that is the only reason for that constructor, to initialise the collections.
you can initialise the Persons collection lazily inside the getter on first access but you need to be careful with multithreading.

How can I populate a FK field using EF Code First?

I have a class Mailout with a Status that looks like this:
public class Mailout
{
public int Id {get; set; }
public string Name {get; set; }
public MailoutStatus Status { get; set; }
}
public class MailoutStatus
{
public int Id { get; set; }
public string Name { get; set;}
}
When I insert Mailouts and set the Status property, they are inserted correctly. When I fetch them, Status is always null. Since I don't have (and don't want) the status ID on my Mailout class, I have no way to retrieve it after-the-fact. How do I tell EF to populate this field eagerly, rather than lazily?
I'm hoping I can set something up in OnModelCreating() since I want this behavior all the time, not as an option that I can use sometimes by manipulating my LINQ-to-Entities queries.
You need to make your navigation properties virtual.
There is no such option in the ModelBuilder to configure an automatic eager loading of navigation properties in each query. You have to specify it query by query. As a workaround you could encapsulate eager loading in some method or property, for instance in the context:
public class MyContext : DbContext
{
public DbSet<Mailout> Mailouts { get; set; }
public IQueryable<Mailout> MailoutsWithStatus
{
get { return Mailouts.Include(m => m.Status); }
}
// ...
}
And then use in your queries:
context.MailoutsWithStatus.Where(...) ... etc.
Only an idea, it's untested.
Taking from Employee Info Starter Kit - upcoming MVC edition, here is a snippet, that works pretty well, to eager load objects when used:
public class Employee
{
...
public int? ReportsTo { get; set; }
[ForeignKey("ReportsTo")]
public virtual Employee Supervisor { get; set; }
/// <summary>
/// Children object collection of foreign key relation
/// </summary>
public virtual List<Employee> Subordinates { get; set; }
}