MVC 4中正确的JSON序列化

47

我希望能够以“正确的方式”(驼峰命名法)对JSON进行序列化,并且如有必要,能够更改日期格式。

对于Web API来说,非常容易 - 在Global.asax文件中执行以下代码即可:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

在管道级别,这段代码处理序列化的方式是我想要的。

我希望在MVC 4中实现相同的功能 - 让控制器操作方法返回的任何JSON都能得到正确的序列化。通过一点搜索,我找到了以下代码可以添加到Global.asax应用启动中:

HttpConfiguration config = GlobalConfiguration.Configuration;
Int32 index = config.Formatters.IndexOf(config.Formatters.JsonFormatter);
config.Formatters[index] = new JsonMediaTypeFormatter
{
     SerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }
};

代码看起来执行得很好,但是从控制器返回JSON时会全都变成PascalCased。这是我的一个action方法的简单示例:

private JsonResult GetJsonTest()
{
    var returnData = dataLayer.GetSomeObject();
    return Json(returnData, JsonRequestBehavior.AllowGet);
}

我这样做错了吗?有什么方法可以在管道级别上完成这个任务吗?


我没有意识到 JSON 规范需要使用驼峰命名法... - evanmcdonnal
3
据我理解,采用驼峰式命名的JSON更为通用,不这样做可能会破坏框架。此外,我们的开发标准也明确规定了这一点,所以我也在这么做。 - Mario
不应该从API返回数据对象。最好创建模型/服务契约/等等并返回它们。问题不仅在于潜在的数据泄漏,而且还存在将API客户端依赖于内部数据对象的高风险。如果有人重命名数据属性,那么您的UI就会出现问题。 - user3285954
4个回答

93

我建议在您的MVC应用程序中处理Json输出时使用类似ServiceStack或Json.NET的工具。但是,您可以轻松地编写一个类并使用基类覆盖Json方法。请参考我的以下示例。

注意:使用此方法,您不需要在Global.ascx.cs文件中添加任何内容。

自定义JsonDotNetResult类:

public class JsonDotNetResult : JsonResult
{
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        Converters = new List<JsonConverter> { new StringEnumConverter() }
    };

    public override void ExecuteResult(ControllerContext context)
    {
        if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
            string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("GET request not allowed");
        }

        var response = context.HttpContext.Response;

        response.ContentType = !string.IsNullOrEmpty(this.ContentType) ? this.ContentType : "application/json";

        if (this.ContentEncoding != null)
        {
            response.ContentEncoding = this.ContentEncoding;
        }

        if (this.Data == null)
        {
            return;
        }

        response.Write(JsonConvert.SerializeObject(this.Data, Settings));
    }
}

基础控制器类:

public abstract class Controller : System.Web.Mvc.Controller
{
    protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonDotNetResult
            {
                Data = data,
                ContentType = contentType,
                ContentEncoding = contentEncoding,
                JsonRequestBehavior = behavior
            };
    }
}

现在,在您的控制器动作中,您可以简单地返回类似以下内容的东西。

return Json(myObject, JsonRequestBehavior.AllowGet);

BAM. 现在你可以返回带有 Json 的驼峰式对象 :)

注意:你可以使用每个 Json 对象的序列化设置来完成此操作。但是,谁想每次返回 Json 都要打出这些字?


6
虽然Web API使用JSON.NET,但MVC4默认使用JavaScriptSerializer,我认为它不支持更改为驼峰式序列化。请参考此链接:在ASP.NET MVC中设置默认JSON序列化器 我的建议是按照这里所述创建自定义的JsonNetResult:在ASP.NET MVC 3中使用JSON.NET作为默认的JSON序列化器 - 是否可能?并将最后一行更改为:
var serializedObject = JsonConvert.SerializeObject(
      Data,
      Formatting.Indented,
      new JsonSerializerSettings { MappingResolver = new CamelCaseMappingResolver() });

5
Note that below information is for Asp .Net core

.Net团队最近宣布,MVC现在默认使用骆驼命名法来序列化JSON。

以下几行代码可以启用这个功能:

services
.AddMvc()
.AddJsonOptions(options =>
options.SerializerSettings.ContractResolver = new DefaultContractResolver());

我写了一篇博客,内容与在MVC中使用驼峰式JSON相关。


3
是的,但它是为aspnet core设计的。 - Thomas

1
你可以创建一个静态方法来返回一个ContentResult,该方法利用NewtonSoft.Json库进行序列化,类似于以下内容:
public static ContentResult CamelJson<TData>(TData response)
{
    DefaultContractResolver resolver = new CamelCasePropertyNamesContractResolver();
    JsonSerializerSettings settings = new JsonSerializerSettings
    {
        ContractResolver = resolver,
        DateFormatHandling = DateFormatHandling.IsoDateFormat
    };
    return new ContentResult
    {
        Content = JsonConvert.SerializeObject(response, settings),
        ContentType = "application/json"
    };
}

使用示例:

[HttpGet]
public ContentResult GetCamelCaseJsonData()
{
  return ContentUtils.CamelJson(result);
}

输出将为驼峰式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接