ASP.NET Web API 'sinde JSON ve XML serileştirmeJSON and XML Serialization in ASP.NET Web API

, Mike te sonby Mike Wasson

Bu makalede ASP.NET Web API 'sindeki JSON ve XML formatlayıcıları açıklanmaktadır.This article describes the JSON and XML formatters in ASP.NET Web API.

ASP.NET Web API 'sinde, bir medya türü biçimlendiricisi şunları yapabilir:In ASP.NET Web API, a media-type formatter is an object that can:

  • Bir HTTP ileti gövdesinden CLR nesnelerini okumaRead CLR objects from an HTTP message body
  • CLR nesnelerini bir HTTP ileti gövdesine yazmaWrite CLR objects into an HTTP message body

Web API 'si hem JSON hem de XML için medya türü biçimleri sağlar.Web API provides media-type formatters for both JSON and XML. Framework, varsayılan olarak bu biçimleri ardışık düzene ekler.The framework inserts these formatters into the pipeline by default. İstemciler, HTTP isteğinin Accept üst bilgisinde JSON veya XML isteğinde bulunabilir.Clients can request either JSON or XML in the Accept header of the HTTP request.

İçindekilerContents

JSON Media-Type biçimlendiricisiJSON Media-Type Formatter

JSON biçimlendirmesi, Jsonmediatypeformatter sınıfı tarafından sağlanır.JSON formatting is provided by the JsonMediaTypeFormatter class. Varsayılan olarak, Jsonmediatypeformatter serileştirme gerçekleştirmek için JSON.net kitaplığını kullanır.By default, JsonMediaTypeFormatter uses the Json.NET library to perform serialization. Json.NET, üçüncü taraf bir açık kaynak projem.Json.NET is a third-party open source project.

İsterseniz, Json.NET yerine DataContractJsonSerializer kullanmak Için Jsonmediatypeformatter sınıfını yapılandırabilirsiniz.If you prefer, you can configure the JsonMediaTypeFormatter class to use the DataContractJsonSerializer instead of Json.NET. Bunu yapmak için Usedatacontractjsonserializer özelliğini trueolarak ayarlayın:To do so, set the UseDataContractJsonSerializer property to true:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;

JSON Seri Hale GetirmeJSON Serialization

Bu bölümde, varsayılan JSON.net serileştirici kullanılarak JSON biçimlendirici 'nin bazı belirli davranışları açıklanmaktadır.This section describes some specific behaviors of the JSON formatter, using the default Json.NET serializer. Bu, Json.NET kitaplığı hakkında kapsamlı bir belge olması anlamına gelir; daha fazla bilgi için JSON.net belgelerinebakın.This is not meant to be comprehensive documentation of the Json.NET library; for more information, see the Json.NET Documentation.

Ne seri hale getirilebilir?What Gets Serialized?

Varsayılan olarak, tüm ortak özellikler ve alanlar serileştirilmiş JSON 'a dahil edilir.By default, all public properties and fields are included in the serialized JSON. Bir özellik veya alanı atlamak için, bunu Jsonıgnore özniteliğiyle süsle.To omit a property or field, decorate it with the JsonIgnore attribute.

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    [JsonIgnore]
    public int ProductCode { get; set; } // omitted
}

Bir " katılım yaklaşımı tercih ediyorsanız " , sınıfı DataContract özniteliğiyle süsler.If you prefer an "opt-in" approach, decorate the class with the DataContract attribute. Bu öznitelik mevcutsa, DataMemberöğesine sahip olmadıkları müddetçe Üyeler göz ardı edilir.If this attribute is present, members are ignored unless they have the DataMember. Özel üyeleri seri hale getirmek için DataMember de kullanabilirsiniz.You can also use DataMember to serialize private members.

[DataContract]
public class Product
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public decimal Price { get; set; }
    public int ProductCode { get; set; }  // omitted by default
}

Read-Only özellikleriRead-Only Properties

Salt okuma özellikleri varsayılan olarak serileştirilir.Read-only properties are serialized by default.

TarihlerDates

Varsayılan olarak, Json.NET tarihleri ıso 8601 biçiminde yazar.By default, Json.NET writes dates in ISO 8601 format. UTC (Eşgüdümlü Evrensel Saat) tarihleri "Z" sonekiyle yazılır.Dates in UTC (Coordinated Universal Time) are written with a "Z" suffix. Yerel saat içindeki tarihler, saat dilimi konumunu içerir.Dates in local time include a time-zone offset. Örneğin:For example:

