JsonConvert was too superficial, and finally had a problem

One: Background 1. Storytelling Before starti...
One: Background
2. Seeking solutions
Three: Summary

One: Background

1. Storytelling

Before starting this article, I really want to do a questionnaire to find out how many people are like me. My knowledge of JsonConvert is limited to the methods of SerilizeObject and DeserializeObject (), so that I can work together and not be alone._Perhaps these two methods can basically solve 80% of the scenarios in my work. That's true for me, but as the coding continues, you'll eventually encounter the remaining 20% of the scenarios, so....

My scenario is like this: When I wrote business code some time ago, I had a Model with a custom client algorithm type that had customer base and Report ing statistics for that algorithm type, and used HashSet to record the CustomerID collection for that type. For the sake of narration, I simplified the Model as follows:

class CustomerAlgorithmModel { public string DisplayName { get; set; } public int CustomerType { get; set; } public ReprotModel Report { get; set; } public HashSet<int> CustomerIDHash { get; set; } } class ReprotModel { public int TotalCustomerCount { get; set; } public int TotalTradeCount { get; set; } }

That's interesting. I personally have a diary hobby, thinking that there won't be any evidence-free situations in the future, and then using them as a matter of course JsonConvert.SerializeObject And then there was a problem. The log was sent to ElasticSearch and it couldn't be found through Kibana. Why?After reading the Model above, I think you can also guess the reason that JSON is too big. There are hundreds of thousands of sprinklers in the rogue CustomerIDHash. Now all of them are exported to json. Is this size small?Would you like me to write a code to have a look?

static void Main(string[] args) { var algorithModel = new CustomerAlgorithmModel() { CustomerType = 1, DisplayName = "🐮👃", Report = new ReprotModel() { TotalCustomerCount = 1000, TotalTradeCount = 50 }, CustomerIDHash = new HashSet<int>(Enumerable.Range(1, 500000)) }; var json = JsonConvert.SerializeObject(algorithModel); File.WriteAllText("1.txt", json, Encoding.UTF8); Console.WriteLine("Write complete!"); }

You can see that only one json is 3.3M. After several dozens of such records are retrieved in kibana, the browser will die of the card. In fact, CustomerIDHash is a field that I have nothing to do with, even if it is saved, so the demand comes and how to block out CustomerIDHash.

2. Seeking solutions

1. Use JsonIgnore

If you have a problem, go online and someone will tell you that you can use JsonIgnoreAttribute to ignore the feature. If you have this feature, continue running the program.

[Newtonsoft.Json.JsonIgnore] public HashSet<int> CustomerIDHash { get; set; }

Great, it's done at last, but calm down and think about it. It always feels a little uncomfortable. Why do you say that once you give this CustomerIDHash a JsonIgnore, it means it disappears from the world of JsonConvet, no matter who uses it?But this is not my original intention. My original intention is just to kick CustomerIDHash while logging. Don't interfere with other scenarios. Now it will dig for yourself, bury unpredictable bug s in others, and I think you should understand what I mean and continue to look for the next option.

2. Use a custom JsonConverter

Really, Newtonsoft is so powerful that I want to write a topic to make up for my knowledge blind spot. In fact, in this scenario, I don't want to block out HashSet <int>. Newtonsoft has a custom processing class for a specific type, so I'll write a paragraph next:

/// <summary> ///Customize a transformation class for HashSet<int> /// </summary> public class HashSetConverter : Newtonsoft.Json.JsonConverter<HashSet<int>> { public override HashSet<int> ReadJson(JsonReader reader, Type objectType, HashSet<int> existingValue, bool hasExistingValue, JsonSerializer serializer) { return existingValue; } public override void WriteJson(JsonWriter writer, HashSet<int> value, JsonSerializer serializer) { writer.WriteNull(); } }

It's that simple, then you can specify a custom HashSetConverter when SerilizeObject, and then run the program to see it.

var json = JsonConvert.SerializeObject(algorithModel, Formatting.Indented, new HashSetConverter());

From the picture, it looks like it's solved, but I suddenly find myself getting into a tight corner. If I have another TopNCustomerIDHash from a top-quality customer base in my entity, but because there are fewer CustomerIDs, I want to keep it in Json, and then the same CustomerIDHash I kicked out will keep it CustomerIDHash.Length Ha-ha, get things done, then what can I do next?

  • Modify Model Entity
class CustomerAlgorithmModel { public HashSet<int> CustomerIDHash { get; set; } // topN Quality Customer Group public HashSet<int> TopNCustomerIDHash { get; set; } }
  • HashSetConverter adds a logical authenticator whether it is a reserved field
public override void WriteJson(JsonWriter writer, HashSet<int> value, JsonSerializer serializer) { if (writer.Path == "TopNCustomerIDHash") { writer.WriteStartArray(); foreach (var item in value) { writer.WriteValue(item); } writer.WriteEndArray(); } else { writer.WriteValue(value.Count); } }
  • Last assign TopNCustomerIDHash
var algorithModel = new CustomerAlgorithmModel() { CustomerType = 1, DisplayName = "🐮👃", Report = new ReprotModel() { TotalCustomerCount = 1000, TotalTradeCount = 50 }, CustomerIDHash = new HashSet<int>(Enumerable.Range(1, 500000)), TopNCustomerIDHash = new HashSet<int>(Enumerable.Range(1, 10)), };

Once you have all three pieces, you can run the program as follows:

The seemingly tricky problem is solved. Now that tricky tricks are definitely despicable, like ReportModel here, which I don't need, CustomerType which I don't need, I just need to look at DisplayName and Total CustomerCount fields. What can I do about that?

3. Use anonymous types

It's true that many times you log to keep track of the fields you care about in Model, so it's really unnecessary to mix in extra fields. You can use anonymity to solve this, so I'll write a code:

var json = JsonConvert.SerializeObject(new { algorithModel.DisplayName, algorithModel.Report.TotalCustomerCount }, Formatting.Indented);

Three: Summary

Although several rounds have been blocked, it is also found that there are a lot of unexplored features in Newtonsoft that really need to be studied. The source code has been laid down, and now we are ready to do a series of dissections. It is worth mentioning that. Net already has its own.System.Text.Json.JsonSerializer Class, at present the function is not too rich, simple to use or can be used, so I hope this article will help you.

If you have more questions to interact with me, scan below to enter ~

18 June 2020, 21:11 | Views: 5791

Add new comment

For adding a comment, please log in
or create account

0 comments