【问题标题】:ASP.NET MVC: Controlling serialization of property names with JsonResultASP.NET MVC:使用 JsonResult 控制属性名称的序列化
【发布时间】:2009-08-19 22:22:33
【问题描述】:

有没有办法用属性控制JsonResult的JSON输出,类似于你可以使用XmlElementAttribute及其兄弟来控制XML序列化的输出?

例如,给定以下类:

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

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

然后我想得到以下输出:

{ bar: '', oygevalt: '' }

相对于:

{ Bar: '', Oygevalt: '' }

【问题讨论】:

标签: asp.net-mvc json serialization


【解决方案1】:

我想要在框架中加入一些比 Jarrett 建议的更深入的东西,所以我做了以下事情:

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 可以用来完成同样的事情。

【讨论】:

  • MVC 最棒的地方在于编写这些东西是多么容易。您可以很快将一些非常复杂的解决方案组合在一起!
  • 确实如此!我不打算回顾 WebForms。
  • 非常好的解决方案! JsonDataContractActionResult 类可以进一步简化,如果你从 JsonResult 继承而不是基 ActionResult - 那么你只需要重写 ExecuteResult 方法!
  • 我可能会遗漏一些东西,但我认为内存流不是必需的。您可以直接写入响应输出流:serializer.WriteObject(context.HttpContext.Response.OutputStream, Data);我已经尝试过了,它似乎工作正常......
【解决方案2】:

这是我对 Daniel Schaffer 答案的实施,其中包含 Justin Rusbatch 和 Daniel 提出的改进建议。

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

【讨论】:

  • +1 - 据我所知,DataContractJsonSerializer 在 MVC 4 中仍然不直接支持,所以这是一个优雅的解决方案。
【解决方案3】:

这是使用 NewtonSoft Json.Net 的解决方案(为了性能) 我找到了部分解决方案 here 和 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 设置为要序列化的每个属性。

【讨论】:

    【解决方案4】:

    我知道这是一个老问题,但对于那些正在寻找如何避免属性被序列化的人来说,请使用命名空间 System.Web.Script.Serialization 中的 ScriptIgnoreAttribute。遗憾的是仍然无法控制序列化属性的名称,但有人可能会觉得这很有帮助。

    public class MyClass {
    
        [ScriptIgnoreAttribute]
        public bool PropertyNotSerialized { get; set; }
    
        public bool AnyProperty { get; set; }
    }
    

    将输出为 Json 结果如下:

    {"AnyProperty ": false}
    

    【讨论】:

    • 我可以确认这是可行的。此命名空间位于 System.Web.Extensions 程序集中。
    【解决方案5】:

    简单的回答:DataContractJsonSerializer 应该尊重 BCL 的 System.Runtime.Serialization 命名空间中的 [DataContract][DataMember] 属性。

    【讨论】:

    • 为了让那些不知道的人清楚,Nate 表达的是 MVC 的 -desired- 行为,而不是当今 MVC 的 -actual- 行为。从 MVC2 开始,MVC 使用 JavaScriptSerializer,它不支持 WCF DataContract 序列化程序支持的 DataMember 属性。今天需要一个自定义的 ActionResult 来使 MVC 使用 DataContract/DataMember 属性。
    【解决方案6】:

    这些答案对我很有帮助,但是比其他所有人晚几年才遇到这个问题,我发现这段代码不适用于当前的框架版本。此版本适用于 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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      • 1970-01-01
      • 2011-08-28
      • 2013-10-09
      相关资源
      最近更新 更多