.NET Core 如何使用FileValidationAttribute结合DocumentType验证文件类型
问题根因
ASP.NET Core的模型绑定与验证顺序和Dto内属性的定义顺序完全一致。你当前的DocumentUploadDto中File属性定义在DocumentType之前,执行File上的验证特性时,DocumentType还未完成赋值,只能拿到枚举类型的默认值(即第一个定义的BANKSTATEMENT),这就是你始终只能拿到第一个枚举值的原因。
可行解决方案
方案1:调整Dto属性顺序(改造成本最低)
只需要把DocumentType属性移到File属性之前,模型绑定会先赋值DocumentType,再验证File时就能拿到正确的枚举值,原有验证逻辑无需修改:
public class DocumentUploadDto { // 调整到File之前,先完成绑定赋值 public ApplicationDocumentType DocumentType { get; set; } [FileValidation] public IFormFile File { get; set; } public Guid Id { get; set; } }
方案2:使用类级验证IValidatableObject(推荐,可维护性最高)
直接让Dto实现IValidatableObject接口,所有属性绑定完成后才会执行Validate方法,无需反射就能直接获取所有属性值,逻辑更清晰:
public class DocumentUploadDto : IValidatableObject { public IFormFile File { get; set; } public ApplicationDocumentType DocumentType { get; set; } public Guid Id { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (File == null) { yield return new ValidationResult("No file found.", new[] { nameof(File) }); } // 直接获取DocumentType值,无需反射 if (DocumentType == ApplicationDocumentType.NRIC && File.ContentType == "application/pdf") { yield return new ValidationResult( "Invalid file type. Pdf file type is not allowed for NRIC.", new[] { nameof(File) } ); } // 剩余差异化校验逻辑可以都放在这里 } }
方案3:从请求上下文直接获取参数(无需修改Dto结构)
如果不想调整Dto结构,可以在验证特性中通过IHttpContextAccessor直接读取请求提交的DocumentType参数:
- 先在Startup/Program.cs中注册服务:
services.AddHttpContextAccessor();
- 修改验证特性逻辑:
public class FileValidationAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var file = value as IFormFile; if (file == null) return new ValidationResult("No file found."); // 从服务容器获取HttpContext访问器 var httpAccessor = validationContext.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor; if (httpAccessor?.HttpContext?.Request.Form.TryGetValue("DocumentType", out var dtStr) == true) { // 转换为枚举类型 if (Enum.TryParse<ApplicationDocumentType>(dtStr, out var docType)) { if (docType == ApplicationDocumentType.NRIC && file.ContentType == "application/pdf") { return new ValidationResult("Invalid file type. Pdf file type is not allowed for NRIC."); } } } // 原有通用校验逻辑 return ValidationResult.Success; } }
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

