3

In ASP.NET Core-6 Web API, I am implementing Fluent Validation.

I have this model:

model:

public class Employee
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string RegistrationNumber { get; set; }
}

Dto:

public class EmployeeCreateDto
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string RegistrationNumber { get; set; }
}

After that I did the validation here, using fluent validation:

public class EmployeeCreateDtoValidator : AbstractValidator<EmployeeCreateDto>
{
    private readonly ApplicationDbContext _dbContext;
    public EmployeeCreateDtoValidator(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public EmployeeCreateDtoValidator()
    {
        RuleFor(user => user.FirstName)
            .NotEmpty().WithMessage("First Name field is required. ERROR!")
            .NotNull().WithMessage("First Name cannot be null");

        RuleFor(user => user.LastName)
            .NotEmpty().WithMessageLast Name cannot be null");

        RuleFor(user => user.RegistrationNumber)
            .Must(BeUniqueRegistrationNumber).WithMessage("The specified Registration Number already exists.")
            .NotEmpty().WithMessage("Registration Number field is required. ERROR!")
            .NotNull().WithMessage("Registration Number cannot be null")
    }
    private bool BeUniqueRegistrationtNumber(string name)
    {
        if (_dbContext.Employees.SingleOrDefault(x => x.RegistrationNumber.ToLower() == name.ToLower()) == null) return true;
        return false;
    }
}

The mapping to the Dto is done here:

public class MapperProfile: Profile
{
    public MapperProfile()
    {
        CreateMap<EmployeeCreateDto, Employee>().ReverseMap();
        CreateMap<Employee, AllEmployeeListDto>().ReverseMap();
        CreateMap<BankUserCreateDto, BankUser>().ReverseMap();
    }
}

EmployeeService:

public async Task<Response<AllEmployeeListDto>> CreateEmployeeAsyncEmployeeCreateDto model)
{
    var existingEmployee = await _dbContext.Employees.FirstOrDefaultAsync(e => e.RegistrationNumber == model.RegistrationNumber);
    var response = new Response<AllEmployeeListDto>();
    using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        if (existingEmployee == null)
        {
            if (result.Succeeded)
            {
                var employee = _mapper.Map<Employee>(model);

                await _unitOfWork.Employees.InsertAsync(employee);
                await _unitOfWork.Save();
                response.StatusCode = (int)HttpStatusCode.Created;
                response.Successful = true;
                response.Data = _mapper.Map<AllEmployeeListDto>(employee);
                response.Message = "Employee Created Successfully!";
                transaction.Complete();
                return response;
            }
        }
        else
        {

            transaction.Dispose();
            response.StatusCode = (int)HttpStatusCode.BadRequest;
            response.Successful = false;
            response.Message = "Registration failed. Please try again";
            return response;
        }
        return response;
    };
}

AutoMapper Configuration:

public static class AutoMapperServiceExtension
{
    public static void ConfigureAutoMappers(this IServiceCollection services)
    {
        services.AddAutoMapper(typeof(MapperProfile));
    }
}

The dependency Injection is also done.

public static class DIServiceExtension
{
    public static void AddDependencyInjection(this IServiceCollection services)
    {
        // Add Service Injections Here -- Employee
        services.AddScoped<IEmployeeService, EmployeeService>();
        //services.AddScoped<IHttpClientService, HttpClientService>();
        // Add Repository Injections Here
        services.AddScoped<IUnitOfWork, UnitOfWork>();

        // Add Fluent Validator Injections Here
        // Employee Validator
        services.AddTransient<IValidator<EmployeeCreateDto>, EmployeeCreateDtoValidator>();
    }
}

Finally, I have the Program.cs

Program.cs:

var builder = WebApplication.CreateBuilder(args);
ConfigurationManager configuration = builder.Configuration;
var environment = builder.Environment;

builder.Services.AddHttpContextAccessor();
builder.Services.AddHttpClient();

builder.Services.AddControllers()
                .AddFluentValidation(options =>
                {
                    // Validate child properties and root collection elements
                    options.ImplicitlyValidateChildProperties = true;
                    options.ImplicitlyValidateRootCollectionElements = true;
                    options.RegisterValidatorsFromAssembly(Assembly.GetExecutingAssembly());
                    options.AutomaticValidationEnabled = true;
                });

// Configure AutoMapper
builder.Services.ConfigureAutoMappers();
builder.Services.AddDependencyInjection();

var app = builder.Build();

app.MapControllers();
string? port = Environment.GetEnvironmentVariable("PORT");
if (!string.IsNullOrWhiteSpace(port))
{
    app.Urls.Add("http://*:" + port);
}
app.Run();

I think I have problems with Fluent Validation Configuration. I am using ASP.NET Core-6. If I enter the correct data, it successfully inserts everything into the database.

However, If I deliberately enter incorrect data, I I expect it to indicate with the help of Fluent Validation. But this is not happening. The data will only not get inserted.

How do I resolve this?

Thanks

2
  • This is apparently my first time when I see using FluentValidation on the entity/dto level... Commented Jul 1, 2022 at 20:20
  • Have a look at this , try to use ModelState.IsValid . Commented Jul 25, 2022 at 8:55

2 Answers 2

0

You have to put validation logic inside the same constructor.

try this.

public EmployeeCreateDtoValidator(ApplicationDbContext dbContext)
{
    _dbContext = dbContext;

    RuleFor(user => user.FirstName)
        .NotEmpty().WithMessage("First Name field is required. ERROR!")
        .NotNull().WithMessage("First Name cannot be null");

    RuleFor(user => user.LastName)
        .NotEmpty().WithMessageLast Name cannot be null");

    RuleFor(user => user.RegistrationNumber)
        .Must(BeUniqueRegistrationNumber).WithMessage("The specified Registration Number already exists.")
        .NotEmpty().WithMessage("Registration Number field is required. ERROR!")
        .NotNull().WithMessage("Registration Number cannot be null")
}
Sign up to request clarification or add additional context in comments.

1 Comment

Still not working. I suspect it may have to do with Program.cs What else do I do?
0

Remove this

Builder.Services.AddControllers()
                .AddFluentValidation(options =>
                {
                    // Validate child properties and root collection elements
                    options.ImplicitlyValidateChildProperties = true;
                    options.ImplicitlyValidateRootCollectionElements = true;
                    options.RegisterValidatorsFromAssembly(Assembly.GetExecutingAssembly());
                    options.AutomaticValidationEnabled = true;
                });

And try this in your program file add

builder.Services.AddValidatorsFromAssemblyContaining<YourValidtor>();

Then in your constructor inject IValidator validator. Then in your action

 ValidationResult result = await _validator.ValidateAsync(city);
            if (!result.IsValid)
            {
                result.AddToModelState(this.ModelState);
                
                return BadRequest(result);
            }

Hope this will help

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.