简单补丁请求的部分对象反序列化 .Net Core

问题描述

最终目标是在不使用 .net 中的 JsonPatchDocument 类的情况下最终支持简单补丁请求的能力。假设我有以下课程:

 public class User
{

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string Username { get; set; }

}

APIController 的以下方法

    [HttpPatch]
    [Route("{id}")]
    public async Task<IActionResult> UpdateUser(int id,User request)
    {
        var updatedUser = //Call method to update user and return user
        return Ok(updatedUser);
    }

我正在寻找一种简单的方法来做这样的事情:

//Simple request payload 
    {
    "LastName":"UpdatedLastName"
    }

我目前使用 System.Text.Json 作为序列化程序。问题是,当序列化为类时,我无法区分空值和未在请求有效负载中发送的值(需要将值设置为空或不更改当前值)。到目前为止,我所想到的不是序列化为类,而是序列化为 Dictionary<string,object> 并编写一个静态方法来返回另一个具有类上属性Dictionary<string,object>

public static IDictionary<string,object> MapObject<T>(IDictionary<string,object> dictionary) where T : class,new()
    {
        Dictionary<string,List<string>> propertyErrors = new Dictionary<string,List<string>>();
        Dictionary<string,object> mappedDictionary = new();
        var newobj = new T();

        //Loop through each item in dictionary
        foreach (var item in dictionary)
        {
            var propName = item.Key;
            var propValue = item.Value;

            //If there is a match on the mapType continue
            if (typeof(T).GetProperty(propName) != null)
            {
                //Get the property type of the matching property name. If it is a nullable value type,return the underlying value type
                var mapType = typeof(T).GetProperty(propName).PropertyType;

                string stringValue = null;

                //If value is null,set these directly else convert to string
                if (propValue != null)
                {
                    stringValue = item.Value.ToString();
                }


                object mapValue = null;

                ////Checks if type is string and value is null
                bool nullString = (mapType == typeof(string) && stringValue == null);

                try
                {
                    //Removing this check will cause null strings to be set to ""
                    if (!nullString)
                    {
                        //Different type of converter that may be used in the future
                        mapValue = TypeDescriptor.GetConverter(mapType).ConvertFrom(stringValue);
                    }
                }

                //If conversion causes and error,throw an exception to be caught by ErrorHandlerMiddleware
                catch (Exception)
                {
                    throw new InvalidCastException($"{propName} is invalid");
                }

                //Validate the object values based on the mappedobject
                ValidationContext context = new ValidationContext(newobj) { MemberName = propName };
                List<ValidationResult> results = new();
                if (!Validator.TryValidateProperty(mapValue,context,results))
                {
                    propertyErrors[propName] = results.Select(x => x.ErrorMessage).ToList();
                }

                mappedDictionary[propName] = mapValue;

            }
        }

        //If there are any validation errors,throw an exception to get caught by ErrorHandlerMiddleware
        if (propertyErrors.Count > 0)
        {
            string validationErrors = string.Join(",",propertyErrors.SelectMany(x => x.Value));
            throw new ValidationException(validationErrors);
        }

        //If there are no mapped values,throw an exception to get caught by ErrorHandlerMiddleware
        if (mappedDictionary.Count == 0)
        {
            throw new ValidationException("Invalid request");
        }

        return mappedDictionary;
    }

问题在于,仅仅能够处理一个非常直接的请求似乎非常复杂。它也不处理任何类上的 List 类型对象。还需要对此执行验证,并且模型验证逻辑现在也在此类上处理。

无论如何,序列化程序是否可以使用 User 类作为引用并对 Dictionary <string,object> 进行部分序列化??

基本上,对于类上的任何公共属性,在此示例中 User,序列化名称匹配的任何属性?然后我就可以接受这个部分请求并将它传递给方法来执行部分更新。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)