Skip to content
yanggujun edited this page Apr 7, 2017 · 10 revisions

Commons.Json

Commons.Json is a fast, lightweight .NET JSON library. The library is intended to provide a way that no any configuration or attribute is needed when mapping the JSON string to .NET object and vice versa.

Installation

Commons.Json is delivered as a nuget package. You can get the package in nuget.org.

Or in nuget console, you can type following commands and directly install to your project

PM>Install-Package Commons.Json

Usage Guide

Basic Mapping

  • Map the object to a JSON string
  public class Person
  {
      public string Name { get; set; }
      public int Age { get; set; }
      public string Nationality { get; set; }
      public string Gender { get; set; }
  }
  
  var person = new Person
  {
      Name = "Joe",
      Age = 25,
      Nationality = "US",
      Gender = "Male"
  };
  var json = JsonMapper.ToJson(person); // {"Name":"Joe","Age":25,"Nationality":"US","Gender":"Male"}
  • Map a JSON string to a .NET object
  // json string: {"Name":"Joe","Age":25, "Nationality":"US","Gender":"Male"}
  var person = JsonMapper.To<Person>(json);
  • Map a JSON array to list
  // json string: [{"Name":"Joe","Age":25, "Nationality":"US","Gender":"Male"}, {"Name":"John", "Age":27, "Nationality":"FR", "Gender":"Male"}, {"Name":"Jane","Age":23, "Nationality":"EN","Gender":"Female"}]
  var list = JsonMapper.To<List<Person>>(json);
  • Map a JSON array to .NET array
  // json string : [0, 1, 3, 4, 5, 6]
  var array = JsonMapper.To<int[]>(json); // get an int array with value [0, 1, 2, 3, 4, 5, 6]

  // json string :[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
  var matrix = JsonMapper.To<int[][]>(json); // get an int matrix object.
  • Map a collection to JSON array. You can map most of collection into a JSON array or a JSON object (for dictionary<string, T>)
  var jane = new Person{...};
  var john = new Person{...};
  var joe = new person{...};
  var list = new List<Person>{joe, john, jane};
  var json = JsonMapper.ToJson(list);
  • Map JSON primitives to .NET primtives and string
  // json string: 5
  var number = JsonMapper.To<int>(json); // number = 5

  var anotherNumber = JsonMapper.To<long>(json); // anotherNumber = 5

  // json string: 5.6
  var floatingNumber = JsonMapper.To<double>(json); // floatingNumber = 5.6

  // note: this will fail when json string is 5.6
  var wrongNumber = JsonMapper.To<int>(json);

  // json string: "a plain string"
  var str = JsonMapper.To<string>(json); // str : "a plain string"

  // json = true
  var b = JsonMapper.To<bool>(json); // b : true
  • Map .NET primitives and string to JSON
  var number = 100;
  var json = JsonMapper.ToJson(number); // json string: 100

  var floatingNumbe = 5.1274;
  var json = JsonMapper.ToJson(floatingNumber); // json string: 5.1274

  var str = "the demo string";
  var json = JsonMapper.ToJson(str); // json string: "the demo string"
  • Map an enum
  public enum Major
  {
  	CS,
  	Art,
  	Politics,
  	Economics,
  	Physics,
  	Chemistry
  }

  //...

  // JSON string: "Art"
  var major = JsonMapper.To<Major>(json); // major = Major.Art

  // Map the enum to JSON
  var json = JsonMapper.ToJson(Major.Physics); // json string: "Physics"
  • Map date time

    Serialize/deserialize date time in c# is quite slow. To speed up this operation, by default, JsonMapper is to map the date time with json string in "MM/dd/yyyy HH:mm:ss.fff".

  • Map a nullable object

  public struct Simple
  {
      public int Count {get;set;}
      public string Name {get;set;}
  }

  // JSON string: {"Name": "A Simple struct", "Count": 10}
  var simple = JsonMapper.To<Simple?>(json);
  var count = simple.Value.Count; // count = 10

  public class Complex
  {
      public bool IsValid {get;set;}
      public Simple? Simple{get;set;}
  }

  // JSON string: {"IsValid": true, "Simple": {"Name": "Simple in complex", "Count": 20}}
  var comp = JsonMapper.To<Complex>(json);
  var count = comp.Simple.Value.Count; // count = 20
  • Combine those things together...
  public class Student
  {
      public string Name {get;set;}
      public int Grade {get;set;}
      public Major Major {get;set;}
  }

  public class School
  {
      public string Name {get;set;}
      public List<Student> Students {get;set;}
  }

  // json string:
  // {"Name": "some university", "Students": [{"Name": "Jane", "Grade": 2, "Major": "Art"}, {"Name": "Jason", "Grade": 3, "Major": "CS"}, {"Name":"Alan", "Grade":3, "Major":"Politics"}]}
  var school = JsonMapper.To<School>(json);
  var name = school.Name; // Name = "some university"
  var students = school.Students;
  var name1 = students[0].Name; // name1 = "Jane"
  var grade1 = students[0].Grade; // grade1 = 2
  • Only property with public getters are mapped from object to JSON
  public class Employee
  {
      public class Employee()
      {
          Gender = "Male";
      }
      public string Name {get;set;}
      public string Gender {get;private set;}
      public string Position {private get;set;}
  }
  
  //...

  var john = new Employee
  {
      Name = "John",
      Position = "Manager"
  }

  var json = JsonMapper.ToJson(john); // json string: {"Name":"John","Gender":"Male"}
  • Only property with public setters are mapped from JSON to object
  // json string: {"Name": "Jane", "Gender": "Female", "Position": "Director"}
  var jane = JsonMapper.To<Employee>(json);
  var gender = jane.Gender; // gender = "Male"
  • When no corresponding property is found on the object, it is ignored
  // json string: {"Name": "John", "Position": "Director", "Age": 40}
  var john = JsonMapper.To<Employee>(json);
  var name = john.Name;
  var position = john.Position;
  //... The "Age" field is not mapped to the object.

