Open Closed

How to remove/disable validation for existing DTO object #1340


User avatar
0
nhontran created
  • ABP Framework version: v3.3.2
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes
  • Exception message and stack trace:
  • Steps to reproduce the issue:

I want to remove/disable the [Required] attribute for "Password" field in IdentityUserCreateDto

It seems could not achieve it so I disabled the validation by putting [DisableValidation] in the CreateAsync method, but it does not work:

[Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IdentityUserController))]
    public class CustomIdentityUserController : IdentityUserController
    {
        public CustomIdentityUserController(IIdentityUserAppService userAppService) : base(userAppService)
        {
        }

        [DisableValidation]
        public override Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
        {
            return UserAppService.CreateAsync(input);
        }
    }

Any advice woule be appreciated much, thank you.


9 Answer(s)
  • User Avatar
    0
    alper created
    Support Team Director

    When you put a breakpoint in CreateAsync method, do you see it comes inside the method? I want to ensure that you successfully overrided the method.


    you may also use Fleunt Validation https://docs.abp.io/en/abp/latest/FluentValidation

  • User Avatar
    0
    nhontran created

    Hi @alper, yes, it hits the breakpoint inside the method.

    Regarding fluent validation, can give me some insights how to by pass the [Required] data annotation validation? As I know, it still triggers the data annotation validation before hit the FluentValidation.

    Thanks for your support.

  • User Avatar
    0
    alper created
    Support Team Director

    I think you disable the validation on the controller but in the controller method also calls the application service method. application service methods are also being validated automatically. so you need to replace the UserAppService and add [DisableValidation] attribute to the UserAppService CreateAsync method.

  • User Avatar
    0
    nhontran created

    Hi @alper, I tried to put [DisableValidation] to CreateAsync in both Controller and AppService, it still does not work.

    if the Password field has value, it hits the method -> the override is succesfully

    if the Password is null/empty, the validation is triggered -> the [DisableValidation] is not working

        [Dependency(ReplaceServices = true)]
        [ExposeServices(typeof(IdentityUserController))]
        public class CustomIdentityUserController : IdentityUserController
        {
            public CustomIdentityUserController(IIdentityUserAppService userAppService) : base(userAppService)
            {
            }
    
            [DisableValidation]
            public override Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
            {
                return UserAppService.CreateAsync(input);
            }
        }
    
        [Dependency(ReplaceServices = true)]
        [ExposeServices(typeof(IdentityUserAppService))]
        public class CustomIdentityUserAppService : IdentityUserAppService
        {
            public CustomIdentityUserAppService(
                IdentityUserManager userManager,
                IIdentityUserRepository userRepository,
                IIdentityRoleRepository roleRepository,
                IOrganizationUnitRepository organizationUnitRepository,
                IIdentityClaimTypeRepository identityClaimTypeRepository,
                IdentityTwoFactorManager identityTwoFactorManager
            ) : base(userManager,
                userRepository,
                roleRepository,
                organizationUnitRepository,
                identityClaimTypeRepository,
                identityTwoFactorManager)
            {
            }
    
            [DisableValidation]
            public override async Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
            {
                var user = new IdentityUser(
                    GuidGenerator.Create(),
                    input.UserName,
                    input.Email,
                    CurrentTenant.Id
                );
    
                input.MapExtraPropertiesTo(user);
    
                (await UserManager.CreateAsync(user)).CheckErrors();
                await UpdateUserByInput(user, input);
    
                await CurrentUnitOfWork.SaveChangesAsync();
    
                var userDto = ObjectMapper.Map<IdentityUser, IdentityUserDto>(user);
    
                return userDto;
            }
        }
    
  • User Avatar
    0
    alper created
    Support Team Director

    ok. so there might be a problem. created a issue. you can track this https://github.com/abpframework/abp/issues/9082

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Solution before upgrade:

    Use MyAbpValidationActionFilter to replace the build-in AbpValidationActionFilter.

    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc.Abstractions;
    using Microsoft.AspNetCore.Mvc.Filters;
    using Microsoft.Extensions.DependencyInjection;
    using Volo.Abp.AspNetCore.Mvc.Validation;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Reflection;
    using Volo.Abp.Validation;
    
    namespace MyCompanyName.MyProjectName.Web
    {
        public class MyAbpValidationActionFilter : IAsyncActionFilter, ITransientDependency
        {
            public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
            {
                if (!context.ActionDescriptor.IsControllerAction() ||
                    !context.ActionDescriptor.HasObjectResult())
                {
                    await next();
                    return;
                }
    
                if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(context.ActionDescriptor.GetMethodInfo()) != null)
                {
                    await next();
                    return;
                }
    
                if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(context.Controller.GetType()) != null)
                {
                    await next();
                    return;
                }
    
                if (context.ActionDescriptor.GetMethodInfo().DeclaringType != context.Controller.GetType())
                {
                    var baseMethod = context.ActionDescriptor.GetMethodInfo();
    
                    var overrideMethod = context.Controller.GetType().GetMethods().FirstOrDefault(x =>
                        x.DeclaringType == context.Controller.GetType() &&
                        x.Name == baseMethod.Name &&
                        x.ReturnType == baseMethod.ReturnType &&
                        x.GetParameters().Select(p => p.ToString()).SequenceEqual(baseMethod.GetParameters().Select(p => p.ToString())));
    
                    if (overrideMethod != null)
                    {
                        if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(overrideMethod) != null)
                        {
                            await next();
                            return;
                        }
                    }
                }
    
                context.HttpContext.RequestServices.GetRequiredService<IModelStateValidator>().Validate(context.ModelState);
                await next();
            }
        }
    }
    
    
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        var configuration = context.Services.GetConfiguration();
    
        PostConfigure<MvcOptions>(mvcOptions =>
        {
            mvcOptions.Filters.ReplaceOne(
                x => (x as ServiceFilterAttribute)?.ServiceType == typeof(AbpValidationActionFilter),
                new ServiceFilterAttribute(typeof(MyAbpValidationActionFilter)));
        });
    }
    
    
  • User Avatar
    0
    nhontran created

    Hi @maliming, thanks for your prompt reply.

    I just tried, the [DisableValidation] works in controller method but not in AppService method, the validation is still triggered.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    HI

    Can you try to add typeof(IIdentityUserAppService) to ExposeServices attribute?

    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IdentityUserAppService), typeof(IIdentityUserAppService))]
    public class CustomIdentityUserAppService : IdentityUserAppService
    
  • User Avatar
    0
    nhontran created

    Hi @maliming, yup, it works now.

    Thanks for your support!!!

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11