0

I have a simple controller which allows a route path constrained by a regex pattern in a 'complex object'. When I try to read the single property from the object it is always null.

The ModelState is showing an errors collection saying:

The ActorId field is required

So it appears to be a model binding issue and not a validation issue.

I feel like I'm missing a pattern in the [HttpGet] block or something.

ActorIdParameter.cs

public sealed class ActorIdParameter
{
    [Required]
    [RegularExpression(@"^.*nm(\d{5}|\d{7})$")]
    public string ActorId { get; set; }
}

ActorsController.cs

[HttpGet("{actorIdParameter}")]
public async Task<IActionResult> GetActorByIdAsync([FromRoute]ActorIdParameter actorIdParameter)
{
    _ = actorIdParameter ?? throw new ArgumentNullException(nameof(actorIdParameter));
        
    // validation result
    if (!ModelState.IsValid) //<---this is always false
        return ValidationProcessor.GetAndLogInvalidActorIdParameter(method, logger);
}

Code is called using this example: http://localhost:4120/api/actors/nm0000206

There are several other posts which deal with the [FromQuery] and [FromBody] but I can't find anything that deals with the route path. It seems like the {actorIdParameter} needs something to say "get the ActorId property within that object" or something.

I feel like I need the complex object for the regex matching. Alternatively I could switch from the ActorIdParameter object to a string and possibly decorate it inline on the GetActorByIdAsync method but I'm curious if anyone has any suggestions?

Jason Shave
  • 2,462
  • 2
  • 29
  • 47

2 Answers2

1

Code below works for me using

https://localhost:5001/api/actors/nm0000206

and validation fails correctly for this one

https://localhost:5001/api/actors/42

You don't need any custom handling for this.

public class ActorIdParameter
{
    [Required]
    [RegularExpression(@"^.*nm(\d{5}|\d{7})$")]
    [FromRoute]
    public string ActorId { get; set; }
}

[Route("api/actors")]
public class ActorsController : ControllerBase
{
    [HttpGet("{actorId}")]
    public async Task<IActionResult> GetActorByIdAsync(ActorIdParameter model)
    {
        if (!ModelState.IsValid)
        {
            return new BadRequestResult();
        }

        return new OkResult();
    }
}
Roar S.
  • 8,103
  • 1
  • 15
  • 37
  • Perfect. I was trying to line up the parameter name with the 'template' name in the route. I noticed you also can't name the variable after one of the property names of the type. – Jason Shave Aug 22 '20 at 14:18
-1
  1. Try to do GET request to those three, change actors to your controller route :
  • http://url/actors/nm11111
  • http://url/actors?actorIdParameter=nm11111
  • http://url/actors/?actorIdParameter=nm11111

Is any worked ?

Check you model errors ( to understand why it is false ) :

var errors = ModelState
    .Where(x => x.Value.Errors.Count > 0)
    .Select(x => new { x.Key, x.Value.Errors })
    .ToArray();

ModelState.IsValid == false, why?

AnGG
  • 679
  • 3
  • 9