Подтвердить что ты не робот

MVC3 JSON Сериализация: как управлять именами свойств?

Я хочу сериализовать простой объект в JSON:

public class JsonTreeNode
{
    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "isFolder")]
    public bool IsFolder { get; set; }

    [DataMember(Name = "key")]
    public string Key { get; set; }

    [DataMember(Name = "children")]
    public IEnumerable<JsonTreeNode> Children { get; set; }

    [DataMember(Name = "select")]
    public bool SelectedOnInit { get; set; }
}

Но всякий раз, когда я это делаю:

return Json(tree, JsonRequestBehavior.AllowGet);

Имена свойств не указаны в разделе [DataMember], но аналогичны именам, определенным непосредственно в классе, например. в случае SelectOnInit это не select, а SelectOnInit.

Что я делаю неправильно?

4b9b3361

Ответ 1

Я решил проблему, используя технику, представленную в ответе в этом вопросе:

ASP.NET MVC: управление сериализацией имен свойств с помощью JsonResult

Вот класс, который я сделал:

/// <summary>
/// Similiar to <see cref="JsonResult"/>, with
/// the exception that the <see cref="DataContract"/> attributes are
/// respected.
/// </summary>
/// <remarks>
/// Based on the excellent stackoverflow answer:
/// https://stackoverflow.com/a/263416/1039947
/// </remarks>
public class JsonDataContractActionResult : ActionResult
{
    /// <summary>
    /// Initializes a new instance of the class.
    /// </summary>
    /// <param name="data">Data to parse.</param>
    public JsonDataContractActionResult(Object data)
    {
        Data = data;
    }

    /// <summary>
    /// Gets or sets the data.
    /// </summary>
    public Object Data { get; private set; }

    /// <summary>
    /// Enables processing of the result of an action method by a 
    /// custom type that inherits from the ActionResult class. 
    /// </summary>
    /// <param name="context">The controller context.</param>
    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        var serializer = new DataContractJsonSerializer(Data.GetType());

        string output;
        using (var ms = new MemoryStream())
        {
            serializer.WriteObject(ms, Data);
            output = Encoding.UTF8.GetString(ms.ToArray());
        }

        context.HttpContext.Response.ContentType = "application/json";
        context.HttpContext.Response.Write(output);
    }
}

Использование:

    public ActionResult TestFunction()
    {
        var testObject = new TestClass();
        return new JsonDataContractActionResult(testObject);
    }

Мне также пришлось изменить исходный класс:

// -- The DataContract property was added --
[DataContract]
public class JsonTreeNode
{
    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "isFolder")]
    public bool IsFolder { get; set; }

    [DataMember(Name = "key")]
    public string Key { get; set; }

    [DataMember(Name = "children")]
    public IEnumerable<JsonTreeNode> Children { get; set; }

    [DataMember(Name = "select")]
    public bool SelectedOnInit { get; set; }
}

Ответ 2

Это решение, которое использует newtonsoft Json.net(для обеспечения производительности)

Я нашел часть решения здесь и на SO

public class JsonNetResult : ActionResult
    {
        public Encoding ContentEncoding { get; set; }
        public string ContentType { get; set; }
        public object Data { get; set; }

        public JsonSerializerSettings SerializerSettings { get; set; }
        public Formatting Formatting { get; set; }

        public JsonNetResult(object data, Formatting formatting)
            : this(data)
        {
            Formatting = formatting;
        }

        public JsonNetResult(object data):this()
        {
            Data = data;
        }

        public JsonNetResult()
        {
            Formatting = Formatting.None;
            SerializerSettings = new JsonSerializerSettings();
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            var response = context.HttpContext.Response;
            response.ContentType = !string.IsNullOrEmpty(ContentType)
              ? ContentType
              : "application/json";
            if (ContentEncoding != null)
                response.ContentEncoding = ContentEncoding;

            if (Data == null) return;

            var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
            var serializer = JsonSerializer.Create(SerializerSettings);
            serializer.Serialize(writer, Data);
            writer.Flush();
        }
    }

Так что в моем контроллере я могу это сделать

        return new JsonNetResult(result);

В моей модели теперь я могу:

    [JsonProperty(PropertyName = "n")]
    public string Name { get; set; }

Обратите внимание, что теперь вы должны установить JsonPropertyAttribute для каждого свойства, которое вы хотите сериализовать.