Open Closed

Using Fluent Validation with Conventional Controllers #937


0
Thiqah.Abp created
  • ABP Framework version: v4.2.1
  • UI type: No
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no
  1. I have created a simple Application service with one post method (Just return success)
  2. Added a simple Dto to the application service.
  3. Created a simple fluent validator for the Dto.
  4. Created a controller implements the Application Service interface.
  5. Keep Conventional Controllers configuration in the host project enabled.

I ended up with two endpoints appear on the Swagger: one for the controller and the other one from the Convension. The problem is that the Fluent Validation is not being called by Conventional Controllers, but working fine for the real controller action.

Should it work? or the fluent validation is not working with Conventional Controllers? Or there is a missing configuration?

Update 21/2/2021: Seems it's not related to Fluent Validation. I have tried to add my custom IObjectValidationContributor and it's called only from Controller and not from Conventional one!


4 Answer(s)
  • 0
    maliming created
    Support Team

    hi

    Can you share the full source code to reporduce the problem?

  • 0
    Thiqah.Abp created

    hi

    Can you share the full source code to reporduce the problem?

    I have reproduced the case with just an empty template and a simple application service bellow:

    In Application.Contracts project:

    [DependsOn(typeof(AbpFluentValidationModule)] Added to Module class

    //Dto
    public class SampleInputDto : EntityDto<Guid>
    {
        public string RegistrationNumber { get; set; }
    }
    
    //Validator
    public class SampleInputValidator : AbstractValidator<SampleInputDto>
    {
       public SampleInputValidator()
       {
          RuleFor(input => input.RegistrationNumber)
                .NotEmpty()
                .MaximumLength(25);
       }
    }
    
    //Application service Interface
    public interface ISampleAppService
    {
       Task AddAsync(SampleInputDto input);
    }
    

    In Application project:

    public class SampleAppService : AbpFluentValidationDemoAppService, ISampleAppService
    {
         [Route("add")]
         public Task AddAsync(SampleInputDto input)
         {
             return Task.CompletedTask;
         }
    }
    

    In HttpApi project (Controllers):

    [Route("api/Sample")]
    public class SampleController : AbpFluentValidationDemoController, ISampleAppService
    {
         private readonly ISampleAppService _sampleService;
    
         public SampleController(ISampleAppService sampleService)
         {
             _sampleService = sampleService;
         }
    
        [HttpPost]
        [Route("add")]
        public Task AddAsync(SampleInputDto input)
        {
            return _sampleService.AddAsync(input);
        }
    }
    
  • 0
    maliming created
    Support Team

    hi

    The SampleAppService inherited the IValidationEnabled interface, but SampleController not.

    Defines IValidationEnabled to add automatic validation to an arbitrary class. Since all the application services inherently implements it, they are also validated automatically.

    https://docs.abp.io/en/abp/latest/Validation https://docs.abp.io/en/abp/latest/Validation#validation-infrastructure

  • 0
    Thiqah.Abp created

    Still not working! Calling the generated conventional controller does not validae the input. However, after reading the documentation again and again, I figured the issue:

    ABP framework uses the dynamic proxying / interception system to perform the validation. In order to make it working, your method should be virtual or your service should be injected and used over an interface (like IMyService).

    https://docs.abp.io/en/abp/latest/Validation#validation-infrastructure

    Our problem is that the Application Service Method is not virtual, after adding the virtual keyword to the method, it works.