Web API 2:如何在对象及其子对象上返回带有camelCased属性名称的JSON


104

更新

感谢所有的答案。我正在一个新项目上,看来我终于明白了这一点:似乎实际上是以下代码导致的:

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

假设它是WebAPI,但我没有理会看上去无害的JsonContent。

无处不在 ...我可以首先说一下wtf吗?也许应该是“他们为什么要这样做?”


原始问题如下

有人会以为这将是一个简单的配置设置,但是现在我已经太久了。

我看过各种解决方案和答案:

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子对象(嵌套对象,子对象)似乎不尽人意,但可行的答案,直到我意识到在使用linq2sql时必须将这些属性添加到生成的代码中...

有办法自动执行此操作吗?这种“讨厌”困扰了我很长时间。



Linq2SQL产生部分类也是有原因的。还... Linq2SQL WTF吗?!
阿隆

1
谢谢,但是此链接是针对MVC的,它是我正在使用的Web API 2,我不确定是否可以通过这种方式设置content-type并返回一个字符串,但是似乎没有就像完全正确的解决方案一样。.也感谢有关分部类的技巧,但是是否可以向分部的另一部分中定义的属性添加属性?
汤姆(Tom)

同样是的,linq2sql wtf ...不是我的决定:)
Tom

结果是相同的,唯一的不同是您在注入的位置JsonSerializerstackoverflow.com/questions/13274625/…–
阿伦

Answers:


175

放在一起就可以得到...

protected void Application_Start()
{
    HttpConfiguration config = GlobalConfiguration.Configuration;
    config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
}

肯定是打开它的方式,但是我的问题是,此设置被忽略了(请参阅我的回答)
Tom

1
@Tom erm ... Tom你知道做什么json.UseDataContractJsonSerializer = true;吗?它告诉WebAPI不要Json.Net用于序列化。> _ <
阿隆2015年

是的,我现在做。但是,还存在另一个问题。我验证了这一点。看我的答案。另请参阅stackoverflow.com/questions/28552567/…–
汤姆(Tom)

1
实际上,仔细检查后发现原来我的结论是错误的。查看我的更新。
汤姆(Tom)

28

这对我有用:

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

CamelCasePropertyNamesContractResolver来自Newtonsoft.Json.dllJson.NET库。


3
当只希望对某些API而不是应用程序中所有API拥有camelCasing时,此方法非常有用。(Y)
droidbot '16

15

原来是

return Json(result);

是罪魁祸首,导致序列化过程忽略了驼峰式设置。然后

return Request.CreateResponse(HttpStatusCode.OK, result, Request.GetConfiguration());

是我一直在寻找的机器人。

json.UseDataContractJsonSerializer = true;

当时正在准备一个扳手,结果却不是我要找的机器人。


这实际上是错误的答案。请参阅我在问题中的更新。
2015年

我实际上发现确实如此。返回时Json(result),我在PascalCase中看到了所有内容,但是返回时,Content(StatusCode, result)它按预期运行。
DeeKayy90 '17

12

对于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。


对于通过OWIN进行自我托管,这是完美的。谢谢!
朱利安·梅尔维尔

3
如果您使用的是Owin,此解决方案将非常有效,但前提是您必须将头发全部撕掉!
Alastair

10

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操作方法以以下方式返回数据,并且您已经安装了最新版本的Json.Net/Newtonsoft.Json:

    [HttpGet]
    public HttpResponseMessage List()
    {
        try
        {
            var result = /*write code to fetch your result*/;
            return Request.CreateResponse(HttpStatusCode.OK, cruises);
        }
        catch (Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
        }
    }

4

在您的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;
    }
}

3

这是一个晦涩的例子,当route属性与GET URL不匹配但GET URL与方法名称匹配时,jsonserializer camel case指令将被忽略,例如

http:// website / api / geo / geodata

//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();
}

2

我已经按照以下方法解决了。

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

0

我正在将WebApi与Breeze配合使用,并且尝试在微风控制器中执行非微风操作时遇到了相同的问题。我尝试使用方法Request.GetConfiguration但结果相同。因此,当我访问Request.GetConfiguration返回的对象时,我意识到请求所使用的序列化程序是微风服务器用来使其神奇的序列化程序。无论如何,我解决了创建另一个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);
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.