Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for registering internal validator types through FluentValidationMvcConfiguration #1748

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/aspnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ services.AddMvc()

Validators that are registered automatically using `RegisterValidationsFromAssemblyContaining` are registered as `Scoped` with the container rather than as `Singleton`. This is done to avoid lifecycle scoping issues where a developer may inadvertantly cause a singleton-scoped validator from depending on a Transient or Request-scoped service (for example, a DB context). If you are aware of these kind of issues and understand how to avoid them, then you may choose to register the validators as singletons instead, which will give a performance boost by passing in a second argument: `fv.RegisterValidatorsFromAssemblyContaining<PersonValidator>(lifetime: ServiceLifetime.Singleton)` (note that this optional parameter is only available in FluentValidation 9.0 or later).

By default, only public validators will be registered. To include internal validators you can set the `includeInternalTypes` optional parameter to `true` (e.g., `fv.RegisterValidatorsFromAssemblyContaining<PersonValidator>(includeInternalTypes: true)`).
By default, only public validators will be registered. To include internal validators you can set the `includeInternalValidatorTypes` optional parameter to `true` (e.g., `fv.RegisterValidatorsFromAssemblyContaining<PersonValidator>(includeInternalValidatorTypes: true)`).

You can also optionally prevent certain types from being automatically registered when using this approach by passing a filter to `RegisterValidationsFromAssemblyContaining`. For example, if there is a specific validator type that you don't want to be registered, you can use a filter callback to exclude it:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public class FluentValidationMvcConfiguration {
internal List<Assembly> AssembliesToRegister { get; } = new List<Assembly>();
internal Func<AssemblyScanner.AssemblyScanResult, bool> TypeFilter { get; set; }
internal ServiceLifetime ServiceLifetime { get; set; } = ServiceLifetime.Scoped;
internal bool IncludeInternalValidatorTypes { get; set; }

/// <summary>
/// Whether automatic server-side validation should be enabled (default true).
Expand All @@ -98,8 +99,9 @@ public class FluentValidationMvcConfiguration {
/// </summary>
/// <param name="filter">Optional filter that allows certain types to be skipped from registration.</param>
/// <param name="lifetime">The service lifetime that should be used for the validator registration. Defaults to Scoped</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssemblyContaining<T>(Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped) {
return RegisterValidatorsFromAssemblyContaining(typeof(T), filter, lifetime);
/// <param name="includeInternalTypes">Include internal validators. The default is false.</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssemblyContaining<T>(Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped, bool includeInternalTypes = false) {
return RegisterValidatorsFromAssemblyContaining(typeof(T), filter, lifetime, includeInternalTypes);
}

/// <summary>
Expand All @@ -108,8 +110,9 @@ public class FluentValidationMvcConfiguration {
/// <param name="type">The type that indicates which assembly that should be scanned</param>
/// <param name="filter">Optional filter that allows certain types to be skipped from registration.</param>
/// <param name="lifetime">The service lifetime that should be used for the validator registration. Defaults to Scoped</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssemblyContaining(Type type, Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped) {
return RegisterValidatorsFromAssembly(type.Assembly, filter, lifetime);
/// <param name="includeInternalTypes">Include internal validators. The default is false.</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssemblyContaining(Type type, Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped, bool includeInternalTypes = false) {
return RegisterValidatorsFromAssembly(type.Assembly, filter, lifetime, includeInternalTypes);
}

/// <summary>
Expand All @@ -118,11 +121,13 @@ public class FluentValidationMvcConfiguration {
/// <param name="assembly">The assembly to scan</param>
/// <param name="filter">Optional filter that allows certain types to be skipped from registration.</param>
/// <param name="lifetime">The service lifetime that should be used for the validator registration. Defaults to Scoped</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssembly(Assembly assembly, Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped) {
/// <param name="includeInternalTypes">Include internal validators. The default is false.</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssembly(Assembly assembly, Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped, bool includeInternalTypes = false) {
ValidatorFactoryType = typeof(ServiceProviderValidatorFactory);
AssembliesToRegister.Add(assembly);
TypeFilter = filter;
ServiceLifetime = lifetime;
IncludeInternalValidatorTypes = includeInternalTypes;
return this;
}

Expand All @@ -132,11 +137,13 @@ public class FluentValidationMvcConfiguration {
/// <param name="assemblies">The assemblies to scan</param>
/// <param name="filter">Optional filter that allows certain types to be skipped from registration.</param>
/// <param name="lifetime">The service lifetime that should be used for the validator registration. Defaults to Scoped</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssemblies(IEnumerable<Assembly> assemblies, Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped) {
/// <param name="includeInternalTypes">Include internal validators. The default is false.</param>
public FluentValidationMvcConfiguration RegisterValidatorsFromAssemblies(IEnumerable<Assembly> assemblies, Func<AssemblyScanner.AssemblyScanResult, bool> filter = null, ServiceLifetime lifetime = ServiceLifetime.Scoped, bool includeInternalTypes = false) {
ValidatorFactoryType = typeof(ServiceProviderValidatorFactory);
AssembliesToRegister.AddRange(assemblies);
TypeFilter = filter;
ServiceLifetime = lifetime;
IncludeInternalValidatorTypes = includeInternalTypes;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public static class FluentValidationMvcExtensions {
var config = new FluentValidationMvcConfiguration(ValidatorOptions.Global);
configurationExpression?.Invoke(config);

services.AddValidatorsFromAssemblies(config.AssembliesToRegister, config.ServiceLifetime, config.TypeFilter);
services.AddValidatorsFromAssemblies(config.AssembliesToRegister, config.ServiceLifetime, config.TypeFilter, config.IncludeInternalValidatorTypes);
services.AddSingleton(config.ValidatorOptions);

if (config.ValidatorFactory != null) {
Expand Down