【问题标题】:How can I add a custom root node when serializing an object with JSON.NET?使用 JSON.NET 序列化对象时如何添加自定义根节点?
【发布时间】:2012-11-30 03:18:00
【问题描述】:

我为我的一些对象添加了一个自定义属性,如下所示:

[JsonCustomRoot("status")]
public class StatusDTO 
{
    public int StatusId { get; set; }
    public string Name { get; set; }
    public DateTime Created { get; set; }
}

属性很简单:

public class JsonCustomRoot :Attribute
{
    public string rootName { get; set; }

    public JsonCustomRoot(string rootName)
    {
        this.rootName = rootName;
    }
}

序列化对象实例时 JSON.NET 的默认输出如下:

{"StatusId":70,"Name":"Closed","Created":"2012-12-12T11:50:56.6207193Z"}

现在的问题是:如何使用自定义属性的值向 JSON 添加根节点,如下所示

{status:{"StatusId":70,"Name":"Closed","Created":"2012-12-12T11:50:56.6207193Z"}}

我发现有几篇文章提到了IContractResolver 接口,但我不知道该怎么做。我的尝试包括这段未完成的代码:

protected override JsonObjectContract CreateObjectContract(Type objectType)
{
    JsonObjectContract contract = base.CreateObjectContract(objectType);

    var info = objectType.GetCustomAttributes()
                   .SingleOrDefault(t => (Type)t.TypeId==typeof(JsonCustomRoot));
    if (info != null)
    {
        var myAttribute = (JsonCustomRoot)info;
        // How can i add myAttribute.rootName to the root from here?
        // Maybe some other method should be overrided instead?
    }

    return contract;
}

【问题讨论】:

  • 我也在寻找类似的东西,我不想将我的响应包装在每个 GET 的控制器上,我正在寻找一种方法来作为设置或每个模型上的自定义属性。
  • 理想情况下,我想和你做的几乎一样,但即使只返回一个对象,我也会以数组的形式返回,例如:{status:[{"StatusId":70,"Name":"Closed","Created":"2012-12-12T11:50:56.6207193Z"}]}。还尝试使用IContractResolver 和 JSON.NET
  • 我在 emadibrahim.com/2014/04/09/… 写了一篇关于 Web api 解决方案的博客

标签: c# json serialization json.net custom-attributes


【解决方案1】:

我在我的一个项目中遇到了类似的挑战。以下是我解决问题的步骤。

1.我的实体类

public class Product
    {
        [Key]
        public string Id { get; set; }
        public string Title { get; set; }
        public string Album { get; set; }
        public string Artist { get; set; }
        public string Genre { get; set; }

    }

2。创建了另一个类,以这种形式定义。

    public class KindOfMedia
        {
            public KindOfMedia()
            {
                Product = new List<Product>();
            }
            public List<Product> Product { get; set; }
        }

3. Web API 控制器,将返回 json

            public HttpResponseMessage Products()
            {
                var kind = new KindOfMedia();
                kind.Products = new List<Product>();
                kind.Products.Add(new Product
                {
                    Id = Guid.NewGuid().ToString(),
                    Title = "I am A Winner",
                    Album = "",
                    Artist = "Project Fame",
                    Genre = "Contemporal"                
                });
                kind.Products.Add(new Product
                {
                    Id = Guid.NewGuid().ToString(),
                    Title = "Great Nation",
                    Album = "Oceans",
                    Artist = "Timi Dakolo",
                    Genre = "Gospel"
                });

                return Request.CreateResponse(HttpStatusCode.OK, kind);
            }

4.将这行代码添加到我的 App_Start 文件夹中的 WebApi Config 文件中

     var json = config.Formatters.JsonFormatter;
                json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;

请注意Newtonsoft.Json.PreserveReferencesHandling.None,不会保留序列化类型的引用

生成的 Json 是

{
  "Musics": [
    {
      "Id": "bf9faeee-7c39-4c33-a0ea-f60333604061",
      "Title": "I am A Winner",
      "Album": "",
      "Artist": "Project Fame",
      "Genre": "Contemporal"
    },
    {
      "Id": "243edd32-7ba2-4ac4-8ab9-bba6399cb0a6",
      "Title": "Great Nation",
      "Album": "Oceans",
      "Artist": "Timi Dakolo",
      "Genre": "Gospel"
    }
  ]
}

【讨论】:

  • 从哪里获取 Musics 根对象?
【解决方案2】:

解决这个问题的一个非常简单的方法是将对象放在另一个对象中。看起来可能过于简单化了,但这在处理集合和单一对象时有效。

  public class StatusDTO
    {
        public int StatusId { get; set; }
        public string Name { get; set; }
        public DateTime Created { get; set; }
    }

    public class statusJasonModel
    {
        public StatusDTO status { get; set; }
    }

现在,如果您将 StatusDTO 放入 statusJsonModel 对象并将其序列化为 Json。它应该会给你想要的答案。

【讨论】:

    【解决方案3】:

    这是一个专门针对 Web API 的解决方案,我也在使用它:RootFormatter.cs

    我是根据Creating a JSONP Formatter for ASP.NET Web API写的。

    我没有使用自定义属性,而是重用了JsonObjectAttribute 的标题字段。这是一个使用代码:

    using Newtonsoft.Json
    
    [JsonObject(Title = "user")]
    public class User
    {
        public string mail { get; set; }
    }
    

    然后,将 RootFormatter 添加到您的 App_Start 并在WebApiConfig 中注册如下:

    GlobalConfiguration.Configuration.Formatters.Insert(0, new RootFormatter());
    

    我能够获得类似于 WCF 的 WebMessageBodyStyle.Wrapped 的包装响应:

    {"user":{
      "mail": "foo@example.com"
    }}
    

    【讨论】:

    • 这真的很酷!如果它有一个收藏解决方案,那将是史诗般的。
    【解决方案4】:

    如果你使用匿名对象会怎样?

    JSON.Serialize(new { status = targetObject});
    

    【讨论】:

    • 我在 .NET 4.0 WebAPI 项目中使用 JSON.Net 作为序列化程序,因此我试图避免在返回数据时编写自定义代码。我希望在应用属性时为我完成。
    猜你喜欢
    • 1970-01-01
    • 2011-07-21
    • 2022-11-15
    • 1970-01-01
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    相关资源
    最近更新 更多