2013-10-18 21 views
139

我的問題是,我希望通過ActionResult從ASP.NET MVC控制器方法返回camelCased(而不是標準PascalCase)JSON數據,由JSON.NET序列化。如何返回由ASP.NET MVC控制器方法JSON.NET序列化的camelCase 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" 
} 

如何我要這樣做嗎?

回答

79

我在Mats Karlsson的blog上發現了一個很好的解決方案。解決的辦法是寫的ActionResult的子類,經由JSON.NET串行化數據,配置後者遵循駝峯約定:

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

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的控制器方法如下使用這個類

+3

完美答案:乾淨且可重複使用!謝謝。 – sander

+0

儘管此解決方案仍在工作。但4年前就有人提出這個建議。我們有更好的解決方案嗎? – SharpCoder

215

,或者簡單地說:

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

+2

是的,我明白你的答案是一個可重用的解決方案,我的觀點是更清楚地表明它只是Serialize方法中的一個參數。 – WebDever

+0

不,這是錯過了大圖,這是從控制器方法返回駝峯數據。 – aknuds1

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實例作爲第二個參數傳遞。這就是駱駝發生的原因。

44

對於的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

+0

鏈接爲了方便;這個設置非常適合這個答案:http://stackoverflow.com/a/26068063/398630(不同的問題,但我一起使用它們,這個鏈接可能會節省我和其他人在未來一些谷歌搜索)。 – BrainSlugs83

22

我認爲這是你正在尋找簡單的答案。這是一個從Shawn Wildermuth的博客:

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

這是Asp.Net 5. –

+1

我的道歉,夥計。我太快閱讀了這篇文章。它是用於ASP.NET 5的。 – Quantium

+8

具有諷刺意味的是,我來到這裏尋找你在這裏回答的問題的答案,所以儘管這不是OP問題的答案,但它無論如何都幫助了我。謝謝! :) – porcus

5

到自定義過濾器的替代方案是創建一個擴展方法序列化任何對象以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"); 
+0

優雅而簡單。 – markau

7

在ASP.NET Core MVC中。

public IActionResult Foo() 
    { 
     var data = GetData(); 

     var settings = new JsonSerializerSettings 
     { 
      ContractResolver = new CamelCasePropertyNamesContractResolver() 
     }); 

     return Json(data, settings); 
    } 
+0

甚至更​​好,把它放在Startup.cs文件中。 – FatAlbert

相關問題