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.
Related
I have "business entities" and their counterpart for saving them to Azure Storage Table, which requires a few additional properties.
// MyData is the business entity with a few properties
public record MyData_AzureTable : MyData, ITableEntity
{
// Required properties for storing data to Azure Storage Table
public string PartitionKey { get; set; } = "";
public string RowKey { get; set; } = "";
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; } = new ETag();
}
I am getting tired of having to duplicate each business entity with its AzureTable counterpart but I can't find the correct pattern to use. Something like that, except it's illegal to inherit from a type parameter.
public record AzureTable<T> : T, ITableEntity
{
public string PartitionKey { get; set; } = "";
public string RowKey { get; set; } = "";
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; } = new ETag();
}
What pattern should be used for adding properties to a base class?
The object saved to Azure Table Storage needs to be "flat" (tabular data as property values, no hierarchical data or encapsulation)
Not necessarily a pattern but abstract classes may fit well for your need here. Check out the docs: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract
In conclusion, those classes have a base one (which would be your always default AZ properties) and all the other classes than inherit from the abstract one will contain those properties as well without needing implementation (like an interface would) but you can extend the children and add more custom properties to each one.
There is no such pattern, currently C# does not support something like traits (though in some cases similar can be achieved with default interface member implementations) and/or multiple inheritance (basically MyData_AzureTable should inherit from both MyData and AzureTable). If you are really tired of writing "duplicates" for data - you should consider using source generators - you can write quite a simple one which will generate azure tables classes for all required classes (for example marked with special attribute like GenerateAzureTable). Potentially it can generate also some useful methods for mapping, copy constructors and so on.
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.
I was working on an enhancement in my Xamarin Android app to make working with Android's saved state easier. One part of the implementation for this needs to Json serialize the properties of current Activity class that have the custom [SaveState] attribute. All other properties are ignored. I've got this mechanism working using a POCO (and Json.NET as serializer). When defining a public property with the custom [SaveState] attribute, it serializes (only) that property as desired.
When I define a class that extends the (obviously) required Activity class, lets call it ExampleActivity, it doesn't serialize the public property anymore. So, the same setup that was working for the POCO isn't working anymore when extending the Activity.
In addition: it's not serializing anything of the ExampleActivity or of the inherited Activity's properties. Even though many are public. Just an empty Json string object.
When I add the [JsonProperty] attribute to the public property it d̲o̲e̲s̲ though! So I believe it's not a matter that Json.NET can't serialize the property, it just won't. For some reason it's ignoring it and everything else.
I've tried some things, but I can't seem to figure out why it's ignoring the properties. I've added a TraceWriter to the serializer in the hopes to see something that might point me in the right direction, but it doesn't.
I've added a small stripped code snippet that reproduces the issue:
public static class Example
{
public static void Run()
{
var exampleActivity = new ExampleActivity { PropertyA = "A value", PropertyB = "B value" };
// Default serializer settings with a memory trace writer
var serializerSettings = new JsonSerializerSettings { TraceWriter = new MemoryTraceWriter() };
var serializedString = JsonConvert.SerializeObject(exampleActivity, serializerSettings);
System.Diagnostics.Debug.WriteLine(serializerSettings.TraceWriter);
// NOTE: The serialized string only contains PropertyB
System.Diagnostics.Debug.WriteLine($"SerializedString: {serializedString}");
}
public class ExampleActivity : Activity
{
//[JsonProperty]
public string PropertyA { get; set; }
[JsonProperty]
public string PropertyB { get; set; }
}
}
When calling the static Example.Run() you'll see that even though the ExampleActivity's PropertyA is a regular public property it's not serialized. Whereas the PropertyB which has the [JsonProperty] attribute i̲s̲ serialized.
For my solution I don't want to be adding the [JsonProperty] attribute to each property that also get's the custom [SaveState] attribute. That it's currently using Json (de)serializing behind the scenes to achieve the desired behavior shouldn't have influence on the usage of the [SaveState] behavior.
I hope I've been sufficiently complete in the describing of my issue. Does anybody know why the regular public properties of the class extending the Activity aren't serialized? And/or how to fix this?
I need to deserialize some JavaScript object represented in JSON to an appropriate C# class. Given the nice features of automatic properties, I would prefer having them in these classes as opposed to just having fields. Unfortunately, the .NET serialization engine (at least, by default) totally ignores automatic properties on deserialization and only cares about the backing field, which is obviously not present in the JavaScript object.
Given that there's no standard way to name backing fields and to be honest I don't even want to bother with the "let's create a JavaScript object that looks like it had C# backing fields" approach as it sounds a bit dirty, the only way I could serialize JavaScript fields to C# auto-properties if I could force the serialization engine to somehow ignore the backing field and use the property directly. Unfortunately, I can't figure out how this is done or if this can be done at all. Any ideas would be appreciated.
EDIT: Here's an example:
Javascript:
function Cat()
{
this.Name = "Whiskers";
this.Breed = "Tabby";
}
var cat = new Cat();
This is then serialized to "{Name: 'Whiskers'}".
The C# class:
[Serializable()]
public class Cat
{
public string Name { get; set; }
public string Breed { get; set; }
}
And the deserialization code, that fails:
new DataContractJsonSerializer(typeof(Cat)).ReadObject(inputStream);
And it is apparent from the exception that it fails because it is looking for the backing field.
EDIT2: Here's the exception, if that helps (no inner exceptions):
System.Runtime.Serialization.SerializationException
"The data contract type 'Test.Cat'
cannot be deserialized because the
required data members
'<Name>k__BackingField, <Breed>k__BackingField' were not
found."
What's happening here is the deserializer is trying to guess the name of your backing fields.
You can solve this by adding explicit mappings (DataContract/DataMember attributes) like this:
[DataContract]
public class Cat
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Breed { get; set; }
}
You can do this with JavaScriptSerializer found in the System.Web.Script.Serialization namespace:
JavaScriptSerializer serializer = new JavaScriptSerializer();
Cat c = serializer.Deserialize<Cat>(jsonString);
I have POCO objects with automatic properties and this works just fine.
EDIT: I wrote about JSON Serializers in .NET which compares this serializer with DataContractJsonSerializer.
baretta's answer solved the k__BackingField bloat for me. Just a tiny addendum that you can decorate this class to auto serialize into either XML or JSON in a similar way:
[Serializable, XmlRoot, DataContract]
public class Cat
{
[XmlElement]
[DataMember]
public string Name { get; set; }
[XmlElement]
[DataMember]
public string Breed { get; set; }
}
... and then use a DataContractJsonSerializer or XmlSerializer to prepare it for your endpoint.
I'm assuming you are passing data via a web service. If you are using the WebService class with the ScriptMethod attribute uncommented-out, the web service methods can read JSON natively. They even use the same JavaScriptSerializer that was mentioned above. If you are using WCF I'm a little more fuzzy on the logic.
But make sure your JSON object are returning data for EVERY property in your class. In your error, there is mention of a Breed property that is not in your example.
Also, on the JavaScript side, do to the dynamic nature of JavaScript it is easy to add new properties to your objects. This can sometimes lead to circular references. You should remove any extra data that you might have added (just as you are sending data via the web method, then add it again once you are done).
Following situation:
Our software works with business objects, at the moment they are sent with wcf from the server to the client.
[Serializable]
public class SomeValueBO
{
public DateTime Timestamp{ get; set; }
}
They are packed in request/response messages.
[DataContract]
public class Response
{
[DataMember]
public List<SomeValueBO> Values { get; set; }
}
The Problem:
We would like to send DTO's to the client instead of the business object's. I heard, that it is possible to retrieve at the client an instance of a different type than was sent on the server.
Example:
public interface ISomeValue
{
DateTime Timestamp { get; set; }
}
[Serializable]
public class SomeValueBO : ISomeValue
{
public DateTime Timestamp { get; set; }
}
[DataContract]
public class SomeValueDTO : ISomeValue
{
[DataMember]
public DateTime Timestamp { get; set; }
}
The response would look like this:
[DataContract]
public class Response
{
[DataMember]
public List<ISomeValue> Values { get; set; }
}
On the server:
public class ServiceClass : IService
{
public Response HandleRequest(Request request)
{
Response response = new Response();
response.Values.Add(new SomeValueBO());
return response;
}
}
On The client:
Response response = serviceProxy.HandleRequest(request);
ISomeValue value = response.Values[0];
value is SomeValueDTO
I tried it with declaring only the known type of the DTO object and with Data Contract Equivalence, but WCF still keep deserializing the item as a BO instance.
I have to add, that both ways have to work, Sending the BO and retrieving it as a BO and sending the BO and retrieving a DTO, but of course with different requests.
So my question is, is this possible and if yes, what am I doing wrong?
Thanks for help,
Enyra
Edit:
I also found out, that we are using the NetDataSerializer, could that be the problem that it does not work?
Even if you weren't using NetDataContractSerializer (comment), the fact that SomeValueBO isn't declared as a data-contract means that it will mainly be acting as a field-serializer. Which is a pain in particular because automatically-implemented properties are a royal pain re field serializers - they become insanely brittle.
I would declare as a contract:
[DataContract]
public class SomeValueBO
{
[DataMember]
public DateTime Timestamp{ get; set; }
}
and switch to DataContractSerializer, but note that this is a breaking change - you would have to update all clients and servers at the same time. You would then be able to have alternative implementations as long as they shared the full contract signature.
Re the current use of NetDataContractSerializer - if this is for performance, there are alternatives - there are contract based binary serializers that are faster (CPU) and smaller (bandwidth) than NetDataContractSerializer: Performance Tests of Serializations used by WCF Bindings
From MSDN:
The NetDataContractSerializer differs
from the DataContractSerializer in one
important way: the
NetDataContractSerializer includes CLR
type information in the serialized
XML, whereas the
DataContractSerializer does not.
Therefore, the
NetDataContractSerializer can be used
only if both the serializing and
deserializing ends share the same CLR
types.
That's why it's not working at present.
If you use the DataContractSerializer instead, the client and the service only need to agree on the serialized XML representation of the object state, not on the exact CLR runtime type. You'll need to attribute both sides' types with DataContractAttribute in order to get the XML namespace associated with the serialized representation the same on both sides. And obviously the data contracts will have to be equivalent in terms of the serialized structure.
That said, what you are trying to do should be workable with the DataContractSerializer. As for whether it's the best way to go - like all design decisions "it depends".