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

Есть ли способ контролировать вывод JSON JsonResult с атрибутами, похожими на то, как вы можете использовать XmlElementAttribute и его контроль над выводом сериализации XML?

Например, дан следующий класс:

public class Foo
{
    [SomeJsonSerializationAttribute("bar")]
    public String Bar { get; set; }

    [SomeJsonSerializationAttribute("oygevalt")]
    public String Oygevalt { get; set; }
}

Я хотел бы получить следующий вывод:

{ bar: '', oygevalt: '' }

В отличие от:

{ Bar: '', Oygevalt: '' }

5 ответов

Решение

Я хотел что-то более запеченное в рамках, чем предлагал Джарретт, так что вот что я сделал:

JsonDataContractActionResult:

public class JsonDataContractActionResult : ActionResult
{
    public JsonDataContractActionResult(Object data)
    {
        this.Data = data;
    }

    public Object Data { get; private set; }

    public override void ExecuteResult(ControllerContext context)
    {
        var serializer = new DataContractJsonSerializer(this.Data.GetType());
        String output = String.Empty;
        using (var ms = new MemoryStream())
        {
            serializer.WriteObject(ms, this.Data);
            output = Encoding.Default.GetString(ms.ToArray());
        }
        context.HttpContext.Response.ContentType = "application/json";
        context.HttpContext.Response.Write(output);
    }
}

Метод JsonContract(), добавленный в мой базовый класс контроллера:

    public ActionResult JsonContract(Object data)
    {
        return new JsonDataContractActionResult(data);
    }

Пример использования:

    public ActionResult Update(String id, [Bind(Exclude="Id")] Advertiser advertiser)
    {
        Int32 advertiserId;
        if (Int32.TryParse(id, out advertiserId))
        {
            // update
        }
        else
        {
            // insert
        }

        return JsonContract(advertiser);
    }

Примечание. Если вы ищете что-то более производительное, чем JsonDataContractSerializer, вы можете сделать то же самое, используя вместо этого JSON.NET. Хотя JSON.NET, по-видимому, не использует DataMemberAttribute, у него есть собственный JsonPropertyAttribute, который можно использовать для достижения той же цели.

Вот моя реализация ответа Дэниела Шаффера, с предложенными улучшениями Джастина Русбэтча и Дэниела.

using System;
using System.Runtime.Serialization.Json;
using System.Web.Mvc;

public class JsonDataContractActionResult : JsonResult
{
    public JsonDataContractActionResult( Object data )
    {
        this.Data = data;
    }

    public override void ExecuteResult( ControllerContext context )
    {
        var serializer = new DataContractJsonSerializer( this.Data.GetType() );
        context.HttpContext.Response.ContentType = "application/json";
        serializer.WriteObject( context.HttpContext.Response.OutputStream, 
            this.Data );
    }
}

Это решение использовать 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 для каждого свойства, которое вы хотите сериализовать.

Я знаю, что это старый вопрос, но для тех, кто ищет только то, как избежать сериализации свойств, используйте ScriptIgnoreAttribute в пространстве имен System.Web.Script.Serialization. К сожалению, все еще не может контролировать имя сериализованных свойств, но кто-то может найти это полезным.

public class MyClass {

    [ScriptIgnoreAttribute]
    public bool PropertyNotSerialized { get; set; }

    public bool AnyProperty { get; set; }
}

Будет выводить как Json результат следующее:

{"AnyProperty ": false}

Простой ответ: DataContractJsonSerializer должен уважать [DataContract] а также [DataMember] атрибуты в пространстве имен System.Runtime.Serialization в BCL.

Эти ответы были мне полезны, но, подойдя к этой проблеме на несколько лет позже, чем все остальные, я обнаружил, что этот код не работает с текущей версией фреймворка. Эта версия работает с Newtonsoft.Json и ASP NET Core 3.1:

/*
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
*/
public class JsonDataContractActionResult : IActionResult
{
    public JsonDataContractActionResult(object data) 
    {
        this.Data = data;
    }

    public object Data { get; private set; }

    public async Task ExecuteResultAsync(ActionContext context)
    {
        context.HttpContext.Response.ContentType = "application/json";
        JsonSerializer serializer = new JsonSerializer();
        serializer.NullValueHandling = NullValueHandling.Ignore;
        using (MemoryStream ms = new MemoryStream()) {
            using (StreamWriter sw = new StreamWriter(ms))
            {
                using (JsonWriter writer = new JsonTextWriter(sw))
                {
                    serializer.Serialize(writer, Data);
                }
            }
            byte[] b = ms.ToArray();
            await context.HttpContext.Response.Body.WriteAsync(b);
        }
    }
}
Другие вопросы по тегам