【问题标题】:C# MVC Control Newtonsoft.json serializationC# MVC 控制 Newtonsoft.json 序列化
【发布时间】:2015-11-06 16:47:58
【问题描述】:

假设我有一堂课

public class Foo
{
  public int Prop1 { get; set; }
  public int Prop2 { get; set; }
  public int Prop3 { get; set; }
}

想象一下,在某些控制器 FooController 中,我正在创建一个此类 Foo 类的 List,用数据填充它,使用 Newtonsoft.Json 对其进行序列化并发送到客户端。

没关系,没有问题。

但是,我也有每个用户的权限系统,它说 User1 看不到 Prop1 的数据,而 User2 看不到 Prop3 的数据。我有很多这样的类 Foo 和我系统的不同用户的很多权限。 而且,为了禁止用户查看不允许列中的数据,我决定中断 json 序列化并从 JSON 序列化中排除不允许的用户列。

目前它已经编写了自定义 JsonConverter,这让我可以这样做。但是,它很复杂(输入类扫描、动态访问器编译、递归等),并且与原生 newtonsoft 相比,速度较慢。

关于上述事实,我想问是否有更简单的方法来实现预期的结果?我的意思是,在不创建自定义 JsonConverter 的情况下,从任何使用 json 类序列化的列中删除任何列。

感谢您的回答!

更新 跟随@SebastianStehle 的回答。 扩展了我自己的映射器以将类映射到字典,并具有排除字段的能力。

【问题讨论】:

  • 与其让我们“想象”,不如发布一些实际代码(并确保您格式化该代码!)。
  • 为什么不根据用户权限剥离 FooController 中的 json Foo 条目呢?含义:序列化模型的所有必要信息,但根据权限对其进行转换。是否有要求用户可以看到原始 json 输出或其他内容?
  • 不,我不允许发送未经允许的用户数据,因为我们的用户足够聪明,可以中断发布的数据
  • 好的,所以这不是在后端,而是一些为前端提供数据的 json 服务。我看到你需要剥离物品。您是否为每种类型的权限考虑了单独的模型?例如,我们有一个对应于权限的子类模型,或者一个基于用户权限(在“gets{}”上)做出反应的模型。
  • 现在我有大约 30 个不同的模型类。你建议我以任何可能的组合对每个类进行子类化?不,这不适合我的情况,因为我不知道哪些“列”对于下一个用户是不可见的。

标签: c# .net json asp.net-mvc-5 json.net


【解决方案1】:

您的问题是面向逻辑的。您有不同的键值,您想根据场景将其发送给您的客户。

Newtonsoft.Json 序列化 json,这是它的目标,不建议在序列化器中添加逻辑,它更难调试/维护,保持一个对象/类做一件事的想法。它被称为single responsibility principle

如何/在哪里添加逻辑?我建议使用带有对象的command pattern 作为参数。使用该“模式”,您可以轻松添加参数(参数对象的属性)并向命令添加逻辑。最后,您可以返回一个键值列表或一个对象,然后让 json.net 对其进行序列化。

这个解决方案可能看起来有点复杂,但从长远来看它绝对有用。我可以更详细地解释如何实现它。

最后提示:您可以使用 ASP.NET WEBAPI 为您序列化您的对象(它使用来自伟大的 Newtonsoft.Json 的 json.net)

【讨论】:

    【解决方案2】:

    我看到了一些其他选项:

    1. 将值留空。您可以将 JSON.NET 配置为不将具有 null 或默认值的属性写入输出流:

      JsonSerializerSettings settings = new JsonSerializerSettings
      {
         DefaultValueHandling = DefaultValueHandling.Ignore,
         NullValueHandling = NullValueHandling.Ignore
      };
      
    2. JSON.NET 也可以很好地处理 Dictionary(string, object)。创建一个更动态的模型并正确映射它。这个 Dictionary 只是 WebAPI 的结果模型,你应该为它实现任何逻辑。你还需要一些好的映射逻辑,可以用反射来实现。

    我会使用一个约定,您可以为每个属性自动创建一些映射逻辑,并为依赖于安全规则的属性覆盖此逻辑,例如

      ModelMapper.CreateByConvention<Product>()
         .Map(x => x.Created)
              .Never()
         .Map(x => x.UserName)
              .WhenUserInRole(Roles.Administrator)
         .Map(x => x.FirstName)
              .WhenUser(u => u.CanSeeFirstName());
    

    【讨论】:

    • 1. int 的默认值为零。并且,它将从结果中删除,因为它是默认值。但是,如果是实际数据,是否允许客户端?
    • 2.字典也不是我的解决方案,因为它太小了,无法满足我的需求
    • “太小”是什么意思?
    • 想象一下,我有一个 TransactionDetail 类,其中有大约 40 个属性。而且,我的模型返回了大约 5000 个此类的列表。而且,我必须在运行时从中排除不需要/不允许的属性,而不事先知道要排除哪个属性。字典?不,谢谢。
    • 这只是一个好的映射逻辑的问题,看我更新的答案。
    猜你喜欢
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    相关资源
    最近更新 更多