Issue with model binding enums with Json.NET ValueProviderFactory - c#

I'm trying to use Json.NET as my default serializer/deserializer in an ASP.NET MVC5 environment. I already use it to serialize my JsonResult. This works fine. But I'm having issues on using it as my ValueProviderFactory.
I have made some tests with complex objects and everything works, except for enumerators on deeper levels on my model (not direct root level properties).
Like in the code below:
public class MyModel
{
public string Property1 { get; set; }
public MyEnum FirstLevelEnum { get; set; }
public MyDetailModel Detail { get; set; }
}
public class MyDetailModel
{
public string Property1 { get; set; }
public IEnumerable<MyEnum> DeeperLevelEnumList { get; set; }
}
public enum MyEnum
{
Enumerated1,
Enumerated2
}
If I deserialize an object like MyModel, all properties will bind correctly, except for the items inside the DeeperLevelEnumList, which will turn to the default value 0.
Back in time, I used to also have a CustomModelBinder, to surpass issues with enums in MVC2~3. I noticed that in MVC5 that is no longer a problem and using the MVC serializer with all the default behaviors works fine (except for really large JSON, which is one of the reasons to use Json.NET).
I compared, side by side, the results in the Dictionary of objects that are generated after the deserialization and they are the same, in both cases, the DeeperLevelEnumList brings the correct value. But, when the ModelBinder GetPropertyValue method is called, with MVC deserializer, the bind is correctly made and with Json.Net it's not.
Am I missing something? I really looked into this on many posts and threads and didn't find an answer.

Related

Binding a ProtoInclude to the corresponding RuntimeTypeModel binding doesn't work

I'm currently trying out protobuf-net, and have got problem with serialization of the following class structure:
[ProtoContract]
public abstract class WorkerResponseBase
{
[ProtoMember(1)]
public WorkerErrorMessage ErrorMessage { get; set; }
[ProtoMember(2)]
public bool IsSuccess { get; set; }
[ProtoMember(3)]
public bool IsError { get; set; }
protected WorkerResponseBase()
{
}
protected WorkerResponseBase(bool isSuccess, [CanBeNull] string errorMessage)
{
IsSuccess = isSuccess;
IsError = !isSuccess;
ErrorMessage = new WorkerErrorMessage(errorMessage);
}
}
[ProtoContract()]
public class WorkerResponse<TPayload> : WorkerResponseBase
{
[ProtoMember(4)]
public TPayload PayloadOrNull { get; private set; }
....
}
When I first tried it with a concrete class as in e.g. WorkerResponse<LoginResult>, I was only able to have PayloadOrNull serialized.
Alright, I got to google a bit on how to make this work. I found this answer: ProtoBuf-Net ProtoInclude Generic Type Subclass
People mentioned, that [ProtoInclude] is required.
So, for testing this, I was trying to decorate the WorkerResponseBase with [ProtoInclude(100, typeof(WorkerResponse<LoginResult>))]. Bingo, serialization works perfectly.
Now, as you might be able to imagine, this is a very generic container for a response, so I wouldn't want to have to define all possible TPayloads in the base class, so a bit further down in the linked comment I found, that I should also be able to do this dynamically, and eventually via reflection.
So for testing purposes, I did the following instead of the [ProtoInclude]:
RuntimeTypeModel.Default.Add(typeof(WorkerResponseBase), false)
.AddSubType(100, typeof(WorkerResponse<LoginResult>));
However, when I run this, no serialization works at all, not even the serialization of the PayloadOrNull.
So, what am I doing wrong here?
The false in your code (to Add) is basically saying "and I'm going to control everything myself, don't process the properties and their attributes - I'll tell you explicitly". Since you're not doing that, you probably want to pass true. In the pending V3 API, this is an optional parameter that defaults to true.

Adding Property to Object in WCF Service Breaks Client

