Note: processing of Null value when deserializing Json string
(novice Xiaobai, if there is a mistake or a better writing method, please correct it, thank you!)
Recently, when making an open interface, I encountered a problem that some fields of the API are not required. When the field type is a reference type and the customer connects to the API, because the field is not required, this field is not given or null value is given directly. After the bottom layer of WebApi automatically deserializes, in the data you get, the field that is not given or null value will be equal to null;
Null value is easy to cause exceptions in the system. For example, it is directly assigned to the entity and inserted into the database. If this field in the database is not allowed to be null, an error will be caused. Therefore, it is necessary to convert the null value into an empty string before operating on the database;
For example:
Model class:
public class AddressInputModel { /// <summary> ///Recipient name /// </summary> public string BuyerFullName { get; set; } /// <summary> ///Recipient country /// </summary> public string Country { get; set; } /// <summary> ///Receiving address province / state /// </summary> public string BuyerState { get; set; } /// <summary> ///Receiving address City /// </summary> public string BuyerCity { get; set; } /// <summary> ///Street address 1 /// </summary> public string BuyerStreet1 { get; set; } /// <summary> ///Street address 2 /// </summary> public string BuyerStreet2 { get; set; } /// <summary> ///Address Zip code /// </summary> public string BuyerZipCode { get; set; } /// <summary> ///Contact number /// </summary> public string BuyerPhone { get; set; } /// <summary> ///Receiving mailbox /// </summary> public string BuyerEmail { get; set; } }
Controller layer interface:
[HttpPost] public object Create(AddressInputModel input) { //Parameter validation code &service method call }
The Jason given by the customer is
{ "BuyerFullName": "Name", "Country": "TH", "BuyerState": "A", "BuyerCity": "B", "BuyerStreet1": "C", "BuyerZipCode": "2", "BuyerPhone": null, "BuyerEmail": "" }
Then, input BuyerStreet2,input.BuyerPhone should be equal to null
In fact, there are many ways to solve this problem. The simplest way is to judge one by one, for example:
if(string.IsNullOrWhiteSpace(input.BuyerStreet2)) input.BuyerStreet2 = string.Empty;
But writing like this will lead to ugly code redundancy and no reusability
So I also asked Du Niang to inquire about the solution to this situation. Maybe the keyword I thought was wrong, and I haven't found it yet, so I went to newtonsoft Jason check the official documents, address: https://www.newtonsoft.com/json
Usually use newtonsoft Jason only uses jsonconvert SerializeObject,JsonConvert. The simplest way to deserializeobject is to know less about others. In document browsing, I found newtonsoft JSON supports custom configuration deserialization,
//If NET value is empty when serializing, jason NET will skip writing JSON attribute. If JSON attribute is empty during deserialization, setting field / attribute will be skipped var setting = new JsonSerializerSettings(); setting.NullValueHandling = NullValueHandling.Ignore;
Description address: https://www.newtonsoft.com/json/help/html/SerializationSettings.htm
So I wrote a public method to deal with such business scenarios, and posted the code directly
1. First, define the base class of the model to assign default values:
/// <summary> ///Entity model base class, in order to prevent the new field from reporting an error when it is null /// </summary> public abstract class EntityBase { /// <summary> ///Default time /// </summary> private static readonly DateTime DefaultTime = new DateTime(1900, 1, 1); protected EntityBase() { var props = GetType().GetProperties(); foreach (var prop in props) { if (prop.PropertyType == typeof(string)) { prop.SetValue(this, string.Empty); } if (prop.PropertyType == typeof(DateTime)) { prop.SetValue(this, DefaultTime); } if (prop.PropertyType == typeof(decimal)) { prop.SetValue(this, 0M); } } } }
2. The input model class inherits the base class:
public class AddressInputModel : EntityBase { /// <summary> ///Recipient name /// </summary> public string BuyerFullName { get; set; } /// <summary> ///Recipient country /// </summary> public string Country { get; set; } /// <summary> ///Receiving address province / state /// </summary> public string BuyerState { get; set; } /// <summary> ///Receiving address City /// </summary> public string BuyerCity { get; set; } /// <summary> ///Street address 1 /// </summary> public string BuyerStreet1 { get; set; } /// <summary> ///Street address 2 /// </summary> public string BuyerStreet2 { get; set; } /// <summary> ///Address Zip code /// </summary> public string BuyerZipCode { get; set; } /// <summary> ///Contact number /// </summary> public string BuyerPhone { get; set; } /// <summary> ///Receiving mailbox /// </summary> public string BuyerEmail { get; set; } }
3. Define a method for re assignment
/// <summary> ///Json deserialization ///The default Json deserialization assigns a null value to the field ///Calling this method, null fields will not be assigned /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public T DeserializeNullValueHandling<T>(T model) { var inputStr = JsonConvert.SerializeObject(model); var setting = new JsonSerializerSettings(); setting.NullValueHandling = NullValueHandling.Ignore; model = JsonConvert.DeserializeObject<T>(inputStr, setting); return model; }
4. Method call:
[HttpPost] public object Create(AddressInputModel input) { input = DeserializeNullValueHandling(input); ............. }
The problem is solved, and the method is highly reusable, which can save a lot of code