'ASP.Net Core Web API ModelState unvalidated when Dictionary used in FromQuery

I have a GET endpoint which accepts a few parameters and a Dictionary in the Query.

public IActionResult Get([FromQuery] RequiredFields required, [FromQuery] Dictionary<string, string> parameters)

RequiredFields is a typed class of known fields that are required. "paramaters" is a dictionary of optional parameters that are optionally required based on the values in RequiredFields. For example if RequiredFields.Type equals Foo then parameters must contain "x" and "y" keys.

The problem is that ModelState.IsValid is always false with no errors. When I inspect ModelState.Root, the children which are unvalidated are the keys in the Dictionary which are not present in the RequiredFields object.

Is this a bug or is there something I need to do to validate the key and value pairs in the Dictionary manually?

Some things I tried.

1) I tried adding a custom ValidationAttribute but that didn't get called for some reason.

2) I ended up using ModelState.ErrorCount > 0 rather than IsValid but that doesn't seem right either.



Solution 1:[1]

You could create an ModelBinder, like a ViewModel but for WebApi, and implement the IValidatableObject interface to your custom validations.

The code bellow was not tested.

public class ResourceModelBinder : IValidatableObject
{
    public RequiredFields RequiredFields { get; set; }

    public Dictionary<string, string> Parameters { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();
        if (RequiredFields.Type == "Foo")
        {
            if (string.IsNullOrEmpty(Parameters["x"]) || string.IsNullOrEmpty(Parameters("y")))
            {
                results.Add(new ValidationResult("Parameters x and y are required."));
            }
        }
        return results;
    }
}

I hope it helps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ricardo Fontana