如何从ASP.NET MVC控制器方法返回由JSON.NET序列化的camelCase JSON?


246

我的问题是我希望通过ActionResult从ASP.NET MVC控制器方法(由JSON.NET序列化)中返回camelCased(与标准PascalCase相反)JSON数据。

作为示例,请考虑以下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"
}

我该怎么做呢?

Answers:


389

或者,简单地说:

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

2
但是,由于必须为每个控制器方法配置一个ContentResult,因此使用起来更加复杂。
aknuds1 2014年

2
是的,我知道您的答案是可重用的解决方案,我的意思是要使其更加清楚,它只是Serialize方法上的一个参数。
WebDever 2014年

1
如果要从Controller方法返回JSON ,则可能应该使用ApiController,在这种情况下,此答案非常有用。
西蒙·哈彻

1
@SimonHartcher但是考虑问题的范围,而不是一般情况。
aknuds1 2015年

1
JSON的有效内容类型为application/json,不是text/plain
弗雷德(Fred)

94

我在Mats Karlsson的博客中找到了解决此问题的绝佳方法。解决方案是编写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)};
}

3
完美答案:干净且可重复使用!谢谢。
桑德2015年

1
虽然此解决方案仍然有效。但建议4年前。我们有更好的解决方案吗?
SharpCoder

59

对于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();

4
Web API和MVC已合并到ASP.NET 6中
AlexFoxGill,2015年

1
链接方便;此设置与以下答案的配合非常好:stackoverflow.com/a/26068063/398630(不同的问题,但是我将它们一起使用,并且此链接可能会在以后为我和其他人省去一些麻烦)。
BrainSlugs83

37

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

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

2
抱歉,伙计们。我过快阅读了这篇文章。它用于
ASP.NET5。– Quantium

8
具有讽刺意味的是,我来这里是为了寻找您在此处回答的问题的答案,因此尽管它不是OP的问题的答案,但无论如何它对我都有帮助。谢谢!:)
porcus

1
我第二次@porcus说了什么!谢谢@Quantium!
Gromer '16

4
对于ASP.NET Core 1.0,默认情况下是驼峰式OOTB
Chris Marisic '16

3
事实证明,这毕竟不是(完全).NET Core 1.0的默认设置。此解决方案会影响动态属性,默认情况下不会影响这些属性。stackoverflow.com/questions/41329279/...
尼尔斯BRINCH

13

自定义过滤器的替代方法是创建一个扩展方法,以将任何对象序列化为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");

优雅而简单。
markau

1
您甚至可以将设置转移到静态只读字段,然后添加FromJson补码方法。
在巷子里的蒸气

8

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

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

6

以下是通过序列化对象数组返回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实例。这就是使camelCase发生的原因。


4

我确实这样:

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方法时都初始化一个新变量。
Ekus

4

您必须在文件“ 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(问题中的框架)却不正确。
Nate Barbettini

0

如果要在.net核心Web api或IHttpAction结果中返回ActionResult,则只需将模型包装在Ok()方法中,该方法将与前端的大小写匹配并为您序列化。无需使用JsonConvert。:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.