mirror of https://github.com/abpframework/abp.git
Browse Source
When Application Services are registered via ConventionalControllers.Create(), their types are added to DynamicProxyIgnoreTypes, which disables the ValidationInterceptor. The AbpValidationActionFilter only checked ModelState (DataAnnotations), so FluentValidation rules were never executed. Add IValidationEnabled check in AbpValidationActionFilter to call IMethodInvocationValidator for conventional controllers, enabling FluentValidation support without duplicating validation for regular controllers. Resolve #23457pull/25105/head
9 changed files with 150 additions and 3 deletions
@ -0,0 +1,64 @@ |
|||
using System.Linq; |
|||
using System.Net; |
|||
using System.Net.Http; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Shouldly; |
|||
using Volo.Abp.Http; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Validation; |
|||
|
|||
public class FluentValidationTestAppService_Tests : AspNetCoreMvcTestBase |
|||
{ |
|||
[Fact] |
|||
public async Task Should_Validate_With_FluentValidation_On_ConventionalController() |
|||
{ |
|||
// Name is "A" which is less than 3 characters, should fail FluentValidation
|
|||
var response = await PostAsync("{\"name\": \"A\"}"); |
|||
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Validate_With_FluentValidation_On_ConventionalController_EmptyName() |
|||
{ |
|||
// Empty name should fail FluentValidation (NotEmpty rule)
|
|||
var response = await PostAsync("{\"name\": \"\"}"); |
|||
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Validate_With_FluentValidation_On_ConventionalController_MaxLength() |
|||
{ |
|||
// Name exceeds 10 characters, should fail FluentValidation (MaximumLength rule)
|
|||
var response = await PostAsync("{\"name\": \"12345678901\"}"); |
|||
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Return_Validation_Errors_With_Details() |
|||
{ |
|||
var response = await PostAsync("{\"name\": \"A\"}"); |
|||
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); |
|||
|
|||
var content = await response.Content.ReadAsStringAsync(); |
|||
content.ShouldContain("Name"); |
|||
content.ShouldContain("validationErrors"); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Pass_Validation_With_Valid_Input() |
|||
{ |
|||
var response = await PostAsync("{\"name\": \"Hello\"}"); |
|||
response.StatusCode.ShouldBe(HttpStatusCode.OK); |
|||
} |
|||
|
|||
private async Task<HttpResponseMessage> PostAsync(string jsonContent) |
|||
{ |
|||
var request = new HttpRequestMessage(HttpMethod.Post, "/api/app/fluent-validation-test") |
|||
{ |
|||
Content = new StringContent(jsonContent, Encoding.UTF8, "application/json") |
|||
}; |
|||
return await Client.SendAsync(request); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using FluentValidation; |
|||
using Volo.Abp.TestApp.Application; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Validation; |
|||
|
|||
public class FluentValidationTestInputValidator : AbstractValidator<FluentValidationTestInput> |
|||
{ |
|||
public FluentValidationTestInputValidator() |
|||
{ |
|||
RuleFor(x => x.Name).NotEmpty().MinimumLength(3).MaximumLength(10); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace Volo.Abp.TestApp.Application; |
|||
|
|||
public class FluentValidationTestAppService : ApplicationService |
|||
{ |
|||
public virtual Task<string> CreateAsync(FluentValidationTestInput input) |
|||
{ |
|||
return Task.FromResult(input.Name); |
|||
} |
|||
} |
|||
|
|||
public class FluentValidationTestInput |
|||
{ |
|||
public string Name { get; set; } |
|||
} |
|||
Loading…
Reference in new issue