.NET Core 2.0中如何在方法执行前获取并验证参数?
针对你在.NET Core项目中想要在非控制器方法SaveComponent执行前验证参数componentToSave并抛出异常的需求,结合你已经排除的PostSharp、Autofac相关库、NConcern、ActionFilter、RealProxy这些方案,这里有几个适配.NET Core内置DI且可行的解决方案:
方案1:手动封装验证逻辑(零额外依赖,快速落地)
这是最直接的方式,适合不想引入第三方库的场景。你可以把验证逻辑抽成独立的类或方法,在SaveComponent执行前显式调用:
// 定义独立的验证器类,集中管理所有组件验证规则 public class ComponentValidator { public void Validate(Component component) { if (component == null) throw new ArgumentNullException(nameof(component)); if (string.IsNullOrWhiteSpace(component.Name)) throw new ArgumentException("组件名称不能为空", nameof(component.Name)); // 可添加更多业务相关的验证规则,比如ID合法性、状态校验等 } } // 在你的业务服务类中注入验证器并调用 public class ComponentService { private readonly ComponentValidator _validator; public ComponentService(ComponentValidator validator) { _validator = validator; } public Component SaveComponent(Component componentToSave) { // 执行保存前先触发验证 _validator.Validate(componentToSave); // 原有保存业务逻辑... return componentToSave; } }
优点:简单易懂,无任何第三方依赖,调试和维护成本低;缺点:如果多个方法需要类似验证,会存在重复的验证调用代码。
方案2:使用Castle DynamicProxy配合内置DI实现拦截
虽然.NET Core没有内置AOP拦截,但可以通过Castle DynamicProxy实现,并且能和内置DI无缝集成,不需要替换整个DI容器。
步骤如下:
- 安装NuGet包:
Castle.Core - 创建拦截器类,实现
IInterceptor接口处理验证逻辑:
public class ComponentValidationInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { // 判断当前拦截的方法是否是目标方法 if (invocation.Method.Name == nameof(IComponentService.SaveComponent)) { var componentToSave = invocation.Arguments[0] as Component; if (componentToSave == null) throw new ArgumentNullException(nameof(componentToSave)); if (string.IsNullOrWhiteSpace(componentToSave.Name)) throw new ArgumentException("组件名称不能为空", nameof(componentToSave.Name)); // 其他验证规则... } // 验证通过后执行原方法逻辑 invocation.Proceed(); } }
- 给服务定义接口(Castle拦截需要基于接口实现):
public interface IComponentService { Component SaveComponent(Component componentToSave); } public class ComponentService : IComponentService { public Component SaveComponent(Component componentToSave) { // 原有保存逻辑... return componentToSave; } }
- 在DI容器中注册服务时用代理包装:
builder.Services.AddScoped<ComponentValidationInterceptor>(); builder.Services.AddScoped<IComponentService>(sp => { var proxyGenerator = new ProxyGenerator(); var targetService = sp.GetRequiredService<ComponentService>(); var interceptor = sp.GetRequiredService<ComponentValidationInterceptor>(); return proxyGenerator.CreateInterfaceProxyWithTarget<IComponentService>(targetService, interceptor); }); builder.Services.AddScoped<ComponentService>();
优点:可以统一处理多个方法的验证逻辑,避免重复代码,扩展性强;缺点:需要依赖Castle.Core,且要求服务基于接口实现。
方案3:使用.NET源代码生成器实现编译期AOP
这是.NET Core 3.0+支持的特性,通过在编译时生成带验证逻辑的代码,没有运行时开销,也不需要第三方依赖,适合需要大量重复验证逻辑的场景。
核心思路:
- 定义自定义特性标记需要验证的方法:
[AttributeUsage(AttributeTargets.Method)] public class ValidateComponentAttribute : Attribute { }
- 编写源代码生成器,扫描带有
ValidateComponentAttribute的方法,自动生成包含验证逻辑的包装代码。比如生成一个继承原服务类的子类,重写目标方法,先执行验证再调用父类逻辑。 - 在DI容器中注册生成的子类,替代原服务类。
示例生成器的核心逻辑(简化版):
[Generator] public class ComponentValidationGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { // 初始化逻辑,注册特性接收器 } public void Execute(GeneratorExecutionContext context) { // 扫描项目中带有ValidateComponentAttribute的方法 // 自动生成如下类似的代码: /* public class ValidatedComponentService : ComponentService { public override Component SaveComponent(Component componentToSave) { if (componentToSave == null) throw new ArgumentNullException(nameof(componentToSave)); if (string.IsNullOrWhiteSpace(componentToSave.Name)) throw new ArgumentException("组件名称不能为空", nameof(componentToSave.Name)); return base.SaveComponent(componentToSave); } } */ } }
优点:无运行时依赖,性能最优,编译期就完成代码注入;缺点:需要编写源代码生成器代码,有一定学习成本。
内容的提问来源于stack exchange,提问作者Node.JS
相关产品推荐
相关产品推荐