We consume a WCF service using C# code. The client was generated in Visual Studio by right-clicking "Add Service Reference" and pointing it at the WSDL.
Recently, the WCF provider adding some properties to one of the objects they serialize. The class went from
public class MyClass
{
public string Foo { get; set; }
public string Baz { get; set; }
public string Zed {get; set; }
}
to this:
public class MyClass
{
public string Foo { get; set; }
public string Bar { get; set; } //<= New Property
public string Baz { get; set; }
public string Zed {get; set; }
}
On our end, this caused Baz and Zed to suddenly start being null when deserialized, until we updated the service reference. In fact, the real object had some ~20 properties alphabetically after Bar, and they were all null (or 0 for ints, false for bools, etc).
It seems an odd way for the deserialization to fail. It didn't throw an exception or ignore the new properties it didn't know anything about.... it just made every property that appeared alphabetically after the new one deserialize to the default value.
So my question is, what's going on here and how do I prevent it? Preferably, I'd like some kind of setting for the client to tell it to "ignore new properties," but telling the service provider how they can prevent future breaking changes would be fine too.
MSDN has an article which lists the serialization ordering of the datamembers. One key point from that document:
current type’s data members that do not have the Order property of the
DataMemberAttribute attribute set, in alphabetical order.
So if you add a new property, without the Order-property of the DataMemberAttribute, the property is alphabetically ordered.
Based on discussion here, your only options are:
Change the serializer to something else
Make sure that the order of the elements in XML matches the order of your properties. Maybe you can always use the Order-property of the DataMemberAttribute?
Make sure that your dll's line up, I've seen some pretty funky issues in the past where one side of a service was pointing to an outdated dll
also remember the fundamentals of data contracts

Entity Framework - code first, remove field without schema change

