Browse Source

Separate validators from the DTO, Extend current validation interceptor.

pull/1003/head
maliming 7 years ago
parent
commit
6bd1ff7cbf
  1. 1
      framework/src/Volo.Abp.FluentValidation/Volo.Abp.FluentValidation.csproj
  2. 41
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/AbpFluentValidationConventionalRegistrar.cs
  3. 7
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/AbpFluentValidationCrossCuttingConcern.cs
  4. 12
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/AbpFluentValidationModule.cs
  5. 15
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentMethodInvocationValidator.cs
  6. 53
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentValidationInterceptor.cs
  7. 16
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentValidationInterceptorRegistrar.cs
  8. 12
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/IFluentValidator.cs
  9. 8
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs
  10. 4
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationOptions.cs
  11. 4
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs
  12. 32
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs
  13. 65
      framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs

1
framework/src/Volo.Abp.FluentValidation/Volo.Abp.FluentValidation.csproj

@ -18,7 +18,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.Validation\Volo.Abp.Validation.csproj" />
</ItemGroup>

41
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/AbpFluentValidationConventionalRegistrar.cs

@ -0,0 +1,41 @@
using System;
using FluentValidation;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.FluentValidation
{
public class AbpFluentValidationConventionalRegistrar : DefaultConventionalRegistrar
{
public override void AddType(IServiceCollection services, Type type)
{
if (typeof(IValidator).IsAssignableFrom(type))
{
var dtoType = GetFirstGenericArgumentOrNull(type, 1);
if (dtoType != null)
{
var serverType = typeof(IValidator<>).MakeGenericType(dtoType);
var serviceDescriptor = ServiceDescriptor.Describe(serverType, type, ServiceLifetime.Transient);
services.Add(serviceDescriptor);
}
}
}
private static Type GetFirstGenericArgumentOrNull(Type type, int depth)
{
const int maxFindDepth = 8;
if (depth >= maxFindDepth)
{
return null;
}
if (type.IsGenericType && type.GetGenericArguments().Length >= 1)
{
return type.GetGenericArguments()[0];
}
return GetFirstGenericArgumentOrNull(type.BaseType, depth + 1);
}
}
}

7
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/AbpFluentValidationCrossCuttingConcern.cs

@ -1,7 +0,0 @@
namespace Volo.Abp.FluentValidation
{
public static class AbpFluentValidationCrossCuttingConcern
{
public const string FluentValidation = "AbpFluentValidation";
}
}

12
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/AbpFluentValidationModule.cs

@ -1,13 +1,23 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
namespace Volo.Abp.FluentValidation
{
[DependsOn(typeof(AbpValidationModule))]
public class AbpFluentValidationModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistred(FluentValidationInterceptorRegistrar.RegisterIfNeeded);
context.Services.AddConventionalRegistrar(new AbpFluentValidationConventionalRegistrar());
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpValidationOptions>(options =>
{
options.ValidationContributor.Add<FluentMethodInvocationValidator>();
});
}
}
}

15
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentValidator.cs → framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentMethodInvocationValidator.cs

@ -1,21 +1,30 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using FluentValidation;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Validation;
namespace Volo.Abp.FluentValidation
{
public class FluentValidator : IFluentValidator, ITransientDependency
public class FluentMethodInvocationValidator : IMethodInvocationValidator, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public FluentMethodInvocationValidator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Validate(MethodInvocationValidationContext context)
{
var validationResult = new AbpValidationResult();
foreach (var parameterValue in context.ParameterValues)
{
if (parameterValue is IValidator validator)
var serverType = typeof(IValidator<>).MakeGenericType(parameterValue.GetType());
if (_serviceProvider.GetService(serverType) is IValidator validator)
{
var result = validator.Validate(parameterValue);
if (!result.IsValid)

53
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentValidationInterceptor.cs

@ -1,53 +0,0 @@
using System.Threading.Tasks;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Validation;
namespace Volo.Abp.FluentValidation
{
public class FluentValidationInterceptor : AbpInterceptor, ITransientDependency
{
private readonly IFluentValidator _fluentValidator;
public FluentValidationInterceptor(IFluentValidator fluentValidator)
{
_fluentValidator = fluentValidator;
}
public override void Intercept(IAbpMethodInvocation invocation)
{
if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpFluentValidationCrossCuttingConcern.FluentValidation))
{
invocation.Proceed();
return;
}
Validate(invocation);
invocation.Proceed();
}
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpFluentValidationCrossCuttingConcern.FluentValidation))
{
await invocation.ProceedAsync();
return;
}
Validate(invocation);
await invocation.ProceedAsync();
}
protected virtual void Validate(IAbpMethodInvocation invocation)
{
_fluentValidator.Validate(new MethodInvocationValidationContext(
invocation.TargetObject,
invocation.Method,
invocation.Arguments
));
}
}
}

16
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentValidationInterceptorRegistrar.cs

@ -1,16 +0,0 @@
using FluentValidation;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.FluentValidation
{
public static class FluentValidationInterceptorRegistrar
{
public static void RegisterIfNeeded(IOnServiceRegistredContext context)
{
if (typeof(IValidator).IsAssignableFrom(context.ImplementationType))
{
context.Interceptors.TryAdd<FluentValidationInterceptor>();
}
}
}
}

12
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/IFluentValidator.cs

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Validation;
namespace Volo.Abp.FluentValidation
{
public interface IFluentValidator
{
void Validate(MethodInvocationValidationContext context);
}
}

8
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs

@ -9,5 +9,13 @@ namespace Volo.Abp.Validation
{
context.Services.OnRegistred(ValidationInterceptorRegistrar.RegisterIfNeeded);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpValidationOptions>(options =>
{
options.ValidationContributor.Add<MethodInvocationValidator>();
});
}
}
}

