This question already has answers here:
Can I optionally turn off the JsonIgnore attribute at runtime?
(3 answers)
Closed 4 years ago.
I am currently using the same C# DTOs to pull data out of CouchDB, via LoveSeat which I am going to return JSON via an ASP MVC controller.
I am using the NewtonSoft library to seralise my DTOs before sending them down through the controller.
However, as CouchDB also uses NewtonSoft it is also respecting the property level NewtonSoft attributes such as
[JsonIgnore]
[JsonProperty("foo")]
Is there anyway to tell the newtonsoft library to ignore these attributes explicitly? LoveSeat allows me to provide my own implementation of IObjectSerializer, which gives me full control over netwonsofts JsonSerializerSettings. So, can I ignore the attributes by using those settings ?
I ask as the only alternative I can see at this point, is to dupe my DTOs. While not that's not terrible, it isn't great either.
The only other way I can see is to bring in my own version of the Newtonsoft.Json source into my project, with a different assembly name etc etc. But this way madness definitely lies and I will just dupe the DTOs before I go down this road.
I'm not sure if this is what you're after, but from what I understand you're looking for the [JsonIgnore] attribute. Stops properties from being serialized with the rest of the object into to JSON.
[JsonIgnore]
public string Whatever{ get; set; }
One suggestion that you may not like. For best practices, I recommend having two almost identical objects. One specifically for your Data Access Layer (Domain Object) which maps to your DB. And a separate DTO that your apps care about. This way the Domain Object will mostly contain more properties than the DTO and you can separate the concerns.
According to Json.NET documentation
You can add method to your class: public bool ShouldSerialize_________(){...} and fill in the blank with the name of the property you don't want to serialize. If the method returns false, the property will be ignored.
The example from the documentation doesn't want to serialize an employee's manager if the manager is the same employee.
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public bool ShouldSerializeManager()
{
// don't serialize the Manager property if an employee is their own manager
return (Manager != this);
}
}
You could put some kind of inhibit setting on your class:
public class DTO
{
[JsonIgnore]
public bool IsWritingToDatabase { get; set; }
public string AlwaysSerialize { get; set; }
public string Optional { get; set; }
public bool ShouldSerializeOptional()
{
return IsWritingToDatabase;
}
}
But, this isn't much simpler than having two objects. So I would recommend doing as #zbugs says, and having separate definitions for API-side and DB-side.
I ended up making all properties I needed to only add attributes to virtual, and overriding them alone in another class, with the relevant newtonsoft attributes.
This allows me to have different serialisation behavior when de-serialising from CouchDB and serialising for a GET, without too much dupe. It is fine, and a bonus, that the two are coupled; any changes in the base i would want anyway.
It would still be nice to know if my original question is possible?
This newtonking.com link helped in a similar situation. It extends the DefaultContractResolver class. To make it work I had to replace
protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
with
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
Related
I have an ASP.NET Core application which can have components of different types. These types are not know until runtime. I have a set of settings which are in a taxonomy of types, and a top-level settings object that stores a collection of the configured components. E.g.,
public class ServiceSettings
{
List<ComponentSettingsBase> Components { get; set; }
}
public abstract class ComponentSettingsBase
{
}
public class ASettings : ComponentSettingsBase { get; set; }
public class BSettings : ComponentSettingsBase { get; set; }
Using a Json file, I can create the base ServiceSettings object and map it correctly for simple types like strings. When it comes to the collection it just ignores it. I've tried adding type information like Json.NET (Newtonsoft) does for type name handling, but haven't found anywhere to configure how it should be deserialized. I thought that's what they used to use, and there are easy configuration settings for the Json serializer used for Web API communication, but this does not seem to effect the settings/configuration serialization.
Is there a way that I can do this using the built-in settings provider? Or will I need to do something like use the settings provider to point to another file, then use a more fully-fledged Json deserializer to deserialize the settings?
I think the problem here is that you want to map a JSON array to a C# List<T>.
What I would do is to change my code to something like this:
public class ServiceSettings
{
ComponentSettingsBase[] Components { get; set; }
}
I might be wrong, however...
Next thing I would try is to go the other direction and
build an example object model in memory
serialize it to a JSON
see how that JSON looks like to learn the format your environment likes
reproduce what you need in the format you have learned in the previous step
Problem
I call different webservices which returns json strings. I parse these strings to custom objects and save them in a "result class" called APIResult. For instance, one webservice returns a list OBJ1, another returns OBJ2, and sometimes two or more objects are returned as well. The result class is returned to the method calling it with the objects and a boolean indicating whether the request was succesful.
This works, but when I have to call many different webservices the class gets ugly. Right now I have 7 properties like OBJ1, OBJ2, List, List and so on. To avoid adding more properties to the APIResult class I want to redesign it to be more flexible, but I'm not sure what is the best approach.
Ideas
Generics seems to be a good idea. I could initialize my class with new APIResult(ObjectType) and then have one or more properties T Data1. Still a bit ugly to have three properties T Data1, T Data2, T Data3. I am also unsure if I can parse the objects from json to a generic type without reflection and if that would slow things down.
Do you have any suggestions?
Separate the result state from the actual data.
As you suggested, generics are a useful tool for this. Create a result state class that encapsulates the success/failure logic and (in the case of success) provides access to the data.
This could look something like this:
public class ApiResult<T>
{
public bool Success { get; }
public T Dto { get; }
public ApiResult(bool success, T dto)
{
Success = success;
Dto = dto;
}
}
Now design the data classes as simple property bags without any logic. Their only purpose is to define what data is returned from a specific web service. Also, do not try to build deep inheritance hierarchies. Adding the same property to two different DTOs is fine.
public class Dto1
{
string PropertyA { get; set; }
string PropertyB { get; set; }
}
public class Dto2
{
string PropertyA { get; set; }
string PropertyC { get; set; }
}
With this, you are now able to define proxies for the web services you call. A proxy interface could look like this:
public interface ISomeServiceProxy
{
ApiResult<Dto1> GetTheThing(string someParam);
}
In the implementation of this interface you will want to use JSON.NET to deserialize the response into a Dto1 and wrap it in a ApiResult.
Also, you probably want to make the proxy use async. I left that out in these examples, converting them is straight-forward.
There are few things to consider here
Do you need an APIResult class? What are you going to do with it? If you have a well documented REST api (say an odata api) then the response is well described and you can verify that the response you get is what you need. Otherwise what are you going to do if it doesn't match?
if you are just going to parse it into your model you might even consider the generic JObject to hold your response. Then you can check for properties/subobjects on this JObject. You could even pass this into the (newtonsoft) json serializer and have the calling method say what it should look like.
what is the business meaning of your response? Result is always a hard name. However if you you have properties like FirstName, LastName, AddressList, etc then it becomes a lot nicer.
This question already has answers here:
Is DataContract attributes required for WCF
(4 answers)
Closed 9 years ago.
I was wondering if there is any way to define a WCF Contract class without using the [DataContract] and [DataMember] annotation. The reason is that domain model we currently have is fairly clean so we would like to keep it this way. Whats the best practice here? Create a Transfer object and copy the domain model object into a transfer object (that has the required annotations and is the Contract transfered between Client and Server)? Or somehow not annotate the object model and specify the contract in a different way.
If you do not add any serialization attributes to your class, and use it as part of a WCF service contract method, WCF will use the default serialization rules to produce a data contract anyway. This means that the class will implicitly become a [DataContract] every public property that has both a get and set accessor will implicitly become a [DataMember].
The only time you need to apply the attributes is if you want to override the default behavior, e.g. hiding some attributes, applying namespaces, etc. It's generally considered good practice to do so anyway, because relying on the default behavior might get you in trouble later. (It also makes it explicit that your class is meant for use by WCF). But it's not strictly required, as long as the default behavior meets your needs.
In response to your follow-up:
As far as I know there's no completely external way to change the serialization behavior of the DataContractSerializer for a given class; every option requires at least some level of attribution on the class being serialized. As #Yair Nevet describes below, my preferred method for turning existing domain objects into data contracts is the MetadataType attribute.
Alternatively, you can bypass the whole issue by doing what you suggested in your question: don't serialize your domain objects, but create custom DTO objects and serialize them. I tend to do this whenever I'm using the Entity Framework, for example, because serializing those can be tricky. This is also a good approach to take if your domain objects have lots of behaviors built into them -- you get a clear separation of "data being passed around" vs. "objects participating in my business logic."
You often end up with lots of redundant code, but it does achieve your goal of zero changes to your existing objects.
You can use the MetadataType attribute and a metadata model class in order to separate the annotations from your model.
For example:
[MetadataType(typeof(MyModelMetadata))]
public class MyModel : MyModelBase {
... /* the current model code */
}
[DataContract]
public class MyModelMetadata {
[DataMember]
public string Name { get; set; }
}
WCF is capable of serializing your objects without the attributes. The attributes are there to allow for customization. For example, the two classes will serialize identically by the DataContractSerializer:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
[DataContract]
public class Customer
{
[DataMember] public string FirstName { get; set; }
[DataMember] public string LastName { get; set; }
}
It is worth mentioning that you really should mark your class with the attributes. They aren't as "messy" as you think. It will actually save you from headache in the future. For example:
[DataContract(Name = "Customer")]
public class Customer
{
[DataMember(Name = "FirstName")]
public string FirstName { get; set; }
[DataMember(Name = "LastName")]
public string LastName { get; set; }
}
In the previous code sample, I explicitly set the names of the class and members. This will allow me to refactor the names without breaking consumers code. So, if someone decides that my class should be named CustomerDetail instead of Customer, I can still leave the name as Customer so that consumers of my service continue to work.
You could always use DTOs. Make a separate class that has everything that is needed to serialize your objects. Then project your domain model on to the DTO. You could use something like AutoMapper to make this process a little easier.
Regarding Performance
Unless you have hundreds, probably thousands, or objects or a very large number of properties per class, the act of converting to and from DTOs probably isn't that much performance overhead.
If you are using something like EF, and you are not serializing every property, you might even be able to reduce some overhead by projecting your EF query directly on to your DTOs.
This is kind of a dramatic case, but I had (poorly designed) database models with 50+ properties per type. By changing to DTOs that only have the 10-15 properties I cared about, I was able to almost double the performance of a WCF service.
I want to ignore certain properties in a class, but I want to keep the class POCO for many reasons. Hence I do not want to introduce dependency to Json.NET, and do not want to use JsonIgnoreAttribute.
Is there some way to customize the contract resolver to respect some other convention? Eg, properties that are named starting with the word "NonSerialized", for instance, or at least a custom attribute of our own choosing that is internally created (again to eliminate external dependency and keep the domain model as pure as possible).
Also different persistence will need to ignore/respect the same attribute differently, so it would be nice to be able to control what gets serialized at runtime via some kind of fluent api. Is this even possible?
For fields you can use [NonSerializable] attribute from System namespace, to avoid serialization. That way you have no dependency to external library. This doesn't work on properties.
For properties, there is a feature called Conditional Property Serialization. Basically, you implement method that returns boolean and follows naming convention - ShouldSerialize[PropertyName].
public class LoginModel
{
public string UserName { get; set; }
public string Password { get; set; }
public bool RememberMe { get; set; }
public bool ShouldSerializePassword() { return false; }
}
This example would always avoid serializing Password. ShouldSerialize method can contain more complex validation logic, instead of simply returning false.
I was wondering if anyone could point me in the right direction for solving easily the following problem:
Suppose I have a Player class in my .NET code, which looks like this:
public class Player
{
public int Id { get; set; }
public string Name { get; set; }
public long Score { get; set; }
}
I need to serialize this class into a JSON string (using JSON.NET) and use it when POST-ing to a web service. However, the thing is that some of the service's endpoints explicitly prohibit in the JSON string the occurrence of certain members. For instance, a "post score" endpoint would allow all the 3 members to be included in the string, while a "register player" endpoint would only allow Id and Name to be present (otherwise, a bad request is thrown back to the client). Now I know that I could make 2 different classes (e.g. Player and CompetitivePlayer), each containing the required (sub)set of members, however for practical purposes let's suppose I can't do this or want to avoid this (my actual data objects are more complex than the Player class given here simply as an example).
So what I actually want is to tell the JSON serializer at runtime that only certain members of an object must be serialized in situation X, while in situation Y a whole different subset is to be serialized. At first I thought that implementing my own ContractResolver would help, but as it turns out this is only called once per object's type, not per object itself when serializing it. Now the only solution I can think of is to subclass JSONSerializer and have it use a JSONWriter that ignores the properties whose names are included in a list of strings given as argument, perhaps - although I'm not quite sure if this plan can work. Is there a simpler solution for what I'm trying to achieve?
Ok, after looking over the JSON.NET source code I found the exact spot that prevented me from custom serializing those properties: the CamelCasePropertyNamesContractResolver class.
Before writing the original question, I tried to implement custom serialization as described here, at the IContractResolver section. However, instead of inheriting directly from DefaultContractResolver I used CamelCasePropertyNamesContractResolver (I needed camel case here) which, after looking inside its code, sets a "share cache" flag that prevented some of its methods from being called, for performance reasons (which I'm willing to sacrifice in this scenario). Thus, CreateProperties() was called only once per object type, instead of every time my object needed to be serialized. So now my contract resolver class looks like this:
class OptionalPropertiesContractResolver : DefaultContractResolver
{
//only the properties whose names are included in this list will be serialized
IEnumerable<string> _includedProperties;
public OptionalPropertiesContractResolver(IEnumerable<string> includedProperties)
{
_includedProperties = includedProperties;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return (from prop in base.CreateProperties(type, memberSerialization)
where _includedProperties.Contains(prop.PropertyName)
select prop).ToList();
}
protected override string ResolvePropertyName(string propertyName)
{
// lower case the first letter of the passed in name
return ToCamelCase(propertyName);
}
static string ToCamelCase(string s)
{
//camel case implementation
}
}
Just wanted to let others know of this particular situation in case they ever come across it.
I would create contract classes and use AutoMapper to map to them from Player class and serialize them as needed. I.e. 'PlayerContract', 'CompetitivePlayerContract', etc.
It doesn't really matter that those classes only represent contracts to your service.