asp.net core controller action route uses encoded slash to determine route (IIS only)
Asked Answered
O

1

11

I have an asp.net core 2.2 mvc action method and GET it from the client JavaScript code :

[Route("/search/{searchterm}")]
public IActionResult Search(string searchterm)
{
    // code
}

Now, when I navigate to search with the searchstring abc/def the uri in the browser is /search/abc%2Fdef because the / gets encoded

I get a 404 though, because the routing attribute decoded the slash and the says /search/abc/def does not match my route. What I want is to treat the %2F as a normal piece of content so the searchstring is abc/def inside of my action method.

Funny(?) thing is, this does not happen on my local machine where I run from VS2017 (which runs Kestrel I guess) but only on the test server where it runs on IIS.

Is this an IIS thing? or maybe the loadbalancer is doing something?

Ornithomancy answered 16/12, 2019 at 14:16 Comment(0)
S
25

You can use an asterisk to indicate that searchterm can contain slashes. This is called a catch-all parameter, and looks like this:

[Route("/search/{**searchterm}")]
public IActionResult Search(string searchterm)
{
    // code
}

From the documentation:

You can use an asterisk (*) or double asterisk (**) as a prefix to a route parameter to bind to the rest of the URI. These are called a catch-all parameters. For example, blog/{**slug} matches any URI that starts with /blog and has any value following it, which is assigned to the slug route value. Catch-all parameters can also match the empty string.

The catch-all parameter escapes the appropriate characters when the route is used to generate a URL, including path separator (/) characters. For example, the route foo/{*path} with route values { path = "my/path" } generates foo/my%2Fpath. Note the escaped forward slash. To round-trip path separator characters, use the ** route parameter prefix. The route foo/{**path} with { path = "my/path" } generates foo/my/path.

Sherborn answered 16/12, 2019 at 14:31 Comment(4)
Thanks, that worked! Any idea on why there is different behaviour on IIS vs local development server?Ornithomancy
@Sherborn Is there a way to do the equivalent of this? [Route("/search/{**searchterm}/{**additionalSearch}")]Catchpole
@BradenBrown it's not possible to have two catch-all parameters, because there's no way to know where one stops and the other starts (e.g. /search/one/two/three/four). You can use query parameters instead (e.g. /search?searchterm=one/two/three&additionalSearch=four).Malebranche
@Sherborn That's what I was thinking. That's true, for some reason I didn't think about using query params... Thanks! +1Catchpole

© 2022 - 2024 — McMap. All rights reserved.