【问题标题】:JSON Root Node - Different From Class NameJSON 根节点 - 与类名不同
【发布时间】:2016-03-22 00:04:24
【问题描述】:

我需要让我的 JSON 输出看起来像这样:

{
    "User": {
        "Id" : "1",
        "FirstName" : "John",
        "LastName" : "Doe",
        ... etc

我的第一个问题是这里被序列化的类名被称为Person 而不是User,我无法更改它。但是 JSON 需要User

其次,我的 Web API 方法根本没有返回根节点,我到底做错了什么?

我的 JSON 如下所示:

{"Id":1,"BossId":null,"Title":"CEO","GivenName":"Doe", ... etc

这是非常糟糕的格式,甚至我的 Chrome 扩展程序使 JSON 更漂亮也无法识别这些东西。

这是我通过 ID 获取用户的 Web API 控制器,结果如下:

[Route("{id:int}")]
public HttpResponseMessage GetPerson(int id) {

    Person person = repository.Get(id);

    if (person == null) {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return Request.CreateResponse(HttpStatusCode.OK, person);

}

我还必须在这里将类属性映射到不同的名称,这是一个单独的问题。

例如,类有 GivenName 和 FamilyName,但 JSON 需要 FirstName 和 LastName。有没有我可以为此属性应用的属性?

任何帮助将不胜感激。

【问题讨论】:

  • 我建议将您的课程与您想要生成的示例 json 一起发布。
  • This is so badly formatted that even my Chrome extension to make JSON pretty doesn't recognize this stuff. - 在我看来,这就像完美的 JSON。无论如何,如果你想要一个根对象,你需要包装一个匿名对象,就像这样:return Request.CreateResponse(HttpStatusCode.OK, new { User = person });
  • 该类是一个简单的小型 POCO 类,类似于 Person ...名字、姓氏、ID ...它确实有一个 IEnumerable 用于多个地址,但这一切都在 JSON 中返回 OK,这只是命名问题和根节点问题。
  • 我不知道为什么 Chrome JSON 格式化扩展在这方面没有发挥作用。我已经针对多个其他 JSON 端点对其进行了测试,它的格式确实很好。它拒绝对我从这里的控制器得到的东西做任何事情。我可以停止调试器,在 JSON 查看器中它看起来没问题(树出来,正确嵌套)所以它必须是有效的。

标签: c# json asp.net-web-api


【解决方案1】:

ASP.NET WebApi 使用JSON.NET 序列化为 json。所以你可以这样改名字:

class Person
{
    [JsonProperty(PropertyName = "LastName")]
    public string FamilyName { get; set; }
    ...
}

编辑

要添加根元素,请查看answer。我没有尝试过,但看起来不错。

【讨论】:

  • 谢谢...我没有意识到他们实际上将 JSON.NET 带入了组合,直到对此进行了一些搜索。它确实让它变得更容易了,这正是我需要的属性名称。
  • 我应该在 Fiddler 中期待“Content-Type: text/html; charset=utf-8”而不是“application/json”吗?如果不是,我该如何改变呢?
  • 不管,我发现是什么破坏了这一切。我从另一篇关于 JSON 格式的 SO 帖子中添加了一行,这把它搞砸了 ("config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));") ...我从WebApiConfig.cs,现在浏览器将其显示为格式正确的 JSON,并且内容类型正确。
  • 我已经接受了这个答案,因为它部分解决了这个问题......序列化时重命名属性的属性。但是,@Rob 在上面发布了关于根节点名称问题的出色评论。非常简单优雅,对我所拥有的进行了微小的更改:return Request.CreateResponse(HttpStatusCode.OK, new { User = person });
【解决方案2】:

假设您使用的是Newtonsoft Json.Net,最流行的.Net Json serializer,则需要进行以下修改:

  1. 将 Person 对象包装在一个包装器中并为其分配一个 JsonProperty

     [JsonObject]
     public class Wrapper
     {
       [JsonProperty("User")]
       public Person Person {get; set;}
     }
    
  2. 现在在 Person 类中也使用相同的 JsonProperty

     [JsonObject]
     public class Person
     {
       [JsonProperty("FirstName")]
       public string GivenName {get; set;}
    
       [JsonProperty("LastName")]
       public string FamilyName {get; set;}
    
       ... More Properties
     }
    

现在在填写 response.following 时需要完成:

Wrapper w = new Wrapper();
w.Person = <assign Value>
return Request.CreateResponse(HttpStatusCode.OK, w);

最后一件事Json 不像XML 没有根节点的概念,它是无名的,这就是为什么包装器不会出现在任何地方,在这种情况下它将从标记为User 的第一个对象开始, Json 类似于anonymous type in C#,内部是一个键值对,因为键总是字符串

【讨论】:

  • Rob 在评论中的回答实际上更简洁,并且确实产生了关于根节点的预期结果:Request.CreateResponse(HttpStatusCode.OK, new { User = person });
  • 在企业系统中,使用Web API访问Rest服务,直接修改HttpResponseMessage不是一个好习惯,你需要让Web API为你做。例外情况是您添加过滤器以处理错误并创建友好的 HttpResponseMessage。无论您选择哪种答案,请尝试使用 Web API 内置实体序列化,它需要一个包装类,如建议
  • 感谢您的 cmets,并一直在阅读有关该过程的更多信息。为了在 JSON 根节点中获取一些文本,必须创建一个额外的“包装器”类似乎有点“丑陋”(如果你愿意的话)。 new { User = person } 完成了它,对我来说似乎更优雅。但如果这不是最佳实践,我将继续研究它。这个特定的应用程序不是企业的,我不必担心这一点。有时,“最佳实践”虽然很棒,但在您不需要时会使事情变得过于复杂。
  • 当然是你的特权,你可能会发现不同的意见:)
  • 我总是这样。我想这就是我不断回到这里的原因!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多