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

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

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

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

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

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

{ bar: '', oygevalt: '' }

В отличие от:

{ bar: '', oygevalt: '' }

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

public class MyClass {

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

    public bool AnyProperty { get; set; }
}

Выведет в качестве результата Json следующее:

{"AnyProperty ": false}

Ответ 4

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

Ответ 5

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