3

I am creating ASP.NET CORE (2.1) project and trying to use FluentValidation library (https://fluentvalidation.net/). Unfortunately I am getting an error when I am sending request to my ApiController.

An unhandled exception occurred while processing the request.

InvalidOperationException: Unable to resolve service for type 'Core.Entities.Estimate' while attempting to activate 'Spinner.Features.Estimates.OnPost+CommandValidator'. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)

Here is the class where I have my model to validate and validator:

public class Command : IRequest<AcceptCostEstimateResponse>
{
    public EstimateDTO Estimate { get; set; }

    public ClientHeaderDTO ClientHeader { get; set; }
}

public class CommandValidator : AbstractValidator<Command>
{
    public CommandValidator(Estimate configuration)
    {
        RuleFor(x => x.Estimate).NotNull();

        RuleFor(x => x.Estimate.Name).NotEmpty();

        RuleFor(x => x.Estimate.Variant).NotEmpty();

        RuleFor(x => x.ClientHeader.ClientName).NotEmpty();

        RuleFor(x => x.ClientHeader.RequestId).NotEmpty();
    }
}

Here is my Startup.cs - place where I dependency injectio configuration exists:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());

    services.AddAutoMapper();

    services.AddMediatR();

    services.AddDbContextPool<SpinnerContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    ConfigureCore(services);

    ConfigureRepositories(services);
}

I also tried to configure CommandValidator differently, something like this, but still this didn't help:

services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddFluentValidation();

services.AddTransient<IValidator<Command>, CommandValidator>();
Tomas Voracek
  • 5,886
  • 1
  • 25
  • 41
tzm
  • 588
  • 1
  • 12
  • 27
  • What is `Estimate configuration` that is being passed into your `CommandValidator` constructor used for? The ASP.NET Core DI system doesn't know what this is and as such, it cannot resolve it. It appears you're not using it inside of the constructor, so you should be able to just remove it. – Kirk Larkin Aug 23 '18 at 13:22
  • @KirkLarkin thanks for feedback. I removed Estimate configuration parameter inside CommandValidator constructor and now getting different error. An unhandled exception occurred while processing the request. NullReferenceException: Object reference not set to an instance of an object. lambda_method(Closure , Command ) – tzm Aug 23 '18 at 13:26
  • @KirkLarkin when I tried to debug it, I go through all code inside the constructor and then visual studio returns error: ServiceProviderValidatorFactory.cs not found – tzm Aug 23 '18 at 13:32
  • That's a *very* broad problem to try and solve. Have a look at [this](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) question that has tonnes of information on how to diagnose this. – Kirk Larkin Aug 23 '18 at 13:36
  • Does it work if you change your validator to validate non complex types e.g. string, int. To validate complex types, you need to tell your validator how to do that: https://fluentvalidation.net/start#complex-properties – Emma Middlebrook Aug 23 '18 at 14:56
  • e.g. RuleFor(command => command.Estimate).SetValidator(new EstimateValidator()); – Emma Middlebrook Aug 23 '18 at 14:58

1 Answers1

0

I removed Estimate configuration parameter inside CommandValidator constructor and now getting different error. An unhandled exception occurred while processing the request. NullReferenceException: Object reference not set to an instance of an object.

For this error, It it caused when there is not value for Estimate or ClientHeader, they will be null, and FluentValidation will try to access their properties.

Try options below:

  • Change Command to set sub properties.

    public class Command : IRequest<AcceptCostEstimateResponse>
    {
        public Command()
       {
           Estimate = new EstimateDTO();
           ClientHeader = new ClientHeaderDTO();
        }
        public EstimateDTO Estimate { get; set; }
        public ClientHeaderDTO ClientHeader { get; set; }
    }
    
  • Change CommandValidator to valide subproperties only when it is not null.

        public CommandValidator()
    {
        //RuleFor(x => x.Estimate).NotNull();
    
        //RuleFor(x => x.Estimate.Name).NotEmpty();
    
        //RuleFor(x => x.Estimate.Variant).NotEmpty();
    
        //RuleFor(x => x.ClientHeader.ClientName).NotEmpty();
    
        //RuleFor(x => x.ClientHeader.RequestId).NotEmpty();
        RuleFor(x => x).NotNull();
    
        When(x => x != null, () =>
        {
            RuleFor(x => x.Estimate).NotNull();
    
            When(x => x.Estimate != null, () =>
            {
                RuleFor(x => x.Estimate.Name).NotEmpty();
    
                RuleFor(x => x.Estimate.Variant).NotEmpty();
            });
    
            RuleFor(x => x.ClientHeader).NotNull();
    
            When(x => x.ClientHeader != null, () =>
            {
                RuleFor(x => x.ClientHeader.ClientName).NotEmpty();
    
                RuleFor(x => x.ClientHeader.RequestId).NotEmpty();
            });
    
        });
    
    
    }
    
Edward
  • 28,296
  • 11
  • 76
  • 121