如何验证发送至Azure函数的参数?(WebApi迁移场景)
嘿,我来帮你搞定Azure Functions里的参数自动验证问题!你之前在Web API里靠ActionFilterAttribute自动校验ModelState的思路完全可以迁移过来,不过因为Azure Functions的执行模型和Web API有点不一样,得稍微调整下实现方式,我给你列几种实用的方案:
在Azure Functions中实现参数自动验证的方法
方法1:自定义绑定(推荐,通用型强)
Azure Functions支持自定义绑定,我们可以用这个特性来封装通用的验证逻辑,不用在每个函数里重复写校验代码。
首先,创建一个标记用的自定义属性:
[AttributeUsage(AttributeTargets.Parameter)] public class ValidatedAttribute : Attribute { }
接着实现绑定的核心逻辑,负责接收参数并执行验证:
public class ValidatedBindingProvider : IBindingProvider { public Task<IBinding> TryCreateAsync(BindingProviderContext context) { if (context.Parameter.GetCustomAttribute<ValidatedAttribute>() == null) { return Task.FromResult<IBinding>(null); } var binding = new ValidatedBinding(context.Parameter.ParameterType); return Task.FromResult<IBinding>(binding); } } public class ValidatedBinding : IBinding { private readonly Type _parameterType; public ValidatedBinding(Type parameterType) { _parameterType = parameterType; } public bool CanBind(IBindingContext context) => true; public Task<object> BindAsync(IBindingContext context, CancellationToken cancellationToken) { var value = context.BindingData.FirstOrDefault(kv => kv.Value?.GetType() == _parameterType).Value; if (value == null) { throw new ValidationException("请求参数不能为空"); } var validationContext = new ValidationContext(value); var validationResults = new List<ValidationResult>(); if (!Validator.TryValidateObject(value, validationContext, validationResults, validateAllProperties: true)) { var errorMessages = validationResults.Select(r => r.ErrorMessage).ToList(); throw new ValidationException(string.Join("; ", errorMessages)); } return Task.FromResult(value); } }
然后在Startup类里注册这个自定义绑定(进程内模型用这个,如果是隔离进程模型,需要在Program.cs里配置):
public class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { builder.Services.AddSingleton<IBindingProvider, ValidatedBindingProvider>(); } }
最后在你的Function里直接用这个属性标记要验证的DTO参数:
public class MyFunction { [FunctionName("TestFunction")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, [Validated] TestDto dto, ILogger log) { // 这里的dto已经是验证通过的,直接写业务逻辑就行 return new OkObjectResult($"Hello {dto.Name}"); } }
方法2:Filter风格的中间件(仅HTTP触发函数)
如果你更习惯Web API里的Filter写法,在Azure Functions进程内模型中,可以用FunctionInvocationFilterAttribute来实现类似全局/局部验证的效果:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class ValidateModelStateAttribute : FunctionInvocationFilterAttribute { public override async Task OnExecutingAsync(FunctionExecutingContext context, CancellationToken cancellationToken) { // 遍历所有参数,自动验证DTO类型的参数 foreach (var parameter in context.Arguments.Values) { if (parameter == null) continue; var validationContext = new ValidationContext(parameter); var validationResults = new List<ValidationResult>(); if (!Validator.TryValidateObject(parameter, validationContext, validationResults, validateAllProperties: true)) { var errors = validationResults.ToDictionary( r => r.MemberNames.FirstOrDefault() ?? "Unknown", r => r.ErrorMessage ); context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; await context.HttpContext.Response.WriteAsJsonAsync(new { Errors = errors }); // 取消后续函数执行 context.CancellationTokenSource.Cancel(); return; } } await base.OnExecutingAsync(context, cancellationToken); } }
把这个Attribute加到Function类或者单个方法上就行:
[ValidateModelState] public class MyFunction { [FunctionName("TestFunction")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] TestDto dto, ILogger log) { return new OkObjectResult($"Hello {dto.Name}"); } }
方法3:手动验证(简单场景快速实现)
如果你的函数数量不多,也可以直接在函数内部手动写验证逻辑,虽然重复代码多胜在简单直接:
[FunctionName("TestFunction")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] TestDto dto, ILogger log) { var validationContext = new ValidationContext(dto); var validationResults = new List<ValidationResult>(); if (!Validator.TryValidateObject(dto, validationContext, validationResults, validateAllProperties: true)) { var errors = validationResults.ToDictionary( r => r.MemberNames.FirstOrDefault() ?? "Unknown", r => r.ErrorMessage ); return new BadRequestObjectResult(new { Errors = errors }); } // 业务逻辑代码 return new OkObjectResult($"Hello {dto.Name}"); }
小提示
- 如果用的是隔离进程模型,自定义绑定的实现需要调整,这时候更推荐用中间件来处理验证逻辑。
- 不管哪种方式,都要确保你的DTO上的验证特性(比如
[Required]、[StringLength])是正确的,.NET自带的Validator类会自动识别这些特性。
内容的提问来源于stack exchange,提问作者Cedric Arnould
相关产品推荐
相关产品推荐

