3

I have a web API project, with the following endpoint:

GET api/search/{searchValue}

Controller code:

[RoutePrefix("api/Search")]
public class SearchController : ApiController
{
    [HttpGet]
    [Route("{searchValue}", Name = "GenericSearch")]
    [ResponseType(typeof(SearchResponse))]
    public async Task<IHttpActionResult> Search(string searchValue) {
        ...
    }
}

This works fine for most search strings. But if the search string ends in a period (.) character, the request breaks with a 404; it seems to be interpreting the period as part of the path rather than as part of the query. This is so, even if the request string is Url encoded, e.g.

api/search/foo%2E

If the period is not the last character of the string, it works:

api/search/foo%2Ebar

will correctly search for "foo.bar".

How can I fix this so that users are allowed to search for strings that end with a period character?

UPDATE: After having this question closed as a duplicate of this question, allow me to clarify why this question is different:

  1. The linked question is trying to use a literal period character in the query string. I'm not even doing that; I'm encoding the . as %2E, and it's still not working.
  2. The query works with the period character in the middle. It's only when it's at the end of the query string that it fails.
  3. I already have <modules runAllManagedModulesForAllRequests="true" /> (as suggested by the accepted answer in my web.config.
  4. I tried suffixing the query with a slash character (i.e. api\search\foo%2E\) as suggested in the highest-voted answer; this made no difference.
  5. I tried all the answers suggested there, and none of them made a difference.
Nkosi
  • 235,767
  • 35
  • 427
  • 472
Shaul Behr
  • 36,951
  • 69
  • 249
  • 387
  • 2
    I always wonder why I need to do the Googling... ;) – Patrick Hofman May 22 '17 at 09:09
  • @PatrickHofman, too quick on the trigger. This is not the same question. – Shaul Behr May 22 '17 at 09:14
  • 1
    Then you should edit the question and explain that. You know the box tells you to do so. And it is as far as I can see. This is a classic problem. – Patrick Hofman May 22 '17 at 09:14
  • 1
    Can you show your code / routes? – Patrick Hofman May 22 '17 at 09:31
  • @PatrickHofman added controller code. – Shaul Behr May 22 '17 at 09:36
  • @PatrickHofman, care to reopen the question, please, now that we've established it's not a duplicate? – Shaul Behr May 22 '17 at 11:10
  • @ShaulBehr: Can you comment on the second linked duplicate? I can't imagine this come out the first time here on the site, but I also don't know much about asp.net, so please excuse my ignorance. – hakre May 22 '17 at 16:48
  • @hakre the second linked question is the same as the first, and different from mine. – Shaul Behr May 22 '17 at 17:45
  • Related: https://support.microsoft.com/en-us/help/2520479/web-services-may-fail-on-microsoft-internet-information-services-iis-7.5-and-windows-7-service-pack-1-with-.net-framework-4.0-due-to-extensionless-url-handlers have you tried setting ExtensionlessUrlHandler to Path="*" ? – Ondrej Svejdar May 24 '17 at 14:27
  • @OndrejSvejdar Not sure where you see a connection between this link and my problem? FYI, API is hosted on Azure Web Apps. – Shaul Behr May 24 '17 at 14:44
  • What is the actual path that system is trying to look for? Considering it is throwing an error, it is unable to find the path. Maybe a look at the path that is generated will help. You can probably just add a simple alert to get the path. – jitendragarg May 24 '17 at 16:05
  • @jitendragarg the path is shown in the question. Unless I'm misunderstand what you're asking? – Shaul Behr May 24 '17 at 16:14
  • I mean the path that is generated when the request is sent. When you get a 404, IIS can log the error message. In that, you should see the path it is trying to access. See if it is same as what you expect, and if not, what is missing. – jitendragarg May 24 '17 at 16:18
  • @jitendragarg any idea how to do that in Azure? It's a Web App. – Shaul Behr May 24 '17 at 16:20
  • Not really used to Azure, but found an article. Try this link. https://learn.microsoft.com/en-us/azure/app-service-web/web-sites-enable-diagnostic-log Enable logging and then recreate this error. – jitendragarg May 24 '17 at 16:22
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/145106/discussion-between-shaul-behr-and-jitendragarg). – Shaul Behr May 25 '17 at 08:58

1 Answers1

4

UPDATE:

I failed to mention that the following was also added to my web config file to allow the period to not cause IIS to break.

<system.web>
    <httpRuntime targetFramework="4.5" sendCacheControlHeader="true" relaxedUrlToFileSystemMapping="true" />
    <!-- ...other code removed for brevity -->
</system.web>

Primarily relaxedUrlToFileSystemMapping="true"that indicates whether the URL in an HTTP request is required to be a valid Windows file path.

HttpRuntimeSection.RelaxedUrlToFileSystemMapping Property

The RelaxedUrlToFileSystemMapping property determines how the URL in an incoming HTTP request will be validated. If this property is false, the URL is validated by using the same rules that determine whether a Windows file system path is valid.


ORIGINAL

Using the catch all parameter in the route template {*searchValue} I was able to get the controller action to match the request with route prefix api/search and return as expected. Even for values ending with a period (.), whether URL encoded or not.

[RoutePrefix("api/search")]
public class SearchController : ApiController {
    [HttpGet]
    [Route("{*searchValue}", Name = "GenericSearch")] // Matches GET api/Seach/{anything here}
    [ResponseType(typeof(SearchResponse))]
    public async Task<IHttpActionResult> Search(string searchValue) {
        //...
    }
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Nice try, but it didn't work... :-( Were you able to repro the problem before adding the * to the Route? – Shaul Behr May 25 '17 at 08:56
  • 1
    @ShaulBehr check updated answer. forgot about a setting in the web config. – Nkosi May 25 '17 at 10:39
  • @ShaulBehr, yeah I had completely forgotten about that setting in the original answer. Tested it again and it would also work without the catch-all (`*`). – Nkosi May 25 '17 at 10:51