2012-07-27T18:51:45.53403Z         // UTC
2012-07-27T11:51:45.53403-07:00    // Local

Varsayılan olarak, Json.NET saat dilimini korur.By default, Json.NET preserves the time zone. DateTimeZoneHandling özelliğini ayarlayarak bunu geçersiz kılabilirsiniz:You can override this by setting the DateTimeZoneHandling property:

// Convert all dates to UTC
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;

ISO 8601 yerine MICROSOFT JSON tarih biçimini () kullanmayı tercih ediyorsanız "\/Date(ticks)\/" , serileştirici ayarlarındaki DateFormatHandling özelliğini ayarlayın:If you prefer to use Microsoft JSON date format ("\/Date(ticks)\/") instead of ISO 8601, set the DateFormatHandling property on the serializer settings:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.DateFormatHandling 
= Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;

GirintilemeIndenting

Girintili JSON yazmak için biçimlendirme ayarını biçimlendirme. girintiliolarak ayarlayın:To write indented JSON, set the Formatting setting to Formatting.Indented:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;

Kamel büyük harfleriCamel Casing

Veri modelinizi değiştirmeden JSON özellik adlarını kamel büyük küçük harfe yazmak için, seri hale getirici üzerinde Camelcasepropertynamescontractresolver ' ı ayarlayın:To write JSON property names with camel casing, without changing your data model, set the CamelCasePropertyNamesContractResolver on the serializer:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

Anonim ve Weakly-Typed nesnelerAnonymous and Weakly-Typed Objects

Bir eylem yöntemi, anonim bir nesne döndürebilir ve bunu JSON 'a seri hale getirebilirsiniz.An action method can return an anonymous object and serialize it to JSON. Örneğin:For example:

public object Get()
{
    return new { 
        Name = "Alice", 
        Age = 23, 
        Pets = new List<string> { "Fido", "Polly", "Spot" } 
    };
}

Yanıt iletisi gövdesinde şu JSON yer alacak:The response message body will contain the following JSON:

{"Name":"Alice","Age":23,"Pets":["Fido","Polly","Spot"]}

Web API 'niz istemcilerden gevşek olarak yapılandırılmış JSON nesneleri alırsa, istek gövdesinin serisini ' de birNewtonsoft.Jsiçin silebilirsiniz ** . LINQ. JObject** türü.If your web API receives loosely structured JSON objects from clients, you can deserialize the request body to a Newtonsoft.Json.Linq.JObject type.

public void Post(JObject person)
{
    string name = person["Name"].ToString();
    int age = person["Age"].ToObject<int>();
}

Ancak, türü kesin belirlenmiş veri nesneleri kullanmak genellikle daha iyidir.However, it is usually better to use strongly typed data objects. Daha sonra verileri kendiniz ayrıştırmanıza gerek kalmaz ve model doğrulamasının avantajlarını elde edersiniz.Then you don't need to parse the data yourself, and you get the benefits of model validation.

XML serileştiricisi anonim türleri veya JObject örneklerini desteklemez.The XML serializer does not support anonymous types or JObject instances. JSON verileriniz için bu özellikleri kullanırsanız, bu makalenin ilerleyen kısımlarında açıklandığı gibi, XML biçimlendirici ' i ardışık düzen öğesinden kaldırmanız gerekir.If you use these features for your JSON data, you should remove the XML formatter from the pipeline, as described later in this article.

XML Media-Type biçimlendiricisiXML Media-Type Formatter

XML biçimlendirmesi Xmlmediatypeformatter sınıfı tarafından sağlanır.XML formatting is provided by the XmlMediaTypeFormatter class. Varsayılan olarak, Xmlmediatypeformatter serileştirme işlemini gerçekleştirmek için DataContractSerializer sınıfını kullanır.By default, XmlMediaTypeFormatter uses the DataContractSerializer class to perform serialization.

Tercih ederseniz, XmlmediatypeformatterDataContractSerializeryerine XmlSerializer 'ı kullanacak şekilde yapılandırabilirsiniz.If you prefer, you can configure the XmlMediaTypeFormatter to use the XmlSerializer instead of the DataContractSerializer. Bunu yapmak için useXmlSerializer özelliğini trueolarak ayarlayın:To do so, set the UseXmlSerializer property to true:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;

