Web API 2: 如何 return JSON with camelCased 属性 names, on objects and their sub-objects
Web API 2: how to return JSON with camelCased property names, on objects and their sub-objects
更新
谢谢大家的回答。我在一个新项目上,看起来我终于弄清楚了这个问题:看起来实际上是以下代码造成的:
public static HttpResponseMessage GetHttpSuccessResponse(object response, HttpStatusCode code = HttpStatusCode.OK)
{
return new HttpResponseMessage()
{
StatusCode = code,
Content = response != null ? new JsonContent(response) : null
};
}
别处...
public JsonContent(object obj)
{
var encoded = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore } );
_value = JObject.Parse(encoded);
Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
我忽略了看起来无害的 JsonContent,假设它是 WebAPI 但不是。
这无处不在...我可以第一个说吗?或者也许应该是 "Why are they doing this?"
原问题如下
有人会认为这将是一个简单的配置设置,但我已经想了太久了。
我看了各种解决方案和答案:
https://gist.github.com/rdingwall/2012642
似乎不适用于最新的 WebAPI 版本...
以下似乎不起作用 - 属性 名称仍然是 PascalCased。
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Mayank 在这里的回答:CamelCase JSON WebAPI Sub-Objects (Nested objects, child objects) 似乎是一个不令人满意但可行的答案,直到我意识到这些属性必须添加到生成的代码中,因为我们正在使用 linq2sql...
有什么方法可以自动执行此操作?这个 'nasty' 困扰我很久了。
原来是
return Json(result);
是罪魁祸首,导致序列化过程忽略驼峰式设置。还有那个
return Request.CreateResponse(HttpStatusCode.OK, result, Request.GetConfiguration());
是我要找的机器人。
还有
json.UseDataContractJsonSerializer = true;
在工作中放了一把扳手,结果发现这不是我要找的机器人。
把它们放在一起你会得到...
protected void Application_Start()
{
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
}
这对我有用:
internal static class ViewHelpers
{
public static JsonSerializerSettings CamelCase
{
get
{
return new JsonSerializerSettings {
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
}
}
}
然后:
[HttpGet]
[Route("api/campaign/list")]
public IHttpActionResult ListExistingCampaigns()
{
var domainResults = _campaignService.ListExistingCampaigns();
return Json(domainResults, ViewHelpers.CamelCase);
}
class CamelCasePropertyNamesContractResolver
来自 Json.NET 库中的 Newtonsoft.Json.dll
。
以上所有答案都不适用于 Owin Hosting 和 Ninject。以下是对我有用的方法:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
// Get the ninject kernel from our IoC.
var kernel = IoC.GetKernel();
var config = new HttpConfiguration();
// More config settings and OWIN middleware goes here.
// Configure camel case json results.
ConfigureCamelCase(config);
// Use ninject middleware.
app.UseNinjectMiddleware(() => kernel);
// Use ninject web api.
app.UseNinjectWebApi(config);
}
/// <summary>
/// Configure all JSON responses to have camel case property names.
/// </summary>
private void ConfigureCamelCase(HttpConfiguration config)
{
var jsonFormatter = config.Formatters.JsonFormatter;
// This next line is not required for it to work, but here for completeness - ignore data contracts.
jsonFormatter.UseDataContractJsonSerializer = false;
var settings = jsonFormatter.SerializerSettings;
#if DEBUG
// Pretty json for developers.
settings.Formatting = Formatting.Indented;
#else
settings.Formatting = Formatting.None;
#endif
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
主要区别在于:new HttpConfiguration() 而不是 GlobalConfiguration.Configuration。
这是一个晦涩的例子,当路由属性不匹配 GET url 但 GET url 匹配方法名称时,jsonserializer 驼峰指令将被忽略,例如
//uppercase fail cakes
[HttpGet]
[Route("countries")]
public async Task<GeoData> GeoData()
{
return await geoService.GetGeoData();
}
//lowercase nomnomnom cakes
[HttpGet]
[Route("geodata")]
public async Task<GeoData> GeoData()
{
return await geoService.GetGeoData();
}
WebApiConfig 代码:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//This line sets json serializer's ContractResolver to CamelCasePropertyNamesContractResolver,
// so API will return json using camel case
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
确保您的 API 操作方法 returns 数据符合以下方式,并且您已安装最新版本的 Json.Net/Newtonsoft.Json:
[HttpGet]
public HttpResponseMessage List()
{
try
{
var result = /*write code to fetch your result - type can be anything*/;
return Request.CreateResponse(HttpStatusCode.OK, result);
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
}
}
我已经通过以下方式解决了
[AllowAnonymous]
[HttpGet()]
public HttpResponseMessage GetAllItems(int moduleId)
{
HttpConfiguration config = new HttpConfiguration();
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
try
{
List<ItemInfo> itemList = GetItemsFromDatabase(moduleId);
return Request.CreateResponse(HttpStatusCode.OK, itemList, config);
}
catch (System.Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
}
}
我将 WebApi 与 Breeze 一起使用,我 运行 在尝试对 breeze 控制器执行 non-breeze 操作时遇到同样的问题。我尝试使用 apprach Request.GetConfiguration 但结果相同。因此,当我访问 Request.GetConfiguration 返回的 object 时,我意识到请求使用的序列化程序是 breeze-server 用来使其变得神奇的序列化程序。无论如何,我通过创建不同的 HttpConfiguration:
解决了我的问题
public static HttpConfiguration BreezeControllerCamelCase
{
get
{
var config = new HttpConfiguration();
var jsonSerializerSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
return config;
}
}
并将其作为参数传递给 Request.CreateResponse,如下所示:
return this.Request.CreateResponse(HttpStatusCode.OK, result, WebApiHelper.BreezeControllerCamelCase);
在您的 Owin Startup 中添加此行...
public class Startup
{
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = ConfigureWebApi();
app.UseWebApi(webApiConfiguration);
}
private HttpConfiguration ConfigureWebApi()
{
var config = new HttpConfiguration();
// ADD THIS LINE HERE AND DONE
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.MapHttpAttributeRoutes();
return config;
}
}
更新
谢谢大家的回答。我在一个新项目上,看起来我终于弄清楚了这个问题:看起来实际上是以下代码造成的:
public static HttpResponseMessage GetHttpSuccessResponse(object response, HttpStatusCode code = HttpStatusCode.OK)
{
return new HttpResponseMessage()
{
StatusCode = code,
Content = response != null ? new JsonContent(response) : null
};
}
别处...
public JsonContent(object obj)
{
var encoded = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore } );
_value = JObject.Parse(encoded);
Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
我忽略了看起来无害的 JsonContent,假设它是 WebAPI 但不是。
这无处不在...我可以第一个说吗?或者也许应该是 "Why are they doing this?"
原问题如下
有人会认为这将是一个简单的配置设置,但我已经想了太久了。
我看了各种解决方案和答案:
https://gist.github.com/rdingwall/2012642
似乎不适用于最新的 WebAPI 版本...
以下似乎不起作用 - 属性 名称仍然是 PascalCased。
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Mayank 在这里的回答:CamelCase JSON WebAPI Sub-Objects (Nested objects, child objects) 似乎是一个不令人满意但可行的答案,直到我意识到这些属性必须添加到生成的代码中,因为我们正在使用 linq2sql...
有什么方法可以自动执行此操作?这个 'nasty' 困扰我很久了。
原来是
return Json(result);
是罪魁祸首,导致序列化过程忽略驼峰式设置。还有那个
return Request.CreateResponse(HttpStatusCode.OK, result, Request.GetConfiguration());
是我要找的机器人。
还有
json.UseDataContractJsonSerializer = true;
在工作中放了一把扳手,结果发现这不是我要找的机器人。
把它们放在一起你会得到...
protected void Application_Start()
{
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
}
这对我有用:
internal static class ViewHelpers
{
public static JsonSerializerSettings CamelCase
{
get
{
return new JsonSerializerSettings {
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
}
}
}
然后:
[HttpGet]
[Route("api/campaign/list")]
public IHttpActionResult ListExistingCampaigns()
{
var domainResults = _campaignService.ListExistingCampaigns();
return Json(domainResults, ViewHelpers.CamelCase);
}
class CamelCasePropertyNamesContractResolver
来自 Json.NET 库中的 Newtonsoft.Json.dll
。
以上所有答案都不适用于 Owin Hosting 和 Ninject。以下是对我有用的方法:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
// Get the ninject kernel from our IoC.
var kernel = IoC.GetKernel();
var config = new HttpConfiguration();
// More config settings and OWIN middleware goes here.
// Configure camel case json results.
ConfigureCamelCase(config);
// Use ninject middleware.
app.UseNinjectMiddleware(() => kernel);
// Use ninject web api.
app.UseNinjectWebApi(config);
}
/// <summary>
/// Configure all JSON responses to have camel case property names.
/// </summary>
private void ConfigureCamelCase(HttpConfiguration config)
{
var jsonFormatter = config.Formatters.JsonFormatter;
// This next line is not required for it to work, but here for completeness - ignore data contracts.
jsonFormatter.UseDataContractJsonSerializer = false;
var settings = jsonFormatter.SerializerSettings;
#if DEBUG
// Pretty json for developers.
settings.Formatting = Formatting.Indented;
#else
settings.Formatting = Formatting.None;
#endif
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
主要区别在于:new HttpConfiguration() 而不是 GlobalConfiguration.Configuration。
这是一个晦涩的例子,当路由属性不匹配 GET url 但 GET url 匹配方法名称时,jsonserializer 驼峰指令将被忽略,例如
//uppercase fail cakes
[HttpGet]
[Route("countries")]
public async Task<GeoData> GeoData()
{
return await geoService.GetGeoData();
}
//lowercase nomnomnom cakes
[HttpGet]
[Route("geodata")]
public async Task<GeoData> GeoData()
{
return await geoService.GetGeoData();
}
WebApiConfig 代码:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//This line sets json serializer's ContractResolver to CamelCasePropertyNamesContractResolver,
// so API will return json using camel case
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
确保您的 API 操作方法 returns 数据符合以下方式,并且您已安装最新版本的 Json.Net/Newtonsoft.Json:
[HttpGet]
public HttpResponseMessage List()
{
try
{
var result = /*write code to fetch your result - type can be anything*/;
return Request.CreateResponse(HttpStatusCode.OK, result);
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
}
}
我已经通过以下方式解决了
[AllowAnonymous]
[HttpGet()]
public HttpResponseMessage GetAllItems(int moduleId)
{
HttpConfiguration config = new HttpConfiguration();
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
try
{
List<ItemInfo> itemList = GetItemsFromDatabase(moduleId);
return Request.CreateResponse(HttpStatusCode.OK, itemList, config);
}
catch (System.Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
}
}
我将 WebApi 与 Breeze 一起使用,我 运行 在尝试对 breeze 控制器执行 non-breeze 操作时遇到同样的问题。我尝试使用 apprach Request.GetConfiguration 但结果相同。因此,当我访问 Request.GetConfiguration 返回的 object 时,我意识到请求使用的序列化程序是 breeze-server 用来使其变得神奇的序列化程序。无论如何,我通过创建不同的 HttpConfiguration:
解决了我的问题public static HttpConfiguration BreezeControllerCamelCase
{
get
{
var config = new HttpConfiguration();
var jsonSerializerSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
return config;
}
}
并将其作为参数传递给 Request.CreateResponse,如下所示:
return this.Request.CreateResponse(HttpStatusCode.OK, result, WebApiHelper.BreezeControllerCamelCase);
在您的 Owin Startup 中添加此行...
public class Startup
{
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = ConfigureWebApi();
app.UseWebApi(webApiConfiguration);
}
private HttpConfiguration ConfigureWebApi()
{
var config = new HttpConfiguration();
// ADD THIS LINE HERE AND DONE
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.MapHttpAttributeRoutes();
return config;
}
}