如何批量配置类型注册以减少依赖注入重复代码?
Absolutely! You can ditch that repetitive boilerplate registration code in a snap by leveraging Autofac's assembly scanning capabilities—this is exactly the kind of scenario it’s designed to solve. Instead of manually registering each IValidator<T> implementation one by one, you can set up a single batch registration that automatically picks up all your validators and applies your shared configuration.
Step-by-Step Solution
Here’s how to implement it:
Target the right assembly: First, reference the assembly where your validator classes live. You can use any validator type to grab its parent assembly:
// Use one of your existing validator types to locate the assembly var validatorAssembly = typeof(UserViewModelValidation).Assembly;Set up batch registration: Use
RegisterAssemblyTypesto scan the assembly, filter for validators, and apply your universal settings:builder.RegisterAssemblyTypes(validatorAssembly) // Filter to only include classes that implement IValidator<T> (closed generic types) .Where(t => t.IsClosedTypeOf(typeof(IValidator<>))) // Register each validator as all of its implemented interfaces (matches IValidator<T>) .AsImplementedInterfaces() // Apply your shared configuration .PropertiesAutowired() .InstancePerLifetimeScope();
How This Works
Let’s break down the key parts:
RegisterAssemblyTypes(validatorAssembly): Tells Autofac to scan all types in the specified assembly.Where(t => t.IsClosedTypeOf(typeof(IValidator<>))): Filters the types to only include classes that are concrete implementations of theIValidator<T>generic interface (e.g.,UserViewModelValidationforIValidator<UserViewModel>).AsImplementedInterfaces(): Automatically registers each validator class against all the interfaces it implements—this perfectly replaces your manual.As<IValidator<...>>()calls for each type.- The final
.PropertiesAutowired()and.InstancePerLifetimeScope()apply your required shared configuration to every registered validator, just like your original code.
Additional Customizations
If you need to adjust the setup for edge cases:
Multiple Assemblies
If your validators are spread across multiple assemblies, pass an array of assemblies to RegisterAssemblyTypes:
var assemblies = new[] { typeof(UserViewModelValidation).Assembly, typeof(OrderValidation).Assembly }; builder.RegisterAssemblyTypes(assemblies) .Where(t => t.IsClosedTypeOf(typeof(IValidator<>))) .AsImplementedInterfaces() .PropertiesAutowired() .InstancePerLifetimeScope();
Exclude Specific Types
To skip abstract base classes or other non-concrete validators, add an extra check in the Where clause:
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)) && !t.IsAbstract)
Wrap-Up
This approach eliminates the need for manual registration of every new validator you add. From now on, any class that implements IValidator<T> in your target assembly will be automatically registered with your desired configuration—no more copy-pasting those repetitive lines!
内容的提问来源于stack exchange,提问作者Ciaran Gallagher

