Fluent Validation遇输入首尾带\时抛出System.ArgumentNullException求助
问题
在应用中使用Fluent Validation校验用户输入时发现:当输入字符串首尾带有\字符(如" ferrari\ "或" \ferrari ")时,校验失败并抛出System.ArgumentNullException异常;移除该字符或放置在其他位置时,校验正常。
使用的校验规则如下:
RuleFor(cb => cb.Address) .NotEmpty().WithMessage("The Address field is required.") .Matches("^[a-zA-Z0-9 ]+$").WithMessage("The Address field must contain only letters and numbers.");
完整错误日志:
System.ArgumentNullException: Cannot pass null model to Validate. (Parameter 'instanceToValidate') at FluentValidation.AbstractValidator`1.EnsureInstanceNotNull(Object instanceToValidate) in /Users/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 516 at FluentValidation.AbstractValidator`1.ValidateAsync(ValidationContext`1 context, CancellationToken cancellation) in /Users/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 247 at ecommerce.Controllers.AuthController.Login(DTO_CustomerLogin customer) in D:\Lavoro\ecommerce\ecommerce\ecommerce\Controllers\AuthController.cs:line 30 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) HEADERS ======= Accept: */* Host: localhost:7298 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 OPR/98.0.0.0 :method: POST Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Content-Type: application/json-patch+json Cookie: wordpress_test_cookie=WP%20Cookie%20check,wordpress_logged_in_743590ba59234b9fc8eaaf393199b671=admin%7C1685559922%7C2IGA4sVh57u8X2IiPvPH55IiFpWW8Bbh7A6bJeAOPCY%7C5922389646a2f0cdae23863404146ff7a36b7e4ec26b2cee87d6495403b7c9c2,tk_ai=woo%3A7xGM8dng5IbSM3DfhUjxnCMi,wp-settings-time-1=1685387348 Origin: https://localhost:7298 Referer: https://localhost:7298/swagger/index.html Content-Length: 48 sec-ch-ua: "Chromium";v="112", "Not_A Brand";v="24", "Opera GX";v="98" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" sec-fetch-site: same-origin sec-fetch-mode: cors sec-fetch-dest: empty
解决方案
异常原因分析
这个异常并非Fluent Validation的校验逻辑抛出,而是模型绑定阶段出错:JSON中的\是转义字符,当输入首尾出现未正确转义的\时,JSON解析器无法正确解析请求体,导致控制器接收的DTO_CustomerLogin实例为null。Fluent Validation校验null模型时,就会触发ArgumentNullException。
具体解决步骤
修正JSON输入格式
确保前端传入的JSON合法,所有\必须转义为\\。如果是用Swagger测试,手动输入时要把\写成\\,否则Swagger会将单个\当作转义符处理,导致JSON格式错误。添加控制器前置校验
在控制器方法中先判断传入的模型是否为null,提前返回错误响应,避免进入Fluent Validation流程:[HttpPost] public async Task<IActionResult> Login(DTO_CustomerLogin customer) { if (customer == null) { return BadRequest("请求体格式无效,请检查输入内容。"); } // 执行Fluent Validation校验 var validationResult = await _validator.ValidateAsync(customer); if (!validationResult.IsValid) { return BadRequest(validationResult.Errors); } // 后续业务逻辑 // ... }优化Fluent Validation规则(可选)
若需要明确禁止输入\字符,可保留现有正则规则(已排除\),同时添加NotNull规则增强容错:RuleFor(cb => cb.Address) .NotNull().WithMessage("地址字段不能为空。") .NotEmpty().WithMessage("地址字段不能为空。") .Matches("^[a-zA-Z0-9 ]+$").WithMessage("地址字段只能包含字母、数字和空格。");配置JSON解析器容错(可选)
在ASP.NET Core的Program.cs中配置JSON解析器,处理非法转义的情况,避免模型绑定为null:builder.Services.AddControllers() .AddJsonOptions(options => { // 忽略注释、允许 trailing commas options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip; options.JsonSerializerOptions.AllowTrailingCommas = true; // 若使用Newtonsoft.Json,可配置错误处理 // options.UseNewtonsoftJson(settings => // { // settings.Error = (sender, args) => args.ErrorContext.Handled = true; // }); });
内容的提问来源于stack exchange,提问作者Petruz21
相关产品推荐
相关产品推荐

