7

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?

Michel
  • 23,085
  • 46
  • 152
  • 242

1 Answers1

20

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.

Community
  • 1
  • 1
Métoule
  • 13,062
  • 2
  • 56
  • 84
  • Thanks, that worked! Any idea on why there is different behaviour on IIS vs local development server? – Michel Dec 18 '19 at 09:39
  • @Métoule Is there a way to do the equivalent of this? [Route("/search/{**searchterm}/{**additionalSearch}")] – Braden Brown Jun 09 '20 at 15:03
  • 1
    @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`). – Métoule Jun 09 '20 at 15:33
  • 1
    @Métoule That's what I was thinking. That's true, for some reason I didn't think about using query params... Thanks! +1 – Braden Brown Jun 09 '20 at 15:36