ASP.NET Core自定义Model Binder解析失败且不触发Required校验问题
自定义Model Binder不触发Required校验问题解决方案
问题原因
模型绑定阶段的错误优先级高于属性校验逻辑:你当前的自定义HeaderComplexModelBinder在对不可空类型做值转换/反序列化时,直接抛出了转换异常,框架捕获异常后会直接终止流程并返回绑定错误,不会进入后续的DataAnnotations校验阶段,因此属性上标注的Required不会生效。
解决方案
方案1:修改自定义Model Binder实现(推荐)
调整HeaderComplexModelBinder的逻辑,转换失败时不抛出异常,将错误信息写入ModelState后继续完成绑定流程,让后续校验逻辑可正常执行,示例代码如下:
public class HeaderComplexModelBinder : IModelBinder { public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } // 实例化目标复杂模型 var model = Activator.CreateInstance(bindingContext.ModelType); var propertyMetadatas = bindingContext.ModelMetadata.Properties; foreach (var propertyMeta in propertyMetadatas) { // 只处理标注了FromHeader的属性 var fromHeaderAttr = propertyMeta.Attributes.OfType<FromHeaderAttribute>().FirstOrDefault(); if (fromHeaderAttr == null) continue; var headerName = fromHeaderAttr.Name ?? propertyMeta.Name; // 从请求头读取值 if (bindingContext.HttpContext.Request.Headers.TryGetValue(headerName, out var headerValues)) { try { // 执行类型转换 var convertedValue = Convert.ChangeType(headerValues.ToString(), propertyMeta.ModelType); propertyMeta.PropertySetter(model, convertedValue); } catch { // 转换失败仅记录错误,不中断流程 bindingContext.ModelState.TryAddModelError( propertyMeta.Name, $"请求头{headerName}格式不符合要求" ); } } // 值不存在时不主动赋值,留到校验阶段处理 } // 返回绑定成功,触发后续校验逻辑 bindingContext.Result = ModelBindingResult.Success(model); await Task.CompletedTask; } }
方案2:属性声明为可空类型
将不可空值类型属性改为可空类型,避免绑定阶段直接抛出转换错误,空值会被留到校验阶段触发Required校验,示例模型定义如下:
public class AuthHeaderModel { [Required(ErrorMessage = "cui请求头不能为空")] public long? Cui { get; set; } }
方案3:调整框架配置(适配Body绑定场景)
如果你的参数是从请求Body绑定,可通过配置修改反序列化和绑定逻辑,避免转换失败直接报错:
services.AddControllers(options => { options.SuppressInferBindingSourcesForParameters = true; options.AllowEmptyInputInBodyModelBinding = true; }) .AddJsonOptions(options => { // 允许数字从字符串读取,降低转换失败概率 options.JsonSerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString; });
内容的提问来源于stack exchange,提问作者PontiacGTX
相关产品推荐
相关产品推荐