4
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IValidationConfiguration.cs → framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationOptions.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Collections;
namespace Volo.Abp.Validation
{
@ -7,9 +8,12 @@ namespace Volo.Abp.Validation
{
public List<Type> IgnoredTypes { get; }
public ITypeList<IMethodInvocationValidator> ValidationContributor { get; set; }
public AbpValidationOptions()
{
IgnoredTypes = new List<Type>();
ValidationContributor = new TypeList<IMethodInvocationValidator>();
}
}
}

4
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs

@ -1,7 +1,7 @@
namespace Volo.Abp.Validation
namespace Volo.Abp.Validation
{
public interface IMethodInvocationValidator
{
void Validate(MethodInvocationValidationContext context);
}
}
}

32
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs

@ -1,4 +1,7 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
@ -7,11 +10,13 @@ namespace Volo.Abp.Validation
{
public class ValidationInterceptor : AbpInterceptor, ITransientDependency
{
private readonly IMethodInvocationValidator _validator;
private readonly AbpValidationOptions _abpValidationOptions;
private readonly IServiceProvider _serviceProvider;
public ValidationInterceptor(IMethodInvocationValidator validator)
public ValidationInterceptor(IServiceProvider serviceProvider, IOptions<AbpValidationOptions> abpValidationOptions)
{
_validator = validator;
_serviceProvider = serviceProvider;
_abpValidationOptions = abpValidationOptions.Value;
}
public override void Intercept(IAbpMethodInvocation invocation)
@ -42,13 +47,18 @@ namespace Volo.Abp.Validation
protected virtual void Validate(IAbpMethodInvocation invocation)
{
_validator.Validate(
new MethodInvocationValidationContext(
invocation.TargetObject,
invocation.Method,
invocation.Arguments
)
);
foreach (var validationContributor in _abpValidationOptions.ValidationContributor)
{
var validator = (IMethodInvocationValidator) _serviceProvider.GetRequiredService(validationContributor);
validator.Validate(
new MethodInvocationValidationContext(
invocation.TargetObject,
invocation.Method,
invocation.Arguments
)
);
}
}
}
}

65
framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs

@ -1,4 +1,4 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
using FluentValidation;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
@ -91,6 +91,18 @@ namespace Volo.Abp.FluentValidation
}));
}
[Fact]
public void NotValidateMyMethod_Test()
{
var output = _myAppService.NotValidateMyMethod(new MyMethodInput4
{
MyStringValue4 = "444"
});
output.ShouldBe("444");
}
[DependsOn(typeof(AbpAutofacModule))]
[DependsOn(typeof(AbpFluentValidationModule))]
public class TestModule : AbpModule
@ -101,7 +113,7 @@ namespace Volo.Abp.FluentValidation
{
if (typeof(IMyAppService).IsAssignableFrom(onServiceRegistredContext.ImplementationType))
{
onServiceRegistredContext.Interceptors.TryAdd<FluentValidationInterceptor>();
onServiceRegistredContext.Interceptors.TryAdd<ValidationInterceptor>();
}
});
}
@ -117,6 +129,8 @@ namespace Volo.Abp.FluentValidation
string MyMethod(MyMethodInput input);
Task<string> MyMethodAsync(MyMethodInput input);
string NotValidateMyMethod(MyMethodInput4 input);
}
public class MyAppService : IMyAppService, ITransientDependency
@ -131,17 +145,15 @@ namespace Volo.Abp.FluentValidation
return Task.FromResult(input.MyStringValue + input.MyMethodInput2.MyStringValue2 +
input.MyMethodInput3.MyStringValue3);
}
}
public class MyMethodInput : AbstractValidator<MyMethodInput>
{
public MyMethodInput()
public string NotValidateMyMethod(MyMethodInput4 input)
{
RuleFor(x => x.MyStringValue).Equal("aaa");
RuleFor(x => x.MyMethodInput2.MyStringValue2).Equal("bbb");
RuleFor(customer => customer.MyMethodInput3).SetValidator(new MyMethodInput3());
return input.MyStringValue4;
}
}
public class MyMethodInput
{
public string MyStringValue { get; set; }
public MyMethodInput2 MyMethodInput2 { get; set; }
@ -154,14 +166,41 @@ namespace Volo.Abp.FluentValidation
public string MyStringValue2 { get; set; }
}
public class MyMethodInput3 : AbstractValidator<MyMethodInput3>
public class MyMethodInput3
{
public MyMethodInput3()
public string MyStringValue3 { get; set; }
}
public class MyMethodInput4
{
public string MyStringValue4 { get; set; }
}
public class MyMethodInputValidator : AbstractValidator<MyMethodInput>
{
public MyMethodInputValidator()
{
RuleFor(x => x.MyStringValue3).Equal("ccc");
RuleFor(x => x.MyStringValue).Equal("aaa");
RuleFor(x => x.MyMethodInput2.MyStringValue2).Equal("bbb");
RuleFor(customer => customer.MyMethodInput3).SetValidator(new MyMethodInput3Validator());
}
}
public string MyStringValue3 { get; set; }
public class MethodInputBaseValidator : AbstractValidator<MyMethodInput3>
{
public MethodInputBaseValidator()
{
RuleFor(x => x.MyStringValue3).NotNull();
}
}
public class MyMethodInput3Validator : MethodInputBaseValidator
{
public MyMethodInput3Validator()
{
RuleFor(x => x.MyStringValue3).Equal("ccc");
}
}
}
}
Loading…
Cancel
Save