ASP.NET – Serialize đối tượng .NET thành JSON và ngược lại

Javascript-JSON-SerializerCác dữ liệu JSON được sử dụng rất thường xuyên trong ứng dụng web, đặc biệt khi cần truyền dữ liệu thông qua ajax. Trong ASP.NET, bạn có thể sử dụng class JavaScriptSerializer để chuyển đối một đối tượng .NET (hay CLR) bất kì thành một chuỗi JSON và ngược lại. Đồng thời, bạn có thể tạo ra các JavaScriptConverter để quy định cách thức chuyển đổi của JavaScriptSerializer.

Cơ bản

Trong bài viết này, tôi sử dụng một ứng dụng kiểu Console vì vậy cần phải thêm tham chiếu đến assembly System.Web.Script.Serialization. Class  JavaScriptSerializer chứa hai phương thức là  Serialize() và  Deserialize() dùng để chuyển đối tượng thành chuỗi JSON và ngược lại. Với một collection, phương thức Serialize() sẽ trả về một chuỗi JSON dạng mảng.

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Birthday { get; set; }
}

class Program
{

    static void Main(string[] args)
    {
        var js = new JavaScriptSerializer();

        var foo=new Foo(){
            Id = 1,
            Name = "Bar",
            Birthday = DateTime.Today
        };
        var json = js.Serialize(foo);

        Console.WriteLine("+ Serialize:\n"+json+"\n");

        var obj = (Foo) js.Deserialize(json, typeof(Foo));

        Console.WriteLine("+ Deserialize:\nId = {0} \nName = {1} \nBirthday = {2}",obj.Id,obj.Name,obj.Birthday);

        Console.Read();
    }

}

Ouput:

+ Serialize:
{"Id":1,"Name":"Bar","Birthday":"\/Date(1329670800000)\/"}

+ Deserialize:
Id = 1
Name = Bar
Birthday = 2/19/2012 5:00:00 PM

Sử dụng JavaScriptConverter

Trong ví dụ trên, kiểu dữ liệu DateTime được serialize thành một chuỗi rất khó để đọc và định dạng khi cần thiết. Vì thế tôi sẽ tạo một tạo một converter sau đó đăng kí cho đối tượng  JavaScriptSerializer. Converter tôi cần tạo phải được thừa kế từ JavaScriptConverter. Class này có 3 thành viên cần được override trong subclass:

–        SupportedTypes: property này sẽ trả về một danh sách các kiểu dữ liệu được hỗ trợ bởi converter này.

–        Serialize: Phương thức này sẽ tạo một đối tượng Dictionary chứa các cặp name/value dùng để chuyển đổi một đối tượng thành JSON.

–        Deserialize: Phương thức này nhận các dữ liệu cần thiết từ một Dictionary để tạo ra đối tượng .NET.

Như vậy Dictionary chính là đối tượng trung gian của quá trình chuyển đổi giữa đối tượng .NET và JSON. Mọi công việc mà bạn cần thực hiện chỉ đơn giản là thao tác trên dữ liệu của đối tượng Dictionary.

Javascript-JSON-Serializer

Tôi sẽ viết một class  MyFooConverter và sau đó đăng kí một instance của nó vào  JavaScriptSerializer bằng phương thức  RegisterConverters():

public class MyFooConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(Foo) }; }
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        var result = new Dictionary<string, object>();

        var foo = obj as Foo;
        if (foo == null)
            return result;

        result["Id"] = foo.Id;
        result["Name"] = foo.Name;
        result["Birthday"] = foo.Birthday.ToShortDateString();

        return result;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        return new Foo()
        {
            Id = (int) dictionary["Id"],
            Name = (string) dictionary["Name"],
            Birthday = DateTime.Parse(dictionary["Birthday"].ToString())
        };

    }
}

// Main method:
// …
 var js = new JavaScriptSerializer();
        js.RegisterConverters(new []{ new MyFooConverter() });
// ...

Output:

{"Id":1,"Name":"Bar","Birthday":"2/20/2012"}