Complex Situations

  • Map context

By default, JsonMapper uses the default map context, which is initialized when JsonMapper is called on the first time.

When you want different mapping behaviors (like map the property into a name other than the property name), a map context is needed in this situation.

Creating a map context may cause unwanted overhead. So it is recommended to use one map context across application or component. It is unwise to always create the map context when map configuration is needed.

Except the map configuration operation, which is usually done in the initialization phase of the application, other operations on map context is thread safe.

  • You can tell the mapper to map an object property into a different name
  // json string:
  // {"School Name": "some university", "Students": [{"Student Name": "Jane", "Grade": 2, "Major": "Art"}, {"Student Name": "Jason", "Grade": 3, "Major": "CS"}, {"Student Name":"Alan", "Grade":3, "Major":"Politics"}]}
  var context = JsonMapper.NewContext();
  context.For<School>(mapper => mapper.MapProperty(x => x.Name).With("School Name")); // case in-sensitive
  context.For<Student>(mapper => mapper.MapProperty(x => x.Name).With("Student Name")); // case in-sensitive

  //...

  var school = context.To<School>(json);
  var schoolName = school.Name; // schoolName = "some university"
  var jason = school.Students[1].Name; // jason = "Jason"
  • And not to map the property
  // json string:
  // {"School Name": "some university", "Students": [{"Student Name": "Jane", "Grade": 2, "Major": "Art"}, {"Student Name": "Jason", "Grade": 3, "Major": "CS"}, {"Student Name":"Alan", "Grade":3, "Major":"Politics"}]}
  var context = JsonMapper.NewContext();
  context.For<School>(mapper => mapper.MapProperty(x => x.Name).With("School Name")); // case in-sensitive
  context.For<Student>(mapper => mapper.MapProperty(x => x.Name).With("Student Name").Not.MapProperty(x => x.Grade)); // case in-sensitive
  
  //... 
  var school = context.To<Employee>(json);
  var jasonGrade = school.Students[1].Grade; // jasonGrade = 0. The value of the property that is not mapped is default(T)
  • If the object does not have a default conctructor or you want to specify the constructor
  public class Book
  {
      public Book(string category)
      {
          Category = category;
      }
      public string Name {get;set;}
      public string Aurthor {get;set;}
      public string Category {get;private set;}
  }

  // json string: {"Name":"The Republic", "Author": "Plato"}
  var context = JsonMapper.NewContext();
  context.For<Book>(mapper => mapper.ConstructWith(() => new Book("Philosophy")));

  var book = context.To<Book>(json);
  var name = book.Name; // name = "The Republic"
  var author = book.Author; // author = "Plato"
  var category = book.Category; // category = "Philosophy"
  • Manually convert JSON string to an object
  public class Strange
  {
      public string StrangeProp1 {get;set;}
      public string StrangeProp2 {get;set;}
      public string StrangeProp3 {get;set;}
  }

  public class Nice
  {
      public string Nice1 {get;set;}
      public Strange TheStranger {get;set;}
  }
  // json string: { "Nice1": "n1", "TheStranger": { "Normal1": "Value1", "Normal2": "Value2", "Normal3": "Value3"}

  var context = JsonMapper.NewContext();
  context.For<Strange>(mapper => mapper.ConstructWith(x => 
  {
      var jsonObj = (JObect)x;
      var strange = new Strange();
      strange.StrangeProp1 = jsonObj.GetString("Normal1");
      strange.StrangeProp2 = jsonObj.GetString("Normal2");
      strange.StrangeProp3 = jsonObj.GetString("Normal3");
      return strange;
  }));

  var nice = context.To<Nice>(json);
  var prop1 = nice.TheStranger.StrangeProp1; // prop1 = "Value1"
  var prop2 = nice.TheStranger.StrangeProp2; // prop2 = "Value2"
  var prop3 = nice.TheStranger.StrangeProp3; // prop3 = "Value3"
  
  • Convert JSON into an interface
  public interface IAwesome
  {
      string WhyIamAwesome {get;set;}
  }

  public class Wonder : IAwesome
  {
      public string WhyIamAwesome {get;set;}
  }

  public class Destination
  {
      public string Place {get;set;}
      public IAwesome Awesome {get;set;}
  }

  var context = JsonMapper.NewContext();
  context.For<IAwesome>(mapper => mapper.ConstructWith(() => new Wonder()));
  //JSON string: {"Place": "Giza", "Awesome": {"WhyIamAwesome": "Astonishing ancient pyramids"}}
  var thing = context.To<Destination>(json);
  var reason = thing.Awesome.WhyIamAwesome; // reason = "Astonishing ancient pyramids"
  • Manually construct an interface for multiple implementations
  public class Park : IAwesome
  {
      public string WhyIamAwesome {get;set;}
      pubilc string BestSeason {get;set;}
  }

  public class Beach : IAwesome
  {
      public string WhyIamAwesome {get;set;}
      public string Event {get;set;}
  }

  var context = JsonMapper.NewContext();
  context.For<IAwesome>(mapper => mapper.ConstructWith(x => 
  {
      var jsonObj = x as JObject;
      IAwesome awe;
      if (jsonObj.ContainsKey("BestSeason"))
      {
          var park = new Park();
          park.BestSeason = jsonObj.GetString("BestSeason");
          awe = park;
      }
      else if (jsonObj.ContainsKey("Event"))
      {
          var beach = new Beach();
          beach.Event = jsonObj.GetString("Event");
          awe = beach;
      }
      else
      {
          throw new ArgumentException();
      }
      awe.WhyIamAwesome = jsonObj.GetString("WhyIamAwesome");
      return awe;
  }));

  // JSON string: [{"Place": "Yellow Stone", "Awesome": {"WhyIamAwesome": "beautiful scenery", "BestSeason": "Autumn"}},{"Place": "Honululu", "Awesome": {"WhyIamAwesome": "Beautiful beach", "Event": "Surfing"}}]
  var places = context.To<List<Destination>>(json);
  var park = (Park)places[0].Awesome;
  var bestSeason = park.BestSeason; // bestSeason = "Autumn"

  var beach = (Beach)places[1].Awesome;
  var event = beach.Event; // event = "Surfing"
  • Use a specific date time format

