【问题标题】:Post service property with optional field but want update if it is null or empty使用可选字段发布服务属性,但如果它为空或为空,则需要更新
【发布时间】:2020-10-16 07:42:30
【问题描述】:

我正在使用 C# 中的 Post 端点,我想让所有字段都是可选的,但也想将其更新为空/空列表。我知道这是非常奇怪的要求。我可以将 int 和 string 数据类型设置为 -1 或一些默认字符串,但我发现 List 或任何数据列表都有困难。

我可以为条件更新添加任何额外的标志,但这会增加请求正文中的属性数量。

如果有人遇到过类似的问题,谁能建议我解决这种情况。我知道解决方案会很棘手。

【问题讨论】:

    标签: c# json webapi


    【解决方案1】:

    抱歉耽搁了。

    让我试着用更多的代码来解释它。

    首先,我们使用从 JSON 字符串中提取的数据填充通用对象的通用方法。

    public static void FillObjectFromJson<T>(T objectToFill, string objectInJson)
                where T : class
            {
                // Check parameters
                if (objectToFill == null) throw new ArgumentNullException(nameof(objectToFill));
                if (string.IsNullOrEmpty(objectInJson)) throw new ArgumentNullException(nameof(objectInJson));
    
                // Deserialize in a typed object (helpful for the type converter)
                var typed = JsonConvert.DeserializeObject<T>(objectInJson);
    
                // Deserialize in an expando object (for check properties)
                var expando = JsonConvert.DeserializeObject<ExpandoObject>(objectInJson);
    
                // Converts the expando to dictionary for check all given properties
                var dictionary = (IDictionary<string, object>)expando;
    
                // Read all properties of the given object (the only one you can assign)
                foreach (var property in typeof(T).GetProperties().Where(x => x.CanWrite))
                {
                    // If dictionary contains the property, it was in the JSON string, 
                    // so we have to replace it
                    if (dictionary.ContainsKey(property.Name))
                    {
                        var propValue = property.GetValue(typed);
                        property.SetValue(objectToFill, propValue);
                    }
                }
            }
    

    就性能而言,它并不是最好的,因为我们将相同的 JSON 反序列化了两次:

    • 第一次进入类型化对象
    • 第二次到 ExpandoObject 类型

    我这样做是因为我们在属性类型方面可能会遇到一些问题。在此示例中,在 ExpandoObject 中,Age 属性的类型为 int64 而不是 int32。因此,如果我们只想反序列化 JSON 一次,那么我们需要转换属性。 随意更改此代码。

    现在我们有了一个泛型方法,尝试在示例中使用它。

    首先,我们需要一个类来使用:

        public class Person
        {
    
            public string Name { get; set; }
    
            public int Age { get; set; }
    
            // This method is used only for this example, just for write data to the console
            public override string ToString()
            {
                return $"Name: {Name} - Age: {Age}";
            }
        }
    

    然后我们需要一种方法来从存储中提取要更新的数据。在本例中,我们将简单地支持一个对象:

        public static Person ReadPersonFromStorage()
        {
            return new Person
            {
                Name = "Name from storage",
                Age = 44
            };
        }
    

    最后,我们可以编写我们的测试方法了:

            // Example of JSON with explicit name (so we have to set it as null)
            var personWithNameJson = "{ \"Name\" : null, \"Age\" : 24 }";
            
            // Read the original value from the storage
            var person = ReadPersonFromStorage();
            Console.WriteLine(person); // We have the name
    
            // Fills from JSON (it will replace the Name since it's in the JSON)
            FillObjectFromJson(person, personWithNameJson);
            Console.WriteLine(person); // The name is set to null
    
            
            
            
            // Example of JSON without explicit name (so you have to leave it with the original value)
            var personWithoutNameJson = "{ \"Age\" : 24 }";
    
            // Read the original value from the storage
            var otherPerson = ReadPersonFromStorage();
            Console.WriteLine(otherPerson); // We have the name
    
            // Fills from JSON (it won't replace the Name since it's NOT in the JSON)
            FillObjectFromJson(otherPerson, personWithoutNameJson);
            Console.WriteLine(otherPerson); // We still have the name since it's not in the JSON
    

    我希望我的意思更清楚,更好的是,我会帮助你。

    PS:对于这个示例,我使用 Newtonsoft 进行 JSON 反序列化。

    【讨论】:

      【解决方案2】:

      如果您同时控制客户端和服务器,则可以使用请求的格式对其进行管理。

      假设你有一个像这样的对象:

      public class Customer {
         
         public string Name { get; set; }
      
         public int? Age { get; set; }
      
      }
      

      然后你可以管理两种请求。我将使用 JSON 格式进行解释。

      {
         "Name": null,
         "Age": 12
      }
      

      在这种情况下,请求包含值“Name”,因此您将在数据库(或任何其他存储)中将其设置为 null

      {
         "Age": 12
      }
      

      在这种情况下,请求不包含值“名称”,因此 ti 表示它没有被更改。

      对于 JSON 格式,两个请求相同(Name = null)。但在您的代码中,它们将以不同的方式工作。

      当然:

      • 这不是一个标准,所以你必须自己做(JSON 序列化器/反序列化器不会管理这种情况)
      • 由于它不是标准的,最好同时管理客户端和服务器端。如果您不遵守标准规则,请人们使用您的服务器可能是一种技巧

      【讨论】:

      • 同意你的观点,但是我们有什么方法可以确定 Name 是显式传递的,还是作为 json 中的 Null 值传递的?
      猜你喜欢
      • 1970-01-01
      • 2020-04-10
      • 1970-01-01
      • 2016-12-18
      • 2019-09-01
      • 2021-12-10
      • 1970-01-01
      • 2013-04-16
      • 1970-01-01
      相关资源
      最近更新 更多