XmlSerializer sınıfı, DataContractSerializer'dan daha dar bir tür kümesini destekler, ancak sonuçta elde edilen XML üzerinde daha fazla denetim sağlar.The XmlSerializer class supports a narrower set of types than DataContractSerializer, but gives more control over the resulting XML. Mevcut bir XML şemasıyla eşleşmesi gerekiyorsa XmlSerializer kullanmayı düşünün.Consider using XmlSerializer if you need to match an existing XML schema.

XML seri hale getirmeXML Serialization

Bu bölümde, varsayılan DataContractSerializerkullanılarak XML biçimlendirici 'nin bazı belirli davranışları açıklanmaktadır.This section describes some specific behaviors of the XML formatter, using the default DataContractSerializer.

Varsayılan olarak, DataContractSerializer aşağıdaki gibi davranır:By default, the DataContractSerializer behaves as follows:

  • Tüm genel okuma/yazma özellikleri ve alanları serileştirilir.All public read/write properties and fields are serialized. Bir özellik veya alanı atlamak için, ıgnoredatamember özniteliğiyle süslenmiş.To omit a property or field, decorate it with the IgnoreDataMember attribute.
  • Özel ve korunan Üyeler serileştirilmez.Private and protected members are not serialized.
  • Salt okuma özellikleri serileştirilmez.Read-only properties are not serialized. (Ancak, salt okunurdur bir koleksiyon özelliğinin içeriği serileştirilir.)(However, the contents of a read-only collection property are serialized.)
  • Sınıf ve üye adları, sınıf bildiriminde göründükleri gibi XML 'e tam olarak yazılır.Class and member names are written in the XML exactly as they appear in the class declaration.
  • Varsayılan bir XML ad alanı kullanılır.A default XML namespace is used.

Serileştirme üzerinde daha fazla denetime ihtiyacınız varsa, bir sınıfı DataContract özniteliğiyle süslemek için kullanabilirsiniz.If you need more control over the serialization, you can decorate the class with the DataContract attribute. Bu öznitelik mevcut olduğunda, sınıf aşağıdaki şekilde serileştirilir:When this attribute is present, the class is serialized as follows:

  • "Kabul etme " yaklaşımı: Özellikler ve alanlar varsayılan olarak serileştirilmez."Opt in" approach: Properties and fields are not serialized by default. Bir özellik veya alanı seri hale getirmek için, bunu DataMember özniteliğiyle süsle.To serialize a property or field, decorate it with the DataMember attribute.
  • Özel veya korumalı bir üyeyi seri hale getirmek için, bunu DataMember özniteliğiyle süsle.To serialize a private or protected member, decorate it with the DataMember attribute.
  • Salt okuma özellikleri serileştirilmez.Read-only properties are not serialized.
  • Sınıf adının XML 'de nasıl göründüğünü değiştirmek için, DataContract özniteliğinde Name parametresini ayarlayın.To change how the class name appears in the XML, set the Name parameter in the DataContract attribute.
  • Bir üye adının XML 'de nasıl göründüğünü değiştirmek için, DataMember özniteliğinde Name parametresini ayarlayın.To change how a member name appears in the XML, set the Name parameter in the DataMember attribute.
  • XML ad alanını değiştirmek için, DataContract sınıfında ad alanı parametresini ayarlayın.To change the XML namespace, set the Namespace parameter in the DataContract class.

Read-Only özellikleriRead-Only Properties

Salt okuma özellikleri serileştirilmez.Read-only properties are not serialized. Salt okunurdur bir özelliğin bir yedekleme özel alanı varsa, özel alanı DataMember özniteliğiyle işaretleyebilirsiniz.If a read-only property has a backing private field, you can mark the private field with the DataMember attribute. Bu yaklaşım, sınıfında DataContract özniteliğini gerektirir.This approach requires the DataContract attribute on the class.

[DataContract]
public class Product
{
    [DataMember]
    private int pcode;  // serialized

    // Not serialized (read-only)
    public int ProductCode { get { return pcode; } }
}

TarihlerDates

Tarihler ISO 8601 biçiminde yazılır.Dates are written in ISO 8601 format. Örneğin, " 2012-05-23T20:21:37.9116538 z " .For example, "2012-05-23T20:21:37.9116538Z".

GirintilemeIndenting

Girintili XML yazmak için Girintile özelliğini trueolarak ayarlayın:To write indented XML, set the Indent property to true:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.Indent = true;

Per-Type XML serileştiricileri ayarlamaSetting Per-Type XML Serializers