I am working on a solution that uses the entity framework code first approach:
[XmlRoot(ElementName = "item")]
public class Item
{
[XmlElement("itemId")]
[Index("idx_item_id")]
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long ItemId{ get; set; }
[XmlElement("otherId")]
[Index("idx_other_id")]
public long OtherId{ get; set; }
[XmlElement("randomStuff")]
public string RandomStuff{ get; set; }
}
And is directly mapped as:
public class DataContext : DbContext
{
public DataContext()
: base("name=DataContext")
{
Database.CommandTimeout = 180;
}
public DbSet<Item> Items{ get; set; }
So basically I have XMLs coming in and these are directly mapped with the model. A HTTP POST comes in, xml is deserialized using the model and then directly inserted to the database. Now I am no longer interested in a field RandomStuff, but I don't want to change the schema, I would simply start inserting NULLs there. Would it make sense to write something like:
private string _randomStuff;
[XmlElement("randomStuff")]
public string RandomStuff
{
get { return _randomStuff; }
set
{
_randomStuff = null;
}
}
Or is there a better way to achieve this?
The best thing of course is to bite the bullet and change the schema. But I know there can be many reasons not to do that (just yet).
A better option (then the null assignment in the setter) is to use a private setter:
public string RandomStuff { get; private set; }
EF can handle private setters and by doing this, EF will never think the property has changed (because it reads a different value than the one it was set with) and fire useless updates. And you will still be able to read old content.
If you don't want to display the content, even if it's still there, I'd replace the mapped property by a new dummy property (again with a private setter) and mark the current property as not mapped.

Avoid using the JsonIgnore attribute in a domain model

I have a domain model component with several entity classes. In another component i have entity repositories implemented using Json.NET serialization. I want to ignore some of the entity properties during serialization, so the straight forward solution would be to decorate those properties with the JsonIgnore attribute. However, out of principle, i would like to avoid references to other components - including 3rd party libraries like Json.NET - in my domain model.
I know that I can create a custom contract resolver as described here but it is hard to generalize what to serialize and what not to serialize in the various entities. Generally I want to ignore all readonly properties, but there are exceptions as for example collections:
public List<Pixel> Pixels
{
get { return this.Pixels; }
}
I can also create a dedicated contract resolver for each entity as described here but that seems like a high-maintenance solution to me - especially with numerous entities.
The ideal solution would be if Json.NET had support for some attribute within the .NET framework, but I cannot even find an appropriate candidate...
I thought about making my own custom Ignore attribute in my domain model and making a custom contract resolver that uses reflection to detect this attribute and ignores the decorated properties when serializing. But is that really the best solution to the given problem?
I believe by default that Json.net Respects the DataContractAttribute. Although you have to be inclusive instead of exclusive, it also means that the serialization can change to Microsofts Binary (or maybe xml) and not have to redesign your domain models.
If a class has many properties and you only want to serialize a small subset of them then adding JsonIgnore to all the others will be tedious and error prone. The way to tackle this scenario is to add the DataContractAttribute to the class and DataMemberAttributes to the properties to serialize. This is opt-in serialization, only the properties you mark up with be serialized, compared to opt-out serialization using JsonIgnoreAttribute.
[DataContract]
public class Computer
{
// included in JSON
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal SalePrice { get; set; }
// ignored
public string Manufacture { get; set; }
public int StockCount { get; set; }
public decimal WholeSalePrice { get; set; }
public DateTime NextShipmentDate { get; set; }
}
The Json serializer also supports opt-in serialization:
[JsonObject(MemberSerialization.OptIn)]
public class File
{
// excluded from serialization
// does not have JsonPropertyAttribute
public Guid Id { get; set; }
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public int Size { get; set; }
}
From the Optin enum value docs:
Only members marked with JsonPropertyAttribute or DataMemberAttribute are serialized. This member serialization mode can also be set by marking the class with DataContractAttribute.
You might consider using something like a View Model to control which properties of your entity model are serialized. I haven't used it myself, but looked into using it for a project of mine, but AutoMapper might be something to look into to decouple the entity model from your serialized model.

Parsing messages with variable length arrays of fixed length fields

I have a need to parse (and build) fixed length text based messages that may in some cases contain array fields.
Example:
PARTA LOTA 02SUBLOT1 SUBLOT2 03TEST1 RESULT1 TEST2 RESULT2 TEST3 RESULT3
If this were an object, it might use the Lot object below.
Part Number (PARTA)
Lot Number (LOTA)
An Array of 2 SubLot Objects (SUBLOT1 with quantity 150 and SUBLOT2 with Quantity 999)
An Array of 3 Test Results (TEST1 with result 1234.67890, ...)
Note that the number of array items is specified in the message.
I was hoping to use the FileHelpers library that I've seen people talking about, but it doesn't appear to support multiple array fields where there is another field specifying the quantity, and it doesn't support field types that themselves have the attribute of [FixedLengthRecord()].
This is what I would like to be able to do. Note that the field length of 10 is just an artifact of keeping this simple. Not all fields would normally be defined with the same length.
[FixedLengthRecord()]
public class Lot
{
[FieldFixedLength(10)]
public string PartNumber { get; set; }
[FieldFixedLength(10)]
public string LotNumber { get; set; }
[FieldFixedLength(10)]
public SubLot[] SubLots { get; set; }
[FieldFixedLength(10)]
public Test[] Tests { get; set; }
}
[FixedLengthRecord()]
public class SubLot
{
[FieldFixedLength(10)]
public string SubLotNumber { get; set; }
[FieldFixedLength(10)]
public int Quantity { get; set; }
}
[FixedLengthRecord()]
public class Test
{
[FieldFixedLength(10)]
public string Description { get; set; }
[FieldFixedLength(10)]
public double Result { get; set; }
}
Anyone have any idea if this is possible with FileHelpers? Any other ideas? I have many different message types so I would rather not manually code for each one. The attribute decoration method in FileHelpers seems like a great clean solution and I'm considering just extending it, but I want to make sure I'm not missing a better solution out there.
I believe that I done something very similar in the past.
The way that I tackled this issue is to use custom attributes. This allowed me to create classes and nested objects which described my data exactly as described in the specification and use custom attributes to describe the data attributes (lenght, type, padding requirements, if required etc).
I also ended up writing a custom serialization/deserialization for the classes and attributes however that was really specific to the actual application as the data was coming through a custom government protocol which also sent and received data in fixed sized chunks or packets over encrypted sockets with continuation codes etc.
Tutorials
http://msdn.microsoft.com/en-us/library/aa288454%28v=vs.71%29.aspx
http://www.codeproject.com/KB/cs/attributes.aspx
http://www.devx.com/dotnet/Article/11579

Categories