Một Converter linh hoạt hơn

Sẽ rất bất tiện nếu như đối tượng bạn cần chuyển đối có quá nhiều property, việc override hai phương thức Serialize() và Deserialize() sẽ chiếm một số lượng code kha khá. Vì vậy, để giải quyết vấn đề này, tôi sẽ sử dụng reflection để tự động xây dựng một Dictionary từ đối tượng:

public class MyFooConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(Foo) }; }
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        if (obj == null)
            return new Dictionary<string, object>();

        var result = obj.GetType()
             .GetProperties()
             .ToDictionary(p => p.Name, p => p.GetValue(obj, null));

        result["Birthday"] = ((DateTime)result["Birthday"]).ToShortDateString();

        return result;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        return new Foo()
        {
            Id = (int) dictionary["Id"],
            Name = (string) dictionary["Name"],
            Birthday = DateTime.Parse(dictionary["Birthday"].ToString())
        };
    }
}

Đoạn mã trên chỉ là một ví dụ đơn giản về cách làm và nó cần phải cải tiến để có thể được cho mọi class. Bạn có thể gọi đây là một JsDateTimeConverter, nhưng dĩ nhiên bạn có thể thay đổi nó để chuyển đối cả các kiểu dữ liệu khác về định dạng JSON cần thiết. Đây mới thực sự là đoạn mã tôi muốn giới thiệu:

Một Generic Javascript Converter

Kết hợp generic, LINQ và reflection để giải quyết, tôi được đoạn mã sau:

public class MyJsConverter<T> : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(T) }; }
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        if (obj == null)
            return new Dictionary<string, object>();

        var result = obj.GetType()
             .GetProperties()
             .ToDictionary(p => p.Name,
                p => {
                 var value = p.GetValue(obj, null);
                 if (value.GetType() == typeof(DateTime))
                     value = ((DateTime)value).ToShortDateString();

                 return value;
                });

        return result;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        var foo = Activator.CreateInstance<T>();

        foreach (var property in type.GetProperties())
	    {
            var value = dictionary[property.Name];
            if (property.PropertyType == typeof(DateTime))
                value = DateTime.Parse(value.ToString());

            property.SetValue(foo,value,null);
	    }

        return foo;
    }
}

Khi đăng kí, bạn cần xác định rõ kiểu dữ liệu cần chuyển đổi, hoặc bạn cũng có thể tạo một class converter sử dụng kiểu object:

var js = new JavaScriptSerializer();
js.RegisterConverters(new []{new MyJsConverter()});

YinYang’s Programming Blog

Advertisements

14 thoughts on “ASP.NET – Serialize đối tượng .NET thành JSON và ngược lại

      • Nói về ví dụ thì giống như là mục đích của JSON để làm gì. Thường thì bạn muốn lấy dữ liệu từ các đối tượng dữ liệu gửi xuống client thì cần chuyển nó về json. Mình viết phần này khi phải thực hiện công việc đọc dữ liệu từ DataTable vào các object, rồi từ object đó có thể chuyển sang các định dạng khác nhau như JSON, XML, CSV,… để client có thể lấy và import vào dữ liệu của nó.

  1. Chào anh.
    Theo em biết thì XML có XML file và ngoài get data ra ta có đầy đủ các thao tác update, delete, create trên các node khá thuận tiện.
    Vậy Json này có Json file tương tự không và ta có được cung cấp các thao tác trên từng node không hay ta phải tự control ạ 😀

    Phản hồi
    • Việc sử dung Json (là một dữ liệu dạng chuỗi) chủ yếu là để truyền tải, lưu trữ. Nếu muốn thao tác thay đổi dữ liệu bạn có thể chuyển đổi nó thành đối tượng. Như thế nó vốn đã dễ dàng hơn nhiều so với sử dụng XML nên không cần thiết phải có các API thao tác trên chính Json.

      Phản hồi
  2. Pingback: ASP.NET – Serialize đối tượng .NET thành JSON và ngược lại – Mưa bay gió cuốn

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s