【问题标题】:How can I return camelCase JSON serialized by JSON.NET from ASP.NET MVC controller methods?如何从 ASP.NET MVC 控制器方法返回由 JSON.NET 序列化的 camelCase JSON?
【发布时间】:2013-10-27 01:33:51
【问题描述】:

我的问题是我希望通过ActionResults 从 ASP.NET MVC 控制器方法返回 camelCased(而不是标准 PascalCase)JSON 数据,由JSON.NET 序列化。

以下面的 C# 类为例:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

默认情况下,当从 MVC 控制器以 JSON 形式返回此类的实例时,它将按以下方式序列化:

{
  "FirstName": "Joe",
  "LastName": "Public"
}

我希望它被序列化(通过 JSON.NET)为:

{
  "firstName": "Joe",
  "lastName": "Public"
}

我该怎么做?

【问题讨论】:

    标签: asp.net-mvc json json.net camelcasing


    【解决方案1】:

    我在 Mats Karlsson 的 blog 上找到了解决此问题的绝佳方法。解决方案是编写一个 ActionResult 的子类,通过 JSON.NET 序列化数据,将后者配置为遵循 camelCase 约定:

    public class JsonCamelCaseResult : ActionResult
    {
        public JsonCamelCaseResult(object data, JsonRequestBehavior jsonRequestBehavior)
        {
            Data = data;
            JsonRequestBehavior = jsonRequestBehavior;
        }
    
        public Encoding ContentEncoding { get; set; }
    
        public string ContentType { get; set; }
    
        public object Data { get; set; }
    
        public JsonRequestBehavior JsonRequestBehavior { get; set; }
    
        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
            }
    
            var response = context.HttpContext.Response;
    
            response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
            if (ContentEncoding != null)
            {
                response.ContentEncoding = ContentEncoding;
            }
            if (Data == null)
                return;
    
            var jsonSerializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            response.Write(JsonConvert.SerializeObject(Data, jsonSerializerSettings));
        }
    }
    

    然后在你的 MVC 控制器方法中使用这个类,如下所示:

    public ActionResult GetPerson()
    {
        return new JsonCamelCaseResult(new Person { FirstName = "Joe", LastName = "Public" }, JsonRequestBehavior.AllowGet)};
    }
    

    【讨论】:

    • 完美答案:干净且可重复使用!谢谢。
    • 虽然这个解决方案仍然有效。但这是 4 年前提出的。我们有更好的解决方案吗?
    • @SharpCoder 现在,3 年后,你有没有找到更好的选择?
    • @DARKGuy:没有调查。 :(
    【解决方案2】:

    或者,简单地说:

    JsonConvert.SerializeObject(
        <YOUR OBJECT>, 
        new JsonSerializerSettings 
        { 
            ContractResolver = new CamelCasePropertyNamesContractResolver() 
        });
    

    例如:

    return new ContentResult
    {
        ContentType = "application/json",
        Content = JsonConvert.SerializeObject(new { content = result, rows = dto }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }),
        ContentEncoding = Encoding.UTF8
    };
    

    【讨论】:

    • 这使用起来更复杂,因为您必须为每个控制器方法配置一个 ContentResult。
    • 是的,我知道您的回答是一个可重复使用的解决方案,我的意思是更清楚地说明它只是 Serialize 方法的一个参数。
    • 如果您从 Controller 方法返回 JSON,您可能应该使用 ApiController,在这种情况下这个答案很有效。
    • @SimonHartcher 考虑问题的范围,而不是一般情况。
    • JSON 的有效内容类型是 application/json,而不是 text/plain
    【解决方案3】:

    下面是一个action方法,通过序列化一个对象数组返回一个json字符串(cameCase)。

    public string GetSerializedCourseVms()
        {
            var courses = new[]
            {
                new CourseVm{Number = "CREA101", Name = "Care of Magical Creatures", Instructor ="Rubeus Hagrid"},
                new CourseVm{Number = "DARK502", Name = "Defence against dark arts", Instructor ="Severus Snape"},
                new CourseVm{Number = "TRAN201", Name = "Transfiguration", Instructor ="Minerva McGonal"}
            };
            var camelCaseFormatter = new JsonSerializerSettings();
            camelCaseFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
            return JsonConvert.SerializeObject(courses, camelCaseFormatter);
        }
    

    注意作为第二个参数传递的 JsonSerializerSettings 实例。这就是骆驼案发生的原因。

    【讨论】:

      【解决方案4】:

      对于 WebAPI,请查看此链接: http://odetocode.com/blogs/scott/archive/2013/03/25/asp-net-webapi-tip-3-camelcasing-json.aspx

      基本上,将此代码添加到您的Application_Start

      var formatters = GlobalConfiguration.Configuration.Formatters;
      var jsonFormatter = formatters.JsonFormatter;
      var settings = jsonFormatter.SerializerSettings;
      settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
      

      【讨论】:

      • Web API 和 MVC 已在 ASP.NET 6 中合并
      • 链接方便;此设置与此答案非常吻合:stackoverflow.com/a/26068063/398630(不同的问题,但我将它们一起使用,此链接可能会在将来为我和其他人节省一些谷歌搜索)。
      【解决方案5】:

      我认为这是您正在寻找的简单答案。来自Shawn Wildermuth的博客:

      // Add MVC services to the services container.
      services.AddMvc()
        .AddJsonOptions(opts =>
        {
          opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        });
      

      【讨论】:

      • 抱歉,伙计们。我读完这篇文章太快了。它适用于 ASP.NET 5。
      • 具有讽刺意味的是,我来这里是为了寻找您在此处回答的问题的答案,因此虽然这不是 OP 问题的答案,但无论如何它对我有所帮助。谢谢! :)
      • 我赞同@porcus 所说的!谢谢@Quantium!
      • fyi 对于 ASP.NET Core 1.0,默认情况下是驼峰式 OOTB
      • 事实证明这毕竟不是 .NET Core 1.0 的默认设置。此解决方案影响动态属性,默认情况下不受影响。 stackoverflow.com/questions/41329279/…
      【解决方案6】:

      自定义过滤器的替代方法是创建一个扩展方法来将任何对象序列化为 JSON。

      public static class ObjectExtensions
      {
          /// <summary>Serializes the object to a JSON string.</summary>
          /// <returns>A JSON string representation of the object.</returns>
          public static string ToJson(this object value)
          {
              var settings = new JsonSerializerSettings
              {
                  ContractResolver = new CamelCasePropertyNamesContractResolver(),
                  Converters = new List<JsonConverter> { new StringEnumConverter() }
              };
      
              return JsonConvert.SerializeObject(value, settings);
          }
      }
      

      然后在从控制器动作返回时调用它。

      return Content(person.ToJson(), "application/json");
      

      【讨论】:

      • 优雅简洁。
      • 您甚至可以将设置转移到静态只读字段并添加 FromJson 补码方法。
      【解决方案7】:

      在 ASP.NET Core MVC 中。

          public IActionResult Foo()
          {
              var data = GetData();
      
              var settings = new JsonSerializerSettings 
              { 
                  ContractResolver = new CamelCasePropertyNamesContractResolver() 
              });
      
              return Json(data, settings);
          }
      

      【讨论】:

      • 更好的是,将它放在 Startup.cs 文件中。
      • @FatAlbert 是的,但是怎么样?
      • @DARKGuy 请参阅 Daniel Sánchez 对此问题的回答,stackoverflow.com/a/57277621/1076993
      【解决方案8】:

      我确实喜欢这样:

      public static class JsonExtension
      {
          public static string ToJson(this object value)
          {
              var settings = new JsonSerializerSettings
              {
                  ContractResolver = new CamelCasePropertyNamesContractResolver(),
                  NullValueHandling = NullValueHandling.Ignore,
                  ReferenceLoopHandling = ReferenceLoopHandling.Serialize
              };
              return JsonConvert.SerializeObject(value, settings);
          }
      }
      

      这是 MVC 核心中的一个简单扩展方法,它将为项目中的每个对象赋予 ToJson() 能力,在我看来,在 MVC 项目中,大多数对象应该具有成为 json 的能力,当然这取决于:)

      【讨论】:

      • 考虑在方法外提取“settings”变量(作为私有静态字段“camelCaseSettings”),这样就不会在每次调用ToJson方法时都初始化一个新变量。
      【解决方案9】:

      IMO 越简单越好!

      你为什么不这样做?

      public class CourseController : JsonController
      {
          public ActionResult ManageCoursesModel()
          {
              return JsonContent(<somedata>);
          }
      }
      

      简单的基类控制器

      public class JsonController : BaseController
      {
          protected ContentResult JsonContent(Object data)
          {
              return new ContentResult
              {
                  ContentType = "application/json",
                   Content = JsonConvert.SerializeObject(data, new JsonSerializerSettings { 
                    ContractResolver = new CamelCasePropertyNamesContractResolver() }),
                  ContentEncoding = Encoding.UTF8
              };
          }
      }
      

      【讨论】:

      • 我认为控制器应该与序列化无关。现在我们必须为N 序列化选项提供N 控制器。最好使用基于请求序列化的策略
      【解决方案10】:

      您必须在“Startup.cs”文件中进行设置

      你还必须在JsonConvert的默认值中定义它,这是如果你以后想直接使用库来序列化一个对象。

          public void ConfigureServices(IServiceCollection services)
          {
              services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                  .AddJsonOptions(options => {
                      options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                      options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                  });
              JsonConvert.DefaultSettings = () => new JsonSerializerSettings
              {
                  NullValueHandling = NullValueHandling.Ignore,
                  ContractResolver = new CamelCasePropertyNamesContractResolver()
              };
          }
      

      【讨论】:

      • 请注意,这个答案对于 ASP.NET Core 是正确的,但对于 ASP.NET(这是问题中的框架)是正确的。
      【解决方案11】:

      如果您在 .net core web api 中返回 ActionResult 或 IHttpAction 结果,那么您只需将模型包装在 Ok() 方法中,该方法将匹配您前端的案例并为您序列化它。无需使用 JsonConvert。 :)

      【讨论】:

        【解决方案12】:

        将 Json NamingStrategy 属性添加到您的类定义中。

        [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
        public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        【讨论】:

        • 又好又简单:)
        【解决方案13】:

        安装包 Microsoft.AspNetCore.Mvc.NewtonsoftJson

        这解决了我的问题

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-08-19
          • 1970-01-01
          • 2017-05-18
          • 1970-01-01
          • 2017-01-17
          • 2013-02-01
          • 1970-01-01
          相关资源
          最近更新 更多