问题描述
最终目标是在不使用 .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 (将#修改为@)