When the default date time format is not intended, a specific format can be specified on the map context.

  public class Baby
  {
      public string Name {get;set;}
      public DateTime Dob {get;set;}
  }

  // json string: {"Name":"Cutie", "Dob":"04/11/2016"}

  var cutie = JsonMapper.NewContext().UseDateFormat("MM/dd/yyyy").To<Baby>(json);
  var birthday = cutie.Dob; // birthday = 04/11/2016 00:00:00
  • And use the default date time format for the current culture

When serialize or deserialize directly through JsonMapper instead of map context, the default date time format is always used.

  var baby = JsonMapper.To<Baby>(json);
  //...

Work with JValue objects and Convert Manually

  • Manually convert from object to JSON
  public class Person
  {
      public string Name { get; set; }
      public int Age { get; set; }
      public string Nationality { get; set; }
      public string Gender { get; set; }
  }

  
  var person = new Person
  {
      Name = "Joe",
      Age = 25,
      Nationality = "US",
      Gender = "Male"
  };

  var json = JsonMapper.ConvertToJson(person, p => 
  {
      var jsonObj = new JObject();
      jsonObj.SetString("Person Name", p.Name);
      jsonObj.SetInt32("Person Age", p.Age);
      jsonObj.SetString("Nation", p.Nationality);
      jsonObj.SetString("Sex", p.Gender);

      return jsonObj;
  });

  // json string: {"Person Name": "Joe", "Person Age": 25, "Nation": "US", "Sex":"Male"}
  • Manually convert from JSON to object
  // json string: {"Person Name": "Joe", "Person Age": 25, "Nation": "US", "Sex":"Male"}
  var person = JsonMapper.ConvertTo<Person>(json, jsonValue => 
  {
      var jsonObj = jsonValue as JObject;
      var p = new Person();
      p.Name = jsonObj.GetString("Person Name");
      p.Age = jsonObj.GetInt32("Person Age");
      p.Nationality = jsonObj.GetString("Nation");
      p.Gender = jsonObj.GetString("Sex");

      return p;
  });
  
  var name = person.Name; // name = "Joe"
  var age = person.Age; // age = 25
  var nation = person.Nationality; // nation = "US"
  var gender = person.Gender; // gender = "Male"

Dynamic JSON Manipulator

  • Work with dynamic JSON object
  // json string: {"Name":"A Storm of Swords", "Series":"A Song of Ice and Fire", "Author": "G.R.R.Martin", "Language": "English"}

  dynamic novel = JsonMapper.Parse(json);
  string name = novel.Name; // name = "A Storm of Swords"
  string series = novel.Series; // series = "A Song of Ice and Fire"
  string author = novel.Author; // author = "G.R.R.Matin"
  string lang = novel.Language; // lang = "English"
  • Dynamic JSON array
  // json string: [{"Name":"A Clash of Kings", "Series":"A Song of Ice and Fire", "Author": "G.R.R.Martin", "Language": "English"}, {"Name":"A Storm of Swords", "Series":"A Song of Ice and Fire", "Author": "G.R.R.Martin", "Language": "English"}] 
  dynamic novels = JsonMapper.Parse(json);
  string clash = novels[0].Name; // clash = "A Clash of Kings"
  string storm = novels[1].Name; // storm = "A Storm of Swords"

Clone this wiki locally