How to ignore null fields in a customized json converter c# ? - c#

I need to ignore all my null fields in my customized json converter .
My converter inherits from JsonConverter , and i've overrideed the WriteJson method.
I need to configure this setting NullValueHandling.Ignore for my converter ,but i can't see how to make it .
public class CommonJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//i dont need it now
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var maclasse = ( Maclasse ) value ;
writer.WritePropertyNameAndValuer("StringValue",maclasse.id);
writer.WritePropertyNameAndValuer("StringValue",maclasse.nom);
}
}
Thnak you All.

Within an dotnet core mvc application one can call AddJsonOptions() after AddMvc() and supply it with the options to ignore null values within your json. However this effects all of your Json results which go through the request pipeline.
The below code can be added to your startup.cs
public void ConfigureServices(IServiceCollection services)
{
// needs a reference in your `csproj` file to `Microsoft.AspNetCore.Mvc.Formatters.Json`
services.AddJsonOptions(Startup.SetJsonOptions);
}
private static void SetJsonOptions(MvcJsonOptions options)
{
options.SerializerSettings.Converters.Add(new CustomConverter());
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
}
For a normal console app there's something like which goes probably somewhere in your main entrypoint (application setup):
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};

Edited:
You may use NullValueHandling setting over a base class, and inherit other classes from it.
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class BaseClass{}

Related

.NET Core/5 Deserialize with custom NewtonSoft converter but model still binds as null

I am trying to deserialize a subclass in a .NET 5 api project. The model binder is handing back a null even though my custom JSON converter is being called and is returning the correct object.
So that I can have polymorphic deserialization, I'm using the NewtonSoft serializer, added like so:
services
.AddControllers()
.AddNewtonsoftJson(opts =>
{
opts.SerializerSettings.Converters.Insert(0, new RecordJsonConverter());
});
And I have Microsoft.AspNetCore.Mvc.NewtonsoftJson added to the project.
The classes are like:
public class RecordDTO
{
[...]
}
public class ARecordDTO : RecordDTO
{
[...]
}
The controller accepts the base class:
public async override Task<IActionResult> Post([FromBody] RecordDTO dto)
And the JSON Converter:
public class RecordJsonConverter : JsonConverter
{
public override bool CanWrite
{
get
{
return false;
}
}
public override bool CanRead
{
get
{
return true;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
// Only objects of the base type RecordDTO need to be converted by this custom converter.
// If it is already knows which derived class it is, then we
// can just let it use the standard converter.
var recordType = typeof(RecordDTO);
return recordType.IsAssignableFrom(objectType) && !objectType.IsSubclassOf(recordType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
[...]
return target;
}
}
When I post an ARecordDTO object, I see ReadJson on my custom RecordJsonConverter being called and filling out an ARecord object and returning it correctly.
But then we're back inside the controller action, and the dto argument is now null instead of being the ARecordDTO that was just created for binding.
Has anyone else encountered this? What would cause the object returned by the JSON converter to be discarded during binding?
Well, in case anyone else shows up here and was similarly uninformed:
If there are any errors present in the ModelState, then the action argument binds as null (rather than just skipping the single field that had the problem and returning the rest of the object, which is the behavior I would've assumed.)

Customizing response serialization in ASP.NET Core MVC

Is it possible to customize the way types are serialized to the response in ASP.NET Core MVC?
In my particular use case I've got a struct, AccountId, that simply wraps around a Guid:
public readonly struct AccountId
{
public Guid Value { get; }
// ...
}
When I return it from an action method, unsurprisingly, it serializes to the following:
{ "value": "F6556C1D-1E8A-4D25-AB06-E8E244067D04" }
Instead, I'd like to automatically unwrap the Value so it serializes to a plain string:
"F6556C1D-1E8A-4D25-AB06-E8E244067D04"
Can MVC be configured to achieve this?
You can customize the output produced by JSON.NET with a custom converter.
In your case, it would look like this:
[JsonConverter(typeof(AccountIdConverter))]
public readonly struct AccountId
{
public Guid Value { get; }
// ...
}
public class AccountIdConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
=> objectType == typeof(AccountId);
// this converter is only used for serialization, not to deserialize
public override bool CanRead => false;
// implement this if you need to read the string representation to create an AccountId
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 is AccountId accountId))
throw new JsonSerializationException("Expected AccountId object value.");
// custom response
writer.WriteValue(accountId.Value);
}
}
If you prefer not to use the JsonConverter attribute, it's possible to add converters in ConfigureServices (requires Microsoft.AspNetCore.Mvc.Formatters.Json):
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.Converters.Add(new AccountIdConverter());
});
}

Json.NET custom JsonConverter being ignored

I have a generic class, whose children I want to serialize with the value of only one of its attributes.
To this end, I wrote a custom JsonConverter and attached it to the base class with the JsonConverter(Type) Attribute - however, it does not ever seem to be called. For reference, as shown in the example below, I am serializing a List<> of the object using the System.Web.Mvc.Controller.Json() method.
If there is an altogether better way of achieving the same result, I'm absolutely open to suggestions.
Example
View function
public JsonResult SomeView()
{
List<Foo> foos = GetAListOfFoos();
return Json(foos);
}
Custom JsonConverter
class FooConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
System.Diagnostics.Debug.WriteLine("This never seems to be run");
// This probably won't work - I have been unable to test it due to mentioned issues.
serializer.Serialize(writer, (value as FooBase<dynamic, dynamic>).attribute);
}
public override void ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
System.Diagnostics.Debug.WriteLine("This never seems to be run either");
return objectType.IsGenericType
&& objectType.GetGenericTypeDefinition() == typeof(FooBase<,>);
}
}
Foo base class
[JsonConverter(typeof(FooConverter))]
public abstract class FooBase<TBar, TBaz>
where TBar : class
where TBaz : class
{
public TBar attribute;
}
Foo implementation
public class Foo : FooBase<Bar, Baz>
{
// ...
}
Current output
[
{"attribute": { ... } },
{"attribute": { ... } },
{"attribute": { ... } },
...
]
Desired output
[
{ ... },
{ ... },
{ ... },
...
]
What happened to me was, I added the using statement automatically as suggested by Visual Studio. And by mistake added using System.Text.Json.Serialization; instead of using Newtonsoft.Json;
So I was using System.Text.Json.Serialization.JsonConverterAttribute on the target class. Which is (correctly) ignored by Json.Net.
First of all System.Web.Mvc.Controller.Json() doesn't work with Json.NET - it uses JavaScriptSerializer that doesn't know anything about your Json.NET stuff. If you still want to use System.Web.Mvc.Controller.Json() call you should do something like this. Also change WriteJson to this:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, ((dynamic)value).attribute);
}
I think this should make your code work.
Documentation says:
To apply a JsonConverter to the items in a collection use either JsonArrayAttribute, JsonDictionaryAttribute or JsonPropertyAttribute and set the ItemConverterType property to the converter type you want to use.
http://james.newtonking.com/json/help/html/SerializationAttributes.htm
Maybe that will help.

Registering a custom JsonConverter globally in Json.Net

Using Json.Net, I have properties in my objects which need special care in order to serialize / deserialize them. Making a descendant of JsonConverter, I managed to accomplish this successfully. This is the common way of doing this:
public class SomeConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
...
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
...
}
public override bool CanConvert(Type objectType)
{
...
}
}
class SomeClass
{
[JsonProperty, JsonConverter(typeof(SomeConverter))]
public SomeType SomeProperty;
}
//Later on, in code somewhere
SomeClass SomeObject = new SomeClass();
string json = JsonConvert.SerializeObject(SomeObject, new SomeConverter());
My problem with this code is that I need to introduce my custom converter in every serialization / deserialization. In my project there are many cases that I cannot do that. For instance, I'm using other external projects which make use of Json.Net as well and they will be working on my SomeClass instances. But since I don't want to or can't make change in their code, I have no way to introduce my converter.
Is there any way I can register my converter, using some static member perhaps, in Json.Net so no matter where serialization / deserialization happens, my converter is always present?
Yes, this is possible using Json.Net 5.0.5 or later. See JsonConvert.DefaultSettings.
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new SomeConverter() }
};
// Later on...
string json = JsonConvert.SerializeObject(someObject); // this will use SomeConverter
If you're using Web API, you can set up a converter globally like this instead:
var config = GlobalConfiguration.Configuration;
var jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.Converters.Add(new SomeConverter());
Another approach (which wins in priority over the one #Brian mentions above) is to implement a custom contract resolver
JsonFormatter.SerializerSettings.ContractResolver = new CustomContractResolver();
And the implementation is rather straightforward
public class CustomContractResolver : DefaultContractResolver
{
private static readonly JsonConverter _converter = new MyCustomConverter();
private static Type _type = typeof (MyCustomType);
protected override JsonConverter ResolveContractConverter(Type objectType)
{
if (objectType == null || !_type.IsAssignableFrom(objectType)) // alternatively _type == objectType
{
return base.ResolveContractConverter(objectType);
}
return _converter;
}
}
Both methods are valid, this one is just a bigger hammer
This approach from the question ASP.NET Web API Custom JsonConverter is never called works with Web API:
// Add a custom converter for Entities.
foreach (var formatter in GlobalConfiguration.Configuration.Formatters)
{
var jsonFormatter = formatter as JsonMediaTypeFormatter;
if (jsonFormatter == null)
continue;
jsonFormatter.SerializerSettings.Converters.Add(new MyConverter());
}
Just put it somewhere into Global.asax.
The other answers didn't work for me. DefaultSettings has no effect on Web API actions, and the JsonFormatter configuration property does not seem to exist in the .NET framework version I use.

Customizing ASP.NET Web API Output

How can I customize the serialized output of ASP.NET Web API?
Let's say, I want all values in uppercase.
You have access to the JSON.NET serializer settings. With JSON.NET you can overide conversions using converters e.g. this datetime one.
You can also implement your own from inheritting from the abstract JsonConverter. See here for details.
For your example create the converter:
public class UpperCaseStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return reader.Value.ToString();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var outputValue = value as string;
writer.WriteValue(outputValue == null ? null : outputValue.ToUpper());
}
}
And then to register this globally add this config:
Registration example from here
JsonMediaTypeFormatter jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
JsonSerializerSettings jSettings = new Newtonsoft.Json.JsonSerializerSettings();
jSettings.Converters.Add(new UpperCaseStringConverter());
jsonFormatter.SerializerSettings = jSettings;
To add to a single property on a model just add the annotation:
[JsonConverter(typeof(UpperCaseStringConverter))]

Categories