1

I have the following method:

public async Task<IActionResult> GetUsersAPICall([Bind(nameof(query))] [RegularExpression(@"^\w+(\.\w+)*@\w+(\.\w+)+|(\w+(\s\w+)*)|[a-z0-9]+$", ErrorMessage = "This does not look like a valid query")] string query)
{
    if (!ModelState.IsValid)
    {
       return BadRequest();
    }
}

This fails for email addresses like test-def.ghi@de.jkl.com (but not for email addresses like test@test.com).

I know for a fact that the regex is the correct pattern, because the following LINQPad script displays True as expected for the exact same email address:

void Main()
{
    var r = new Regex(@"^\w+(\.\w+)*@\w+(\.\w+)+|(\w+(\s\w+)*)|[a-z0-9]+$");
    
    r.IsMatch("test-def.ghi@de.jkl.com").Dump();
}

I tried dropping the [Bind(nameof(query))] entirely, but that didn't help.

If I change this to

public async Task<IActionResult> GetUsersAPICall([Bind(nameof(query))] string query)
{
    if (!Regex.IsMatch(query, @"^\w+(\.\w+)*@\w+(\.\w+)+|(\w+(\s\w+)*)|[a-z0-9]+$"))
    {
        return BadRequest();
    }

    // ...
}

I'm completely baffled as to why what I had originally wasn't working. Can someone see what I'm missing here?

The closest I've found so far on Stack Overflow is this Q&A, but there it turned out that the OP's regex was wrong (which isn't the case for me, since the Regex works just fine in two different contexts).

  • 2
    "*I know for a fact that the regex is the correct pattern*": I don't think [this](https://regex101.com/r/9ezYLz/1) is your expected result... – InSync Jul 28 '23 at 17:41
  • @InSync I'm confused, then - the same pattern appears to have worked in LINQPad. Am I missing something dumb? – EJoshuaS - Stand with Ukraine Jul 28 '23 at 17:43
  • 2
    I don't know ASP.NET/C#, so I'm not sure what you are trying to match. If it's email addresses you're after, see [this question](https://stackoverflow.com/q/5342375). The main problem is that the pipes (`|`) in your regex are dividing the expression, making `^` only applies to the first part and `$` the last. Perhaps you meant to enclose those parts in a group (`^(...|...|...)$`)? – InSync Jul 28 '23 at 17:51

1 Answers1

1

Problem is within your regex and difference in its handling by IsMatch and RegularExpression annotation.

IsMatch checks if input contains anything matching provided regex. Documentation:

Indicates whether the specified regular expression finds a match in the specified input string, using the specified matching options and time-out interval.

So it's trying to find any match in your input, finds it (specifically for second alteration: (\w+(\s\w+)*)) and returns true.

RegularExpression annotation on the other hand checks if your whole input matches provided regex. Documentation:

The regular expression searches for an exact match, not using ^ before and $ at the end of the pattern produces the same results as using it. For a search hit, prepend and append the pattern with .*.

So effectively, annotation applies pattern ^(?:^\w+(\.\w+)*@\w+(\.\w+)+|(\w+(\s\w+)*)|[a-z0-9]+$)$.

Probably you tried to achieve similar effect, but forgot parenthesis?

markalex
  • 8,623
  • 2
  • 7
  • 32