JSON序列化:
WebAPI的默认序列库使用的是Json.NET,可以在Globally中配置使用DataContractJsonSerializer 进行序列化
protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; json.UseDataContractJsonSerializer = true; }
默认情况下,所有的公共的属性和字段都能被序列化(非公共的不能),除非声明了JsonIgnore特性
public class Product { public string Name { get; set; } public decimal Price { get; set; } [JsonIgnore] public int ProductCode { get; set; } // 不能被序列化 }
或者使用一下方式,将需要序列化的元素显示标出来
[DataContract] public class Product { [DataMember] public string Name { get; set; } [DataMember] public decimal Price { get; set; } public int ProductCode { get; set; } // 不能被序列化 }
JSON序列化时的一些设置【测试好像没效果,疑惑】
1 var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; 2 //设置UTC时区 3 json.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; 4 //设置缩进 5 json.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; 6 //使用驼峰命名法 7 json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 8 //使用Microsoft JSON 时间格式("/Date(ticks)/") 9 json.SerializerSettings.DateFormatHandling= Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
action方法可以返回一个匿名对象,序列化成JSON(匿名对象不能序列化成XML)
1 public object Get() 2 { 3 return new { 4 Name = "Alice", 5 Age = 23, 6 Pets = new List<string> { "Fido", "Polly", "Spot" } 7 }; 8 } 9 结果: 10 {"Name":"Alice","Age":23,"Pets":["Fido","Polly","Spot"]}
如果从client收到一个JSON格式的对象,可以反序列化这个JSON对象成Newtonsoft.Json.Linq.JObject 类型的对象【需要时POST请求】
public void Post(JObject person) { string name = person["Name"].ToString(); int age = person["Age"].ToObject<int>(); }
Note:XML序列器不支持 匿名对象和JObject实例
XML序列化:
默认使用DataContractSerializer进行xml序列化,序列化的规则如下:
- 所有的公共属性和字段都能被序列化,使用IgnoreDataMember 特性可以将其排除
- 私有和受保护的成员不会被序列化
- 只读属性不会被序列化
- 类和成员的名字被原样写入xml
- 使用默认的xml命名空间
如果要更准确的控制序列化的内容,可以使用DataContract 特性,当出现了这个特性,将按如下规则进行序列化:
- 只有标记了DataMember特性的字段或属性才能被序列化
- 标记了DataMember特性的private/protected的成员也能被序列化
- 只读属性不会被序列化
- 改变对应的xml文件中命名空间或类的名字,使用DataContract特性
//xml默认使用DataContractSerializer 进行序列化 var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter; xml.UseXmlSerializer = true; //使用XmlSerializer 进行序列化 xml.Indent = true;//使用缩进 //设置指定对象使用指定的序列化器 xml.SetSerializer<Product>(new XmlSerializer(typeof(Product)));
移除JSON或XML序列化器
void ConfigureApi(HttpConfiguration config) { // Remove the JSON formatter config.Formatters.Remove(config.Formatters.JsonFormatter); // or // Remove the XML formatter config.Formatters.Remove(config.Formatters.XmlFormatter); }
处理对象的循环引用
默认情况下XML和JSON的序列化器会对对象的循环引用这种情况在序列化时抛出异常
JSON可以使用如下方式处理:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;
举例如下:
1 public class Employee 2 { 3 public string Name { get; set; } 4 public Department Department { get; set; } 5 } 6 7 public class Department 8 { 9 public string Name { get; set; } 10 public Employee Manager { get; set; } 11 } 12 13 public class DepartmentsController : ApiController 14 { 15 public Department Get(int id) 16 { 17 Department sales = new Department() { Name = "Sales" }; 18 Employee alice = new Employee() { Name = "Alice", Department = sales }; 19 sales.Manager = alice; 20 return sales; 21 } 22 } 23 结果: 24 {"$id":"1","Name":"Sales","Manager":{"$id":"2","Name":"Alice","Department":{"$ref":"1"}}}
XML有两种方式处理这种情况:
- 在DataContract特性上设置IsReference=true
1 [DataContract(IsReference=true)] 2 public class Department 3 { 4 [DataMember] 5 public string Name { get; set; } 6 [DataMember] 7 public Employee Manager { get; set; } 8 }
2.创建一个针对这个对象的xml序列化器,设置允许循环引用
1 var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter; 2 var dcs = new DataContractSerializer(typeof(Department), null, int.MaxValue, 3 false, /* preserveObjectReferences: */ true, null); 4 xml.SetSerializer<Department>(dcs);
测试对象的序列化
1 string Serialize<T>(MediaTypeFormatter formatter, T value) 2 { 3 // Create a dummy HTTP Content. 4 Stream stream = new MemoryStream(); 5 var content = new StreamContent(stream); 6 /// Serialize the object. 7 formatter.WriteToStreamAsync(typeof(T), value, stream, content, null).Wait(); 8 // Read the serialized string. 9 stream.Position = 0; 10 return content.ReadAsStringAsync().Result; 11 } 12 13 T Deserialize<T>(MediaTypeFormatter formatter, string str) where T : class 14 { 15 // Write the serialized string to a memory stream. 16 Stream stream = new MemoryStream(); 17 StreamWriter writer = new StreamWriter(stream); 18 writer.Write(str); 19 writer.Flush(); 20 stream.Position = 0; 21 // Deserialize to an object of type T 22 return formatter.ReadFromStreamAsync(typeof(T), stream, null, null).Result as T; 23 } 24 25 // Example of use 26 void TestSerialization() 27 { 28 var value = new Person() { Name = "Alice", Age = 23 }; 29 30 var xml = new XmlMediaTypeFormatter(); 31 string str = Serialize(xml, value); 32 33 var json = new JsonMediaTypeFormatter(); 34 str = Serialize(json, value); 35 36 // Round trip 37 Person person2 = Deserialize<Person>(json, str); 38 }