'Programming/etc'에 해당되는 글 4건
- 2018.03.30
- 2018.03.30
- 2018.03.30
- 2018.03.30
Copyright
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 다섯번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents).
Content
Outline
Manual Serialization/Deserialization
Fragments
Populate Objects
Merge Array Handling
Attributes
Memory Usage
Serializing and deserializing manually
Json.NET is extremely fast but it relies on reflection so if speed is key, serialize/deserialize manually using JsonTextReader/Writer. (Avoids using Reflection, Less memory usage, Fastest way of reading and writing JSON)
Writing
var builder = new StringBuilder(); //Never to use strings(immutable) if you're going to be changing them too much
StringWriter writer = new StringWriter(builder);
using (var jsonWriter = new JsonWriter(writer))
{
jsonWriter.Formatting = Formatting.Indented;
jsonWriter.WriteStartArray();
for (int i =0; i < numberOfView; i++)
{
jsonWriter.WriteStartObject();
....
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
Reading
var reader = new JsonTextReader(new StringReader()jsonStrings);
while(reader.Read())
{
if(reader.Value != null)
{
if(reader.TokenType == JsonToken.String....)
}
}
JSON Fragments (Deserialize only what you need!)
Large JSON documents or objects may take a lot of time serializing and deserializing. However, in certain scenarios you may have a very big JSON object, but you're only interested in a specific subsection of your data. With Json.NET it is possible to extract and work with a fragment of a JSON object using Linq.
Json.NET has the capability of extracting a subsection of a big JSON text, allowing you to deserialize only that small section. This is very beneficial both in terms of performance and simplicity because you're not deserializing the entire object, that's the first one, and second, it makes the code much more readable.
List<UserInteraction> userLogs = GetTestData(); //Generate huge data
string bigLog = JsonConvert.SerializeObject(userLogs);
JArray logs = JArray.Parse(bigLog); //bigLog is huge json string
List<CourseView> courses = new List<CourseView>(); //CourseView is an objects which we are interest in bigLog
foreach (JObject logEntry in logs)
{
courses.Add(logEntry["courseView"].ToObject<CourseView>()); //Using Linq to json to extract CourseView
}
Remember that readable and simple code is much better than code that's complex and difficult to read. By using JSON fragments it makes your code much more readable and easier to maintain.
PopulateObject
With JSON fragments you're able to extract and work with sections of a large JSON object. PopulateObject is the opposite functionality where you're able to write specific values to a large JSON object.
List<UserInteraction> userLogs = GetTestData(); //Generate huge data
string jsonReviewed = "{'reviewed' : true. 'processedBy' : [''ReviewerProcess'], 'reviewedDate : '" + DateTime.Now.ToUniversalTime().ToString("yyyy-mm-ddTHH:mm:ssK") + @"' }";
foreach(UserInteraction log in userLogs)
{
JsonConvert.PopulateObject(jsonReviewed, log);
}
JSON Merge (Merge JSON Objects) (Skip)
There are cases where you have two JSON objects that you need to merge. For example, we might have a large JSON array where each item might need to read an object from a different data source. This can be a complex operation or not. Json.NET provides the merge functionality from one object to another. Logic is very simple. Name value pairs are copied across, skipping nulls if the existing property is not null and you can even specify how to handle arrays via merge array handling. You have four options for arrays, concat, union, replace, and merge.
Attributes for performance (Serialize and Deserialize Only What You Need) (Skip)
JsonIgnore Attributes on class
Optimizing Memory Usage (Avoid Large Object Heap, Use Streams)
Memory usage is critical to performance, but more than that, it can lead to exceptions. Any object over 85 kilobytes in size goes directly to a large object heap and this can mean a few out of memory exception. This number(85) is a threshold that was obtained after multiple tests by Microsoft. The problem with the large object heap as opposed to heap generations 0, 1, and 2, is that it's not compacted and even though there are some improvements in .NET Framework 4.5 and up, the promise that your memory usage may grow and grow until your application can be in trouble. Json.NET helps you improve memory usage by using streams instead of loading entire strings into memory. It achieves this by reading from a client in a synchronous way, reading one piece at a time a large JSON.
using (StreamReader streamReader = new StreamReader(stream))
{
using (JsonReader jsonReader = new JsonTextReader(streamReader))
{
var jsonSerializer = new JsonSerializer();
List<UserInteraction> logsStream = jsonSerializer.Deserialize<List<UserInteraction>>(jsonReader);
//The key here is that we're loading the text in an asynchronous way
}
}
출처
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 다섯번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.
(Json.NET) Custom Serialization (0) | 2018.03.30 |
---|---|
(Json.NET) Settings & Attributes (0) | 2018.03.30 |
(Json.NET) Serialization Fundamentals (0) | 2018.03.30 |
Copyright
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 네번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents).
Content
Outline
Conditional Serialization
Custom JsonConverter
Callbacks
ITraceWriter for logging and debugging
Conditional Serialization
Conditional serialization may not be the case that you want to serialize an object as is, but instead only serialize based on specific conditions and this is what conditional serialization is for.
You can specify conditions in your code using ShouldSerialize which works by creating a function with a bool return type that has the name ShouldSerialize and the property name.
public class AuthorSS
{
public string Name { get; set; }
public bool IsActive { get; set; }
public string[] Courses { get; set; }
public bool ShouldSerializeCourses()
{
//If Author IsActive then Courses will be serialized
return IsActive;
}
}
target class(AuthorSS) to serialize has to have boolean member(IsActive) with bool ShouldSerialize"TargetMemberName"() method
Before Serializing the class, If IsActive set to true. then target member will be serialized. if not target member is not serialized.
Or you can use IContractResolver
The IContractResolver is very useful when you use classes that you have not defined or you do not want to add the ShouldSerialize methods to those classes, or if it's a third party code you can't modify the code or you decide you prefer to avoid placing attributes.
public class SelectiveContractResolver : DefaultContractResolver
{
private IList<string> propertiesList = null;
public SelectiveContractResolver(IList<string> propertiesToSerialize)
{
propertiesList = propertiesToSerialize; //Get strings of property names which want to serialize
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
return properties.Where(p => propertiesList.Contains(p.PropertyName)).ToList();
}
}
...
var contractResolver = new SelectiveContractResolver(propertiesToSerialize); //propertiesToSerialize is list of property name
string jsonstring = JsonConvert.SerializeObject(author, new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ContractResolver = contractResolver
});
Custom JsonConverter
Json.NET provides JsonConvert as an easy to use wrapper over the JsonSerializer class to allow quick and easy conversion between .NET and JSON text. however, it may be possible that you want to extend or customize the serialization and deserialization process with a custom JSON converter based on the JsonConvert to fit exactly to your needs by overriding methods as required.
The JsonConverter class is the class responsible of converting from an object to JSON text and vice versa. It is extremely useful and easy to use, but what happens if you want to have finer control over the serialization and deserialization process? Well, you can create your own CustomJsonConverter class.
1. Create your own converter
2. Derived from JsonConvert
3. Override methods as needed
4. Set JsonSerializerSettings.Converters as a List<JsonConverter> with own custom converter
Callbacks
Serialization callbacks are methods that are raised before and after the serialization and deserialization process. They let you manipulate the objects or perform any operation before and after. A good example for using serialization callbacks is if you want it to have a functionality that logs the serialization time. The methods are OnSerializing and OnDeserializing, which are called before the conversion takes placed and OnSerialized and OnDeserialized which are called when the process completes.
public class Author
{
private Stopwatch timer = new Stopwatch();
public int age;
public string name { get; set; }
...
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
timer.Reset(); timer.Start();
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
timer.Stop();
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
timer.Reset(); timer.Start();
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
timer.Stop();
}
}
Logging and Debugging with ITraceWriter (Skip)
Debugging the serializer is not a common scenario, as in most cases everything just works, but what if you wanted to debug or if you want to understand exactly the serialization process, or you're running into an error and can't figure out what is the cause? Then you need the ITraceWriter. ITraceWriter is the method used for debugging the serialization process. Json.NET comes with a MemoryTraceWriter which logs all debugging information in memory. It's quick and easy to use or you can create your own custom TraceWriter.
출처
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 네번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.
(Json.NET) Performance Tips (0) | 2018.03.30 |
---|---|
(Json.NET) Settings & Attributes (0) | 2018.03.30 |
(Json.NET) Serialization Fundamentals (0) | 2018.03.30 |
Copyright
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 세번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents).
Content
Outline
Settings and Attributes
Settings
Attributes
Settings and Attributes
A setting is a user preference that is supplied during the conversion process. It can be specified as a property on the JsonSerializer class or using the JsonSerializer settings on JsonConvert.
An attribute is a declarative tag that is supplied on classes, properties, and more, that is taking into account during the serialization and deserialization process.
Settings
DateFormatHandling
With DateFormatHandling you tell Json.NET how to handle dates. e.g., the ISO date format or the Microsoft date format.
MissingMemberHandling
With MissingMemberHandling you tell Json.NET what to do when the JSON contains a member that is not defined. You can ignore or you can raise an error.
ReferenceLoopHandling
With ReferenceLoopHandling you tell Json.NET what to do when there is an object that references itself. You can ignore, raise an error, or serialize.
NullValueHandling
With NullValueHandling you tell Json.NET what to do when it runs into null values, both on serialization and deserialization.
DefaultValueHandling
With DefaultValueHandling you specify how to use the default values that are set using the DefaultValue attribute. [DefaultValue(3)] int defaultAgeIsThree;
Can ignore property which was set to default value when Serializing
Can populate default value to a property when Deserializing
ObjectCreationHandling
With ObjectCreationHandling you tell Json.NET how to handle objects that are created during the deserialization. By default, Json.NET sets values and appends values to existing collections. This might be the desired behavior in some cases, but in others it might not. You can specify if you want to reuse or replace the objects or collections that are set. This is particularly useful when you have constructors that populate values before the deserialization process.
TypeNameHandling
TypeNameHandling is very important because it tells Json.NET to preserve type information that's very useful when you're serializing and deserializing.
TypeNameAssemblyFormat
With TypeNameAssembly you tell Json.NET how you want type names written during the serialization process.
Binder
With Binder you tell Json.NET how to resolve type names to .NET types.
MetadataPropertyHandling
ConstructorHandling
ConstructorHandling is a way of telling Json.NET to specify which constructor to use, even if it's not a public constructor.
Converters
Converters is a way of telling Json.NET which converters you want to use during the deserialization and serialization process.
ContractResolver
With ContractResolver you specify to Json.NET how you want to control the serialization and deserialization without having attributes in your classes.
TraceWriter
TraceWriter is used for logging and debugging, and with Error you specify to Json.NET how is it that you want to handle errors.
Error
With Error you specify to Json.NET how is it that you want to handle errors.
Attributes
Attributes are declarative tags that are placed on classes, properties, and more and they provide additional information to Json.NET on how to do the serialization and deserialization process.
in Json.NET
JsonObjectAttribute
The JsonObjectAttribute is placed on classes to tell Json.NET how to serialize as a JsonObject.
JsonArrayAttribute
The JsonArrayAttribute is placed in collections and it tells Json.NET to serialize as a JsonArray.
JsonDictionaryAttribute
The JsonDictionaryAttribute is placed in dictionaries and it tells Json.NET how they should be serialized as JSON objects.
JsonPropertyAttribute
The JsonPropertyAttribute is used in fields and properties to control how they're serialized as properties in JsonObjects.
+ [JsonProperty(PropertyName = "AuthorName", Required = Required.Always, Order = 2)]
public string name { get; set; }
If Json.NET try to serialize the class without value of above property(name) throws an error - Useful when a specific member to be set before serialize.
And Serialized PropertyName set to "AuthorName". Setting PropertyName can be implicit like below "WhereInTheWorld"
+ [JsonProperty("WhereInTheWorld", DefaultValueHandling = DefaultValueHandling.Ignore)]
[DefaultValue("Costa Rica")]
public string location { get; set; }
if location property is set to "Costa Rica" just as same as DefaultValue above, then DefaultValueHandling.Ignore Attribute makes Json.NET not to serialize location property at all. It's useful to save some bytes.
JsonIgnoreAttribute
JsonIgnore tells Json.NET to ignore and do not include a property during serialization.
MemberSerialization OptIn, OptOut, Fields
[JsonObject(MemberSerialization = MemberSerialization.OptIn)] //Only JsonProperty attached member is serialized
[JsonObject(MemberSerialization = MemberSerialization.OptOut)] //Just looking for which ones to ignore
[JsonObject(MemberSerialization = MemberSerialization.Field)] //Add some string on autogenerated field
public class AuthorJsonObjectOptIn
{
private string privateField;
[JsonProperty] private string privateFieldWithAttribute; //private field also serialized
[JsonProperty] public string name { get; set; } //Only this two member get serialize
public string[] courses { get; set; }
public DateTime since;
[NonSerialized] public bool happy; //Ignore this two member and serialize else including private member
[JsonIgnoreAttribute] public object issues { get; set; }
}
JsonConverterAttribute
The JsonConverter can be placed on classes, fields, or properties and it tells Json.NET to use a specific JsonConverter during the serialization process.
e.g. [JsonConverter(typeof(StringEnumConverter))] public Relationship relationship { get; set; } //Relationship is of type enum
if no Converter here, Json.NET serialize relationship(of type enum) as string like 1 or 2...
But with this converter it uses text in enum
JsonExtensionDataAttribute
The JsonExtensionDataAttribute is placed on a collection field or property and it tells Json.NET to use this as a catchall bucket to include any properties that do not have any matching class members.
JsonConstructorAttribute
The JsonConstructor attribute is placed on a constructor and it tells Json.NET to use this constructor during deserialization.
in Standard .NET Attributes
SerializableAttribute
The SerializableAttribute is used to indicate that a class can be serialized.
DataContractAttribute
The DataContractAttribute is used to specify that the type or class implements a data contract and is serializable.
DataMemberAttribute
The DataMemberAttribute which when applied to a member of a type specifies that the member is part of a data contract.
NonSerializedAttribute
NonSerializedAttribute which tells Json.NET that a particular field should not be serialized.
출처
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 세번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.
(Json.NET) Performance Tips (0) | 2018.03.30 |
---|---|
(Json.NET) Custom Serialization (0) | 2018.03.30 |
(Json.NET) Serialization Fundamentals (0) | 2018.03.30 |
Copyright
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 두번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents).
Content
Outline
Serialization And Deserialization
JsonSerializer and JsonConvert
JsonTextReader and JsonTextWriter
Dates in JSON
Error Handling
Serialization And Deserialization
Serialization and deserialization is the main functionality of Json.NET. Serialization and deserialization involves taking a data structure or object and converting it back and forth between JSON text and .NET objects. A .NET object when serialized can be stored as a stream of bytes of file or in memory and later it can be used to recreate the original object. You have to be careful though. In some cases there are private implementation details that are not available when deserializing or serializing, so you need to review the recreated object to determine if there is any information missing. In the serialization and deserialization process, you map property names and copy their values using the main JSON serializer class with the support of JsonReader and JsonWriter.
JsonSerializer and JsonConvert
The JsonSerializer class is a straightforward way of converting between JSON text and .NET objects. It provides a great deal of control and customization, being able to read and write directly to streams via JSON text reader and JSON text writer.
Simply use the serialize and deserialize methods.
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize()...
And it gets even better. Json.NET comes with a very easy to use wrapper over JsonSerializer called JsonConvert that makes the serialization process that easy for most scenarios.
Simply use the SerializeObject and DeserializeObject methods.
string author = JsonConvert.SerializeObject(AuthorObject);
DeserializeObject<Author>(author);
Caution : There are many classes in Json.NET that provide async methods. Stay away from them as they are now marked as obsolete.
Demo note
1. Formatting.Indented setting on JsonConvert.SerializeObject method
2. PreserveReferenceHandling.Objects setting on JsonConvert.SerializeObject method
Whenever you're using Json.NET to serialize a class, by default it will serialize the object by value. This means that is if you have a class that has two references to another class, it will basically create two copies of the values. This might not be a problem if you're just serializing the class, but what happens if you want to deserialize, this is converted back again from JSON text to a .NET object and you want to have two references to the same object instead of two different objects and this is where preserving object references comes into play.
자기자신을 포함하는 리스트를 갖는 class를 Serialize할 때
PreserveReferenceHandling.Objects(want to preserve object) setting on JsonConvert.SerializeObject method
==> preserve reference to the objects, so when deserializing, Deserializer will not create duplicate classes.
3. Dynamic, ExpandoObject
dynamic varName = new ExpandoObejct(); //ExpandoObject class == members can be Dynamically added and removed at runtime.
... add members to varName...
then just pass varName to JsonConvert.SerializeObject method, and Deserialize it with dynamic
4. JsonConvert.DesrializeObject<Dictionary<string, string>>(...)
5. AnonymousType
JsonConvert.DeserializeAnonymousType method
JsonTextReader and JsonTextWriter
JsonConvert is useful but let's learn a little bit more about the control and performance that Json.NET provides to you via the JsonSerializer class. Let's start first with JsonReader and JsonWriter.
The JsonTextReader is for reading JSON. It's non-cache and forward only and it's used for large objects and files.
The JsonTextWriter which is used for creating JSON. It's also non-cached, forward only, and allows you to have a lot more control in improvements in performance.
Demo note
1. Using the JsonSerializer with the aid of a StreamWriter
serializer = new JsonSerializer();
serializer.NullValueHandling = NullValueHandling.Ignore; //setting to ignore null value when serializing
serialier.Formatting = Formatting.Indented; //indenting make file bigger
using (StreamWriter sw = new StreamWriter(@"..\..\jsonfilename.json"))
{
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, author); //author is an instance to serialize
}
}
2. JsonConvert and ultimately the JsonSerializer class use reflection to convert from JsonText to .NET classes. Even though Json.NET is very fast by using reflection it makes it a little bit slower than it can actually be and thus we have the JsonTextReader, which does not use reflection and provides the fastest way of reading JSON text.
JsonTextReader jsonReader = new JsonTextReader(new StringReader(jsonText)); //jsonText is a string
while(jsonReader.Read()) //iterate strings in jsonText
{
if (jsonReader.Value != null) Console.WriteLine("Token: {0}, Value: {1}", jsonReader.TokenType, jsonReader.Value);
else ....skip...
}
TokenType : Start/EndObject, PropertyName, Date, Boolean, String, Integer, Start/EndArray... etc
The JsonTextWriter basically iterated over the entire jsonText, retrieving one token at a time.
3. Write jsonText in a manual way for performance and control
StringWriter se = new StringWriter();
JsonTextWriter writer = new JsonTextWriter(sw);
writer.Formatting = Formatting.Indented; //at the beginning!
writer.WriterStartObject();
wirter.WritePropertyName("name");
writer.WriteValue("EMPister");
writer.WritePropertyName("courses");
writer.WriteStartArray();
writer.WriteValue("Json course");
writer.WriteEndArray();
writer.WritePropertyName("since");
writer.WriteValue(new DateTime(2018, 03, 29));
writer.WritePropertyName("happy");
writer.WriteValue(true);
writer.WritePropertyName("issues");
writer.WriteNull();
writer.WriterStartObject();
...
writer.WriteEndObject();
writer.WriteEndObject();
writer.Flush();
string jsonText = sw.GetStringBuilder().ToString();
//In .NET string are immutable so if you keep modifying a string without using a StringBuilder,
//you will be suffering from a deep performance hit
Dates in JSON
1. Without any setting, Json.NET's default is ISO 8601 (2009-07-11T23:00:00)
2. Use Microsoft date format with setting
JsonSerializerSetting settingsMicrosoftDate = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat // "\/Date(1247374800000-0600)\/"
};
3. Use custom date converter
... = JsonConvert.SerializeObject(author, Formatting.Indented, new IsoDateTimeConverter());
4. Use Custom format date
JsonSerializerSetting settingsCustomDate = new JsonSerializerSettings
{
DateFormatString = "dd/mm/yyyy"
};
5. Use JavaScript date
... = JsonConvert.SerializeObject(author, Formatting.Indented, new JavaScriptDateTimeConverter()); // "new Date(1247374800000)"
Error Handling
List<string> errors = new List<string>();
JsonSerializerSettings jSS = new JsonSerializerSettings
{
Error = delegate(object sender, ErrorEventArgs errorArgs) //1 way
{
errors.Add(errorArgs.ErrorContext.Error.Message);
errorArgs.ErrorContext.Handled = true;
},
Error = HandleDeserializationError, //2 way
Converters = { new IsoDateTimeConverter() }
}
private static void HandleDeserializationError(object sender, ErrorEventArgs errorArgs)
{
var currentError = errorArgs.ErrorContext.Error.Message;
//Test if data in other format
errorArgs.ErrorContext.Handled = true;
}
or just throw error with try-catch block
출처
이 모든 내용은 Pluralsight에 Xavier Morera가 올린 'Getting Started with JSON in C# Using Json.NET'라는 강의의 두번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/json-csharp-jsondotnet-getting-started/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.
(Json.NET) Performance Tips (0) | 2018.03.30 |
---|---|
(Json.NET) Custom Serialization (0) | 2018.03.30 |
(Json.NET) Settings & Attributes (0) | 2018.03.30 |