Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can FluentValidation recognize which methods (PUT or POST) were called?

In ASP.NET Core 3.0 Web API, I'm using the same DTO for Post and Put methods. While creating new Item I want to guard against already existing name. Like this:

    public ItemValidator(IItemRepository itemRepository)
    {
        RuleFor(input => input.Name).NotEmpty();
        RuleFor(input => input.Name).Must(name => !itemRepository.ItemExists(name))
            .WithMessage(input => $"Item '{input.Name}' already exists");
    }

It all works great for update and insert. You can't update a name to name that already exists. But! When you try to change "ItemA" to "ItemA" (new name is the same as the old one) you get that error and it can be a little bit misleading (although technically correct).

In the dto itself, I don't have unique id of the item. Because I pass id in the path.

If I have an access to the Controller's method that has been called and its parameters (including id) I would be able to tell if someone is trying to change item's name to the same name.

like image 626
Adam Wojnar Avatar asked Dec 07 '25 05:12

Adam Wojnar


1 Answers

FluentValidation can recognize which HTTP method is called. For that, you will need to add HttpContextAccessor in the ConfigureServices method in StartUp file.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        services.AddHttpContextAccessor();
        services.AddMvc(setup => { }).AddFluentValidation();
        services.AddTransient<IValidator<MyModel>, MyModelValidator>();
    }

Now you can use IHttpContextAccessor in your validator class. Here is my validator class

public class MyModelValidator : AbstractValidator<MyModel>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    public MyModelValidator(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;

        RuleFor(myModel => myModel.Id)
            .NotEmpty();

        RuleFor(myModel => myModel.Value)
            .Must(value => MyRule(value, _httpContextAccessor.HttpContext.Request.Method));
    }

    private bool MyRule(string value, string method)
    {
        if (method.ToUpper() == "POST")
        {
            return true;
        }
        else if (method.ToUpper() == "PUT")
        {
            // validatation logic for value
            return !string.IsNullOrWhiteSpace(value);
        }
        return false;
    }
}

You can get Request Path from _httpContextAccessor as following

var path = _httpContextAccessor.HttpContext.Request.Path.Value;

EDIT:

Please consider marking this answer accepted if this solves your problem.

like image 171
Kush Avatar answered Dec 08 '25 17:12

Kush



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!