Farklı CLR türleri için farklı XML serileştiricileri ayarlayabilirsiniz.You can set different XML serializers for different CLR types. Örneğin, geriye doğru uyumluluk için XmlSerializer gerektiren belirli bir veri nesneniz olabilir.For example, you might have a particular data object that requires XmlSerializer for backward compatibility. Bu nesne için XmlSerializer 'ı kullanabilir ve diğer türler için DataContractSerializer kullanmaya devam edebilirsiniz.You can use XmlSerializer for this object and continue to use DataContractSerializer for other types.

Belirli bir tür için bir XML serileştirici ayarlamak için setserializerçağırın.To set an XML serializer for a particular type, call SetSerializer.

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
// Use XmlSerializer for instances of type "Product":
xml.SetSerializer<Product>(new XmlSerializer(typeof(Product)));

Bir XmlSerializer veya XmlObjectSerializeröğesinden türetilen herhangi bir nesne belirtebilirsiniz.You can specify an XmlSerializer or any object that derives from XmlObjectSerializer.

JSON veya XML biçimlendirici kaldırılıyorRemoving the JSON or XML Formatter

JSON biçimlendirici veya XML biçimlendirici, bunları kullanmak istemiyorsanız Formatters listesinden kaldırabilirsiniz.You can remove the JSON formatter or the XML formatter from the list of formatters, if you do not want to use them. Bunu yapmak için başlıca nedenler şunlardır:The main reasons to do this are:

  • Web API yanıtlarınızı belirli bir medya türüyle sınırlamak için.To restrict your web API responses to a particular media type. Örneğin, yalnızca JSON yanıtlarını desteklemeye karar verebilir ve XML biçimlendirici ' ı kaldırabilirsiniz.For example, you might decide to support only JSON responses, and remove the XML formatter.
  • Varsayılan biçimlendiricisi özel bir biçimlendirici ile değiştirmek için.To replace the default formatter with a custom formatter. Örneğin, JSON biçimlendirici bir JSON biçimlendiricisi kendi özel uygulamanıza göre değiştirebilirsiniz.For example, you could replace the JSON formatter with your own custom implementation of a JSON formatter.

Aşağıdaki kod, varsayılan formatlamalara nasıl kaldırılacağını gösterir.The following code shows how to remove the default formatters. Bunu, Global. asax içinde tanımlanan uygulama _ başlatma yönteminden çağırın.Call this from your Application_Start method, defined in Global.asax.

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);
}

Döngüsel nesne başvurularını işlemeHandling Circular Object References

Varsayılan olarak, JSON ve XML formatlayıcıları tüm nesneleri değer olarak yazar.By default, the JSON and XML formatters write all objects as values. İki özellik aynı nesneye başvurursanız veya aynı nesne bir koleksiyonda iki kez görünürse, biçimlendirici nesneyi iki kez serileştirilir.If two properties refer to the same object, or if the same object appears twice in a collection, the formatter will serialize the object twice. Bu, nesne grafikleriniz döngüler içeriyorsa, bu bir sorundur çünkü seri hale getirici grafikte bir döngü algıladığında bir özel durum oluşturur.This is a particular problem if your object graph contains cycles, because the serializer will throw an exception when it detects a loop in the graph.

Aşağıdaki nesne modellerini ve denetleyiciyi göz önünde bulundurun.Consider the following object models and controller.

public class Employee
{
    public string Name { get; set; }
    public Department Department { get; set; }
}

public class Department
{
    public string Name { get; set; }
    public Employee Manager { get; set; }
}

public class DepartmentsController : ApiController
{
    public Department Get(int id)
    {
        Department sales = new Department() { Name = "Sales" };
        Employee alice = new Employee() { Name = "Alice", Department = sales };
        sales.Manager = alice;
        return sales;
    }
}

Bu eylemi çağırmak, biçimlendirici bir durum kodu 500 (Iç sunucu hatası) yanıtına çeviren bir özel durum oluşturulmasına neden olur.Invoking this action will cause the formatter to throw an exception, which translates to a status code 500 (Internal Server Error) response to the client.

JSON 'daki nesne başvurularını korumak için, Global. asax dosyasındaki uygulama _ başlatma yöntemine aşağıdaki kodu ekleyin:To preserve object references in JSON, add the following code to Application_Start method in the Global.asax file:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = 
    Newtonsoft.Json.PreserveReferencesHandling.All;

Artık denetleyici eylemi şuna benzer bir JSON döndürür:Now the controller action will return JSON that looks like this:

{"$id":"1","Name":"Sales","Manager":{"$id":"2","Name":"Alice","Department":{"$ref":"1"}}}

Seri hale getiricinin " her iki nesneye bir $id özelliği eklediğine dikkat edin " .Notice that the serializer adds an "$id" property to both objects. Ayrıca, Employee. Department özelliğinin bir döngü oluşturduğunu algılar, bu yüzden değeri bir nesne başvurusuyla değiştirir: { " $ref " : " 1 " }.Also, it detects that the Employee.Department property creates a loop, so it replaces the value with an object reference: {"$ref":"1"}.

Note

Nesne başvuruları JSON 'da standart değildir.Object references are not standard in JSON. Bu özelliği kullanmadan önce, istemcilerinizin sonuçları ayrıştırabilecek olup olmayacağını göz önünde bulundurun.Before using this feature, consider whether your clients will be able to parse the results. Yalnızca grafikten döngüleri kaldırmak daha iyi olabilir.It might be better simply to remove cycles from the graph. Örneğin, çalışana kadar olan bağlantı bu örnekte gerçekten gerekli değildir.For example, the link from Employee back to Department is not really needed in this example.

XML 'deki nesne başvurularını korumak için iki seçeneğiniz vardır.To preserve object references in XML, you have two options. Daha basit seçeneği [DataContract(IsReference=true)] model sınıfınıza eklemektir.The simpler option is to add [DataContract(IsReference=true)] to your model class. IsReference parametresi nesne başvurularını mümkün bir şekilde sunar.The IsReference parameter enables object references. DataContract serileştirme kabul eder, bu nedenle ayrıca özelliklere DataMember öznitelikleri eklemeniz gerekir:Remember that DataContract makes serialization opt-in, so you will also need to add DataMember attributes to the properties:

[DataContract(IsReference=true)]
public class Department
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public Employee Manager { get; set; }
}

Artık biçimlendirici şuna benzer bir XML oluşturacak:Now the formatter will produce XML similar to following:

<Department xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="i1" 
            xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" 
            xmlns="http://schemas.datacontract.org/2004/07/Models">
  <Manager>
    <Department z:Ref="i1" />
    <Name>Alice</Name>
  </Manager>
  <Name>Sales</Name>
</Department>

Model sınıfınıza ait özniteliklerin önüne geçmek istiyorsanız, başka bir seçenek vardır: yeni türe özgü bir DataContractSerializer örneği oluşturun ve bu tür Için preserveObjectReferences öğesini true olarak ayarlayın.If you want to avoid attributes on your model class, there is another option: Create a new type-specific DataContractSerializer instance and set preserveObjectReferences to true in the constructor. Sonra bu örneği, XML medya türü biçimlendirici üzerinde tür başına seri hale getirici olarak ayarlayın.Then set this instance as a per-type serializer on the XML media-type formatter. Aşağıdaki kod bunun nasıl yapılacağını göstermektedir:The following code show how to do this:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
var dcs = new DataContractSerializer(typeof(Department), null, int.MaxValue, 
    false, /* preserveObjectReferences: */ true, null);
xml.SetSerializer<Department>(dcs);

Test nesnesi serileştirmeTesting Object Serialization

Web API 'nizi tasarlarken, veri nesnelerinizin nasıl seri hale getirileceğinin test olması yararlı olur.As you design your web API, it is useful to test how your data objects will be serialized. Bunu, denetleyici oluşturmadan veya bir denetleyici eylemi çağırmadan yapabilirsiniz.You can do this without creating a controller or invoking a controller action.

string Serialize<T>(MediaTypeFormatter formatter, T value)
{
    // Create a dummy HTTP Content.
    Stream stream = new MemoryStream();
    var content = new StreamContent(stream);
    /// Serialize the object.
    formatter.WriteToStreamAsync(typeof(T), value, stream, content, null).Wait();
    // Read the serialized string.
    stream.Position = 0;
    return content.ReadAsStringAsync().Result;
}

T Deserialize<T>(MediaTypeFormatter formatter, string str) where T : class
{
    // Write the serialized string to a memory stream.
    Stream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(str);
    writer.Flush();
    stream.Position = 0;
    // Deserialize to an object of type T
    return formatter.ReadFromStreamAsync(typeof(T), stream, null, null).Result as T;
}

// Example of use
void TestSerialization()
{
    var value = new Person() { Name = "Alice", Age = 23 };

    var xml = new XmlMediaTypeFormatter();
    string str = Serialize(xml, value);

    var json = new JsonMediaTypeFormatter();
    str = Serialize(json, value);

    // Round trip
    Person person2 = Deserialize<Person>(json, str);
}