基于.Net WebApi的类型和属性的自定义Json序列化

本文关键字:自定义 Json 序列化 属性 类型 Net WebApi 基于 | 更新日期: 2023-09-27 18:28:20

我正在用一个mvc项目构建一个web应用程序,一方面是angularjs,另一方面是Webapi。

我会有很多视图,不想在webApi端创建那么多视图模型变体。

有些视图是项目列表,有些视图是一个项目的详细信息。

我可以为我的应用程序中的每个业务实体创建2个视图模型(轻度/摘要和完整/详细),但我会有很多类,维护或发展可能很困难。

我的想法是创建更少的视图模型,并使用属性来指定我想要的属性。轻结果json或完整的json。

好的,显然还不清楚。请和我在一起

public class BookVM
    {  
        [WebApiRef]
        public long Id { get; set; }
        [WebApiRef]
        public String Title { get; set; }
        public DateTime Date { get; set; }
        public float Price { get; set; }
        public AuthorVM Author { get; set; }
    }
    public class AuthorVM
    {  
        [WebApiRef]
        public long Id { get; set; }
        [WebApiRef]
        public String Name { get; set; }
        public int Age { get; set; }
        public String Country { get; set; }
        public List<BookVM> Books { get; set; }
        [...]
    }

对于一个列出书籍的页面,我希望有一个json格式的序列化BookMV列表,如下所示:

[
  {
    "Id": 1,
    "Title": "The Lord of the Rings",
    "Date": "29'/07'/1954",
    "Price": "23",
    "Author": {
      "Id": 854,
      "Name": "J. R. R. Tolkien"
    }
  },
  {
    "Id": 2,
    "Title": "The Hobbit",
    "Date": "21'/08'/1937",
    "Price": "12",
    "Author": {
      "Id": 854,
      "Name": "J. R. R. Tolkien"
    }
  },
  {
    "Id": 3,
    "Title": "A Game of Thrones",
    "Date": "06'/08'/1996",
    "Price": "17",
    "Author": {
      "Id": 157,
      "Name": "George R. R. Martin"
    }
  }
]

对于列出作者的页面:

    [
  {
    "Id": 854,
    "Name": "J. R. R. Tolkien",
    "books": [
      {
        "Id": 1,
        "Title": "The Lord of the Rings"
      },
      {
        "Id": 2,
        "Title": "The Hobit"
      }
    ]
  },
  {
    "Id": 157,
    "Name": "George R. R. Martin",
    "books": [
      {
        "Id": 3,
        "Title": "A Game of Thrones"
      }
    ]
  }
]

对于作者的页面:

    {
  "Id": 157,
  "Name": "George R. R. Martin",
  "books": [
    {
      "Id": 3,
      "Title": "A Game of Thrones"
    }
  ]
}

属性[WebApiRef]将定义要包含在附加实体中的属性,但不会用于主类型。

因此,根据被序列化/反序列化的类型,该属性将用于定义在内部的附加实体中保留什么。

我希望这是有意义的。。。

我的问题是我该怎么做才能做到这一点?

我读过关于格式化程序、ContractResolver的文章,我不确定在哪里加载或加载什么。

基于.Net WebApi的类型和属性的自定义Json序列化

事实上,它不起作用。

我想我可以创建一个自定义ContractResolver并在那里应用我的序列化逻辑。

问题是如何确定我想要序列化的对象的类型。

我想,我可以在解析器中保存CreateProperty传递的第一个类型。

public class CustomSerializationContractResolver : DefaultContractResolver
{
    private Type _serializingType;
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        if (_serializingType == null)
        {
            _serializingType = member.DeclaringType;
        }
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (_serializingType == member.DeclaringType)
        {
            property.ShouldSerialize = (instance) => true;
        }
        else if(Attribute.IsDefined(member, typeof(WebApiRefAttribute)))
        {
            property.ShouldSerialize = (instance) => true;
        }
        else
        {
            property.ShouldSerialize = (instance) => false;
        }

        return property;
    }
}

这起到了作用,但没有为每个对象序列化安装约定解析程序。因此,保存的类型对于下一个序列化是不正确的。

我使用的是WebApi,contractResolver是在WebApiConfig.cs中全局设置的它是通过所有控制器方法共享的。

formatter.SerializerSettings.ContractResolver = new CustomSerializationContractResolver();

我发现你可以通过控制器应用ContractResolver,但问题仍然存在,因为你可以通过不同的控制器使用不同的返回类型。

不幸的是,我没有找到通过方法指定ContractResolver的方法。

总之,它不起作用,因为自定义ContractResolver安装一次并使用:

  • 通过所有方法(如果全局设置)
  • 或由控制器中的每种方法使用(如果由控制器设置)