.NET Core Web API如何将Selected为True的模型字段设为NULL?
问题描述
我有一个接收如下JSON(对应RequestModel)的.NET Core Web API:
{ "isSpecimen": true, "forms": { "cyber": { "abc1": { "formOrder": 1, "endNumber": "1", "selected": true, "aggLimit": 5000000.0, "Date": "2016-12-14T00:00:00.00Z" }, "abc2": { "formOrder": 2, "endNumber": "4", "selected": false, "aggLimit": 50000.0, "Date": "2019-12-14T00:00:00.00Z" } } } }
对应的C#模型类如下:
public class RequestModel { public FormsModel Forms { get; set; } public bool IsSpecimen { get; set; } } public abstract class BaseFormInfo { public bool Selected { get; set; } public int? FormOrder { get; set; } public virtual string FormKey { get; set; } } public class FormsModel { public ExcessFormsModel? Excess { get; set; } public CyberFormsModel? Cyber { get; set; } } public class CyberFormsModel { public Abc1? abc1 { get; set; } public Abc2? abc2 { get; set; } public Abc3? abc3 { get; set; } } public class Abc1: BaseFormInfo { public override string FormKey => "Abc1"; public decimal? aggLimit{ get; set; } public DateTime? Date { get; set; } public string? endNumber{ get; set; } }
需求:更新模型,将所有Selected字段为true的类的其他字段设为null,仅保留Selected: true。比如示例中abc1的Selected为true,需要把它的formOrder、endNumber、aggLimit、Date等字段都设为null。
解决方案
方案一:通过反射遍历已绑定的模型对象处理
适合在API接收模型后,直接操作实例化的对象:
1. 编写通用处理方法
递归遍历所有继承自BaseFormInfo的对象,检查Selected属性,若为true则清空其他可空字段:
using System.Reflection; public static void ClearExtraFieldsWhenSelected<T>(T model) where T : class { if (model == null) return; // 获取当前对象的所有公开实例属性 var properties = model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { var propValue = prop.GetValue(model); if (propValue == null) continue; // 处理BaseFormInfo子类对象 if (typeof(BaseFormInfo).IsAssignableFrom(propValue.GetType())) { var formInfo = (BaseFormInfo)propValue; if (formInfo.Selected) { // 筛选出除Selected外的可空属性(值类型需为可空,引用类型直接处理) var formProperties = formInfo.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.Name != nameof(BaseFormInfo.Selected) && (Nullable.GetUnderlyingType(p.PropertyType) != null || p.PropertyType.IsClass)); foreach (var formProp in formProperties) { formProp.SetValue(formInfo, null); } } } // 递归处理嵌套的复杂对象(比如FormsModel、CyberFormsModel这类容器) else if (!prop.PropertyType.IsValueType && prop.PropertyType != typeof(string)) { ClearExtraFieldsWhenSelected(propValue); } } }
2. 在API接口中调用
[HttpPost] public IActionResult ProcessRequest([FromBody] RequestModel request) { // 执行字段清空逻辑 ClearExtraFieldsWhenSelected(request); // 后续业务逻辑处理 return Ok(request); }
方案二:在JSON反序列化阶段自动处理
如果希望在JSON转模型的过程中直接完成处理,可以自定义JSON转换器(以Newtonsoft.Json为例):
1. 编写BaseFormInfo的自定义转换器
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public class BaseFormInfoConverter : JsonConverter<BaseFormInfo> { public override BaseFormInfo ReadJson(JsonReader reader, Type objectType, BaseFormInfo existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObj = JObject.Load(reader); var selected = jsonObj[nameof(BaseFormInfo.Selected)]?.Value<bool>() ?? false; // 先完成基础反序列化 var formInfo = jsonObj.ToObject(objectType) as BaseFormInfo; if (formInfo == null) return null; // 如果Selected为true,清空其他可空字段 if (selected) { var properties = objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.Name != nameof(BaseFormInfo.Selected) && (Nullable.GetUnderlyingType(p.PropertyType) != null || p.PropertyType.IsClass)); foreach (var prop in properties) { prop.SetValue(formInfo, null); } } return formInfo; } public override void WriteJson(JsonWriter writer, BaseFormInfo value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
2. 注册转换器
有两种注册方式:
- 方式一:在BaseFormInfo类上标记特性
[JsonConverter(typeof(BaseFormInfoConverter))] public abstract class BaseFormInfo { // 原有代码 }
- 方式二:全局注册(Program.cs)
builder.Services.AddControllers() .AddNewtonsoftJson(options => { options.SerializerSettings.Converters.Add(new BaseFormInfoConverter()); });
注意事项
- 两种方案都依赖字段为可空类型(比如
int?、decimal?、string?),如果有非可空值类型需要处理,需额外调整逻辑设置默认值(但需求要求设为null,所以非可空值类型需要先改为可空)。 - 若使用
System.Text.Json,自定义转换器的写法略有不同,但核心递归检查、清空字段的逻辑一致。
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

