【问题标题】:JSON Patch Validation .Net CoreJSON 补丁验证 .Net Core
【发布时间】:2018-04-27 15:09:12
【问题描述】:

有没有人找到一种使用数据注释来防止在 json 补丁文档中更新特定属性的好方法。

型号:

 public class Entity
 {
    [DoNotAllowPatchUpdate]
    public string Id     { get; set; }

    public string Name   { get; set; }

    public string Status { get; set; }

    public string Action { get; set; }
 }

逻辑:

var patchDoc = new JsonPatchDocument<Entity>();
patchDoc.Replace(o => o.Name, "Foo");

//Prevent this from being applied
patchDoc.Replace(o => o.Id, "213");

patchDoc.ApplyTo(Entity);

逻辑代码只是一个示例,说明补丁文档可能来自客户端,只是为了快速测试而用 C# 生成

【问题讨论】:

    标签: c# .net-core json-patch


    【解决方案1】:

    我为 JsonPatchDocument 写了一个扩展方法;这是一个缩写版本:

    public static void Sanitize<T>(this Microsoft.AspNetCore.JsonPatch.JsonPatchDocument<T> document) where T : class
    {
        for (int i = document.Operations.Count - 1; i >= 0; i--)
        {
            string pathPropertyName = document.Operations[i].path.Split("/", StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
    
            if (typeof(T).GetProperties().Where(p => p.IsDefined(typeof(DoNotPatchAttribute), true) && string.Equals(p.Name, pathPropertyName, StringComparison.CurrentCultureIgnoreCase)).Any())
            {
                // remove
                document.Operations.RemoveAt(i); 
    
                //todo: log removal
            }
        }
    }
    

    添加一个最小属性:

    [AttributeUsage(AttributeTargets.Property)]
    public class DoNotPatchAttribute : Attribute
    

    将该属性应用于您的类属性:

    public class SomeEntity
    {
        [DoNotPatch]
        public int SomeNonModifiableProperty { get; set; }
        public string SomeModifiableProperty { get; set; }
    }
    

    然后你可以在应用转换之前调用它:

    patchData.Sanitize<SomeEntity>();
    
    SomeEntity entity = new SomeEntity();
    
    patchData.ApplyTo(entity);
    

    【讨论】:

    • 我喜欢这种方法在仍然使用有效属性的同时默默地忽略请求中的无效属性。对我来说,这就是 API 应该做的事情,只要文档清楚说明您在 PATCH 中可以做什么和不可以做什么。
    【解决方案2】:

    您可以创建自己的Attribute。类似的东西:

    DoNotAllowPatchUpdate:Attribute{}
    
    public class Entity
     {
        [DoNotAllowPatchUpdate]
        public string Id     { get; set; }
    
        public string Name   { get; set; }
    
        public string Status { get; set; }
    
        public string Action { get; set; }
     }
    

    然后像这样检查它:

        var notAllowedProperties = typeof(Entity).GetProperties()
          .Where(x => Attribute.IsDefined(x, typeof(DoNotAllowPatchUpdate)))
          .Select(x => x.Name).ToList();
    

    现在在更新它们之前,您可以查看notAllowedProperties

    【讨论】:

    • 这段代码不会总是返回一个只有一个“Id”的名称列表,并不会真正阻止应用对属性的更改。这可能有助于检查 patchDoc 的逻辑块。我想您可以使用 notAllowedProperties 中的名称并查看该名称是否会在操作路径中弹出,然后删除该操作。完成后我会发布我的代码
    【解决方案3】:

    虽然该问题专门询问了有关使用注释来限制通过 JsonPatchDocuments 进行更新的问题,但我认为添加另一种方法可能对某些人有所帮助。

    我通常会创建一个特定于更新的模型,它只包含我希望允许更新的字段。那么就无法更新Id,例如:

    public class UpdateEntityModel
    {    
        public string Name { get; set; }
    
        public string Status { get; set; }
    
        public string Action { get; set; }
     }
     
    

    我的控制器/函数接收JsonPatchDocument&lt;UpdateEntityModel&gt; 类型的参数。我从数据库中获取所需的实体,将其属性映射到我的更新模型,将补丁应用到更新模型并验证结果。然后将其映射回实体以将更改持久保存在数据库中。

    /* Fetch entity from db */
    
    
    var updateEntityModel = MapEntityToUpdateModel(entity);
        
    jsonPatchDocument.ApplyTo(updateEntityModel);
    
    ValidateModel(updateEntityModel); // Using FluentValidation validator
         
    MapUpdateModelBackToEntity(entity, updateEntityModel);
    
    
    /* Persist entity in db */
    

    我使用 FluentValidation AbstractValidator&lt;UpdateEntityModel&gt; 专门验证更新模型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-24
      • 1970-01-01
      • 1970-01-01
      • 2018-02-22
      相关资源
      最近更新 更多