Getting SerializeObject to use JsonProperty "name" defined inside interface - json.net

When calling "JsonConvert.SerializeObject" I am passing in an object that implements an interface. It is the interface that defines the JsonProperty attributes to set the desired JSON object property name. However when I examine the JSON object that is produced it is using the actual .NET property name, rather than JsonPropertyAttribute value. This leads me to believe it is only reflecting over the implementation of the interface to find the JsonProperty attributes, rather than the interface itself. I have verified that if I place the JsonProperty attributes on the implementing class then everything works as expected, but this is not the desired behaviour. Is there any way to make JSON.NET pick up the JsonPropertyAttributes defined upon the interface as well as (or instead of) the interface.
public interface ISpecifyDataPageToGet
{
[JsonProperty("offset")]
int PageNumber { get; }
[JsonProperty("limit")]
int PageSize { get; }
}
public class PageInfo : ISpecifyDataPageToGet
{
public PageInfo(int pageNumber, int pageSize)
{
this.PageNumber = pageNumber;
this.PageSize = pageSize;
}
// I don't want to have to define JsonProperty attribute here
public int PageNumber { get; private set; }
// Or here
public int PageSize { get; private set; }
}
public void MakeCall(ISpecifyDataPageToGet requestMessage)
{
// I'm passing instance of interface in here, but it still only picks up
// attributes defined on class implementing interface.
JsonConvert.SerializeObject(requestMessage, Formatting.None, new JsonSerializerSettings());
...
...
}
UPDATE: Reported on Codeplex project site

This has now been fixed in the Json.NET codebase by James and is working.
See the codeplex issue report as well as the Json.NET 4.0 Release 3 release notes:
New feature - JsonObject and JsonProperty attributes can now be placed on an interface and used when serializing implementing objects.

Related

Ignoring implemented interface property for all implementations [duplicate]

I have an interface with a property like this:
public interface IFoo {
// ...
[JsonIgnore]
string SecretProperty { get; }
// ...
}
I want the SecretProperty to be ignored when serializing all implementing classes. But it seems I have to define the JsonIgnore attribute on every implementation of the property. Is there a way to achieve this without having to add the JsonIgnore attribute to every implementation? I didn't find any serializer setting which helped me.
After a bit of searching, I found this question:
How to inherit the attribute from interface to object when serializing it using JSON.NET
I took the code by Jeff Sternal and added JsonIgnoreAttribute detection, so it looks like this:
class InterfaceContractResolver : DefaultContractResolver
{
public InterfaceContractResolver() : this(false) { }
public InterfaceContractResolver(bool shareCache) : base(shareCache) { }
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
var interfaces = member.DeclaringType.GetInterfaces();
foreach (var #interface in interfaces)
{
foreach (var interfaceProperty in #interface.GetProperties())
{
// This is weak: among other things, an implementation
// may be deliberately hiding an interface member
if (interfaceProperty.Name == member.Name && interfaceProperty.MemberType == member.MemberType)
{
if (interfaceProperty.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Any())
{
property.Ignored = true;
return property;
}
if (interfaceProperty.GetCustomAttributes(typeof(JsonPropertyAttribute), true).Any())
{
property.Ignored = false;
return property;
}
}
}
}
return property;
}
}
Using this InterfaceContractResolver in my JsonSerializerSettings, all properties which have a JsonIgnoreAttribute in any interface are ignored, too, even if they have a JsonPropertyAttribute (due to the order of the inner if blocks).
In more recent versions of Json.NET, applying [JsonIgnore] to interface properties now just works and successfully prevents them from being serialized for all implementing types, as long as the property is declared on the same class where the interface is declared. A custom contract resolver is no longer required.
For instance, if we define the following types:
public interface IFoo
{
[JsonIgnore]
string SecretProperty { get; set; }
string Include { get; set; }
}
public class Foo : IFoo
{
public string SecretProperty { get; set; }
public string Include { get; set; }
}
Then the following test passes in Json.NET 11 and 12 (and probably earlier versions also):
var root = new Foo
{
SecretProperty = "Ignore Me",
Include = "Include Me",
};
var json = JsonConvert.SerializeObject(root);
Assert.IsTrue(json == "{\"Include\":\"Include Me\"}");// Passes
Demo fiddles here and here.
I believe this was added in Json.NET 4.0.3 despite the fact that JsonIgnore was not mentioned explicitly in the release notes:
New feature - JsonObject and JsonProperty attributes can now be placed on an interface and used when serializing implementing objects.
(The implementation can be found in JsonTypeReflector.GetAttribute<T>(MemberInfo memberInfo).)
However, as noted by Vitaly, this does not work when the property is inherited from a base class of the class where the interface is declared. Demo fiddle here.
I have found it's simplest to create a DTO of only the properties I want and serialize that object to JSON. it creates many small, context specific objects but managing the code base is much easier and I don't have to think about what I'm serializing vs what I'm ignoring.
You should add [DataContract] in front of the class name.
It changes the default from including all properties, to including only explicitly marked properties. After that, add '[DataMember]' in front of each property you want to include in the JSON output.

Blazor get nested components by Reflection

I'm actually working on form validation in Blazor project (0.8.0).
I have created a component called InputValidation. This component receive many parameters to test if a property value is correct according a condition we can set up.
#using System.Linq.Expressions;
#typeparam TItem
#if (!Valid)
{
<span id="#(Id)_validation" class="form-text text-danger">#Message</span>
}
#functions {
[Parameter]
string Id { get; set; }
[Parameter]
TItem Property { get; set; }
[Parameter]
Expression<Func<TItem, bool>> On { get; set; }
[Parameter]
string Message { get; set; }
[Parameter]
bool ActiveOnLoad { get; set; } = true;
internal bool Valid { get; set; }
bool Activated;
protected async override Task OnInitAsync()
{
Activated = ActiveOnLoad;
}
protected async override Task OnAfterRenderAsync()
{
Activated = true;
}
protected async override Task OnParametersSetAsync()
{
Valid = !On.Compile().Invoke(Property);
}
}
You can implement it on your parent component like this :
<InputValidation Id="#nameof(ViewModel.UrlInput)" Property="#ViewModel.UrlInput" On="#(x => string.IsNullOrEmpty(x))" Message="Url is empty" ActiveOnLoad="#false"/>
I have coded a class that verifies that all InputValidation components have the property Valid at true.
#if (ViewModel.IsValid(this))
this represents the parent component.
The problem is... it's not working !
Here is the code of the validator :
public static class ModelValidator
{
public static bool IsValid<T, V>(this T viewmodel, V component) where T : IViewModel where V : ComponentBase
=> component.GetType().GetFields().OfType<InputValidation<T>>().All(x => x.Valid);
}
It's not working, I know, but even if we use Reflection (GetProperties, GetFields, GetMembers), it won't return any of the InputValidation members of the parent component.
My question is : is there a way to get all child components by using Reflection ? If yes, how to do it ?
I know that Blazor is still on early stage and I hope it will be released soon because it's a very pleasant technology !
Thank you for your responses !
You don't need reflection here (the InputValidation component is not a field in the parent, it is a component that will be rendered by the RenderTree).
You can capture a reference to each InputValidation component using the ref attribute.
<InputValidation ref="#InputValidationRef" Id="#nameof(ViewModel.UrlInput)" Property="#ViewModel.UrlInput" On="#(x => string.IsNullOrEmpty(x))" Message="Url is empty" ActiveOnLoad="#false"/>
Normally this ref "InputValidationRef" would be a field, but you can, instead use a property with a custom setter to build a list (or whatever collection you like)
List<InputValidation> InputValidations = new List<InputValidation>();
InputValidation InputValidationRef { set => InputValidations.Add(value); }
So, each InputValidation will now be captured as a reference and the Property InputValidationRef will be set for each one, which will, in turn, store all the references in the collection "InputValidations".
Now, you have a collection, you can test against
InputValidations.All(iv => iv.Valid)
Note: the collection is only populated after the component/page is rendered, so during the initial page load the collection of references is empty until the OnAfterRender/OnAfterRenderAsync method is called.

Why do class fields get defaulted at deserialization?

Hello i am having a class that is defined in a .Net Standard assembly.
Now i have a reference to that assembly from my .Net Core project.
When i try to deserialize the class in my .Net Core my class fields are default.
By default i mean value types get all inner values default and class fields are null.
In my example if Val is an int it would have its value 0 after deserialization whereas would it have been a class it would be null.
.NET Standard class
public class Matrix
{
public int Val { get; set; }
public Matrix(int set) //value is default
{
this.Val = set;
}
}
.NET Core
static void Main(string[] args)
{
Matrix matr = new Matrix(3);
var str=JsonConvert.SerializeObject(matr);
var bytes=Encoding.Utf8.GetBytes(str);
var str = Encoding.UTF8.GetString(bytes); //string looks ok !
var deser = JsonConvert.DeserializeObject<Matrix>(str);
}
Please note that my class uses a parameter in the constructor.Could this be the problem ? If my parameter constructor is indeed the problem ...how do you manage to serialize an object that needs to perform some logic in its constructor via his parameters ?
Code which you provided works good. After deserialization in deser.Val you will see 3. But if you will change public int Val { get; private set; } or public int Val { get; } you will have a default value. For reference type it will be NULL for value type it depends.
Maybe you can provide more information and screenshot of problem?

Converting Entity Framework object to JSON (without object graph)

Suppose I have a object structure like this
Library 1 ---- 1+ Book 1 ---- 1+ Page
I want to serialize a json object of a book with an array of page objects.
Using JSON.net serializer, I can get this to serialize without getting a circular reference, but the JSON still includes all of the properties of the book in each page, which includes data about the library...which can have data on other books which is a ton of noise.
From the answer from this question - Serialize Entity Framework objects into JSON, I know that I can do generics, but is this really the only way? This just seems like a ton of extra work. Especially if for a Json result that is Book with and array of page objects in it.
I am using Entity Framework 4.3.1 and Json.net 4.0.30319...
You should look at the serialization attributes.
[JsonObject(MemberSerialization.OptIn)]
public class Page
{
[JsonProperty]
public string Text { get; set; }
// not serialized because mode is opt-in
public Book Book { get; set; }
}
Original answer
The aforementioned way should be prefered in most of the cases, but there are some where it is not enough.
There are two ways of doing it.
You can implement a JsonConverter, and override the WriteJson method to write only the properties you want.
class BookConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Book);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value.GetType() == typeof(T2))
{
JObject obj = new JObject();
Book b = value as Book;
obj["titre"] = b.Name;
obj["pages"] = b.Pages;
// This line can also be
// obj.WriteTo(writer, this);
// if you also need change the way pages are serialized.
obj.WriteTo(writer, null);
}
else
{
throw new NotImplementedException();
}
}
}
You can call it like that :
string result = JsonConvert.SerializeObject(
book,
new JsonSerializerSettings
{
Converters = new JsonConverter[] { new BookConverter() }
});
You can also create a JsonBook class, and serialize it.
class JsonBook{
public JsonBook(Book b){/*...*/}
public List<Pages> l;
public string title;
// No reference to Library.
}

serializing/deserializing derived objects using JSON.NET without using JsonProperty?

I'm using the NewtonSoft JSON.NET library for serializing the following class where DTOBase can hold derived instances.
public class Command
{
public DTOBase CommandDTO { get; set; }
}
Per this article you need to include the JsonProperty attribute so that the derived instances get deserialized properly
public class Command
{
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
public DTOBase CommandDTO { get; set; }
}
The question is whether there is any other way besides using an attribute to get the same result? I would prefer to not be coupled to the NewtonSoft library and json serialization in particular at the class level. Is there a way to specify some settings on the Serialize/Deserialize methods of the library at all to get the same result?
The TypeNameHandling property can be set on JsonSerializerSettings when you call JsonConvert.SerializeObject(value, settings).
If you only want the name included for derived objects set TypeNameHandling to TypeNameHandling.Auto.

Resources