Dot character '.' in MVC Web API 2 for request such as api/people/STAFF.45287

C#asp.net Mvc-4asp.net Web-Apiasp.net Mvc-Routingasp.net Web-Api2

C# Problem Overview


The URL I'm trying to let work is one in the style of: http://somedomain.com/api/people/staff.33311 (just like sites as LAST.FM allow all sort of signs in their RESTFul & WebPage urls, for example "http://www.last.fm/artist/psy'aviah" is a valid url for LAST.FM).

What works are following scenarios:

I've set up following things:

  1. The controller "PeopleController"

    public IEnumerable<Person> GetAllPeople()
    {
        return _people;
    }
    
    public IHttpActionResult GetPerson(string id)
    {
        var person = _people.FirstOrDefault(p => p.Id.ToLower().Equals(id.ToLower()));
        if (person == null)
            return NotFound();
    
        return Ok(person);
    }    
    
  2. The WebApiConfig.cs

    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
    
        // Web API routes
        config.MapHttpAttributeRoutes();
    
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
    

I already tried following all the tips of this blogpost http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx but it still won't work.. I also think it's quite tedious and I wonder if there isn't another, better and more secure way.

We have our Id's internally like this, so we're going to have to find a solution to fit the dot in one way or another, preferably in the style of "." but I'm open to alternative suggestions for urls if need be...

C# Solutions


Solution 1 - C#

Suffix the URL with a slash e.g. http://somedomain.com/api/people/staff.33311/ instead of http://somedomain.com/api/people/staff.33311.

Solution 2 - C#

Following setting in your web.config file should fix your issue:

<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />

Solution 3 - C#

I've found that adding the following before the standard ExtensionlessUrlHandler solves the issue for me:

<add name="ExtensionlessUrlHandler-Integrated-4.0-ForApi"
     path="api/*"
     verb="*"
     type="System.Web.Handlers.TransferRequestHandler"
     preCondition="integratedMode,runtimeVersionv4.0" />

I don't think the name actually matters all that much except it probably helps if your IDE (Visual Studio in my case) is managing your site configuration.

H/T to https://stackoverflow.com/a/15802305/264628

Solution 4 - C#

I don't know what I am doing really, but after playing with the previous answer a bit I came up with another, perhaps more appropriate, solution:

<system.webServer>
<modules>
    <remove name="UrlRoutingModule-4.0" />
    <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
</modules>
</system.webServer>

Solution 5 - C#

I found that I needed to do more than just set the runAllManagedModulesForAllRequests attribute to true. I also had to ensure that the extensionless URL handler was configured to look at all paths. In addition, there is one more bonus configuration setting you can add which will help in some cases. Here is my working Web.config:

<system.web>
	<httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
<system.webServer>
	<modules runAllManagedModulesForAllRequests="true" />
	<handlers>
		<remove name="WebDAV" />
		<remove name="OPTIONSVerbHandler" />
		<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
		<add name="ExtensionlessUrlHandler-Integrated-4.0"  path="*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
	</handlers>
</system.webServer>

Note, specifically, that the ExtensionlessUrlHandler-Integrated-4.0 has its path attribute set to * as opposed to *. (for instance).

Solution 6 - C#

I'd use this in Web.config file:

<add name="ManagedSpecialNames" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

before standard "ExtensionlessUrlHandler".

For instance in my case I put it here:

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ManagedFiles" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

So you force URLs of such pattern to be managed by you, instead of standard management as files in application directory tree.

Solution 7 - C#

I got stuck in this situation but appending / at the end of URL wasn't look clean for me.

so just add below in web.config handlers tag and you will be good to go.

<add name="Nancy" path="api" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" allowPathInfo="true" />

Solution 8 - C#

I found that both way works for me: either setting runAllManagedModulesForAllRequests to true or add ExtentionlessUrlHandler as following. Finally i choose to add extensionUrLHandler since runAllManagedModulesForAllRequests do have performance impact to the site.

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" 
       type="System.Web.Handlers.TransferRequestHandler" 
       preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

Solution 9 - C#

I faced the very same issue and the circumstances I was in where I was not supposed to play with IIS and website config related settings. So I had to make it working by making changes at the code level only.

The simple point is that the most common case where you would end up having dot character in the URL is when you get some input from the user and pass it as a query string or url fragment to pass some argument to the parameters in the action method of your controller.

public class GetuserdetailsbyuseridController : ApiController
{
     string getuserdetailsbyuserid(string userId)
     {
        //some code to get user details
     }
}

Have a look at below URL where user enters his user id to get his personal details:

http://mywebsite:8080/getuserdetailsbyuserid/foo.bar

Since you have to simply fetch some data from the server we use http GET verb. While using GET calls any input parameters can be passed only in the URL fragments.

So to solve my problem I changed the http verb of my action to POST. Http POST verb has the facility of passing any user or non-user input in body also. So I created a JSON data and passed it into the body of the http POST request:

{
  "userid" : "foo.bar"
}

Change your method definition as below:

public class GetuserdetailsbyuseridController : ApiController
{
     [Post]
     string getuserdetailsbyuserid([FromBody] string userId)
     {
        //some code to get user details
     }
}

Note: More on when to use GET verb and when to use POST verb here.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYves SchelpeView Question on Stackoverflow
Solution 1 - C#Danny VarodView Answer on Stackoverflow
Solution 2 - C#KiranView Answer on Stackoverflow
Solution 3 - C#BrianSView Answer on Stackoverflow
Solution 4 - C#Greg Z.View Answer on Stackoverflow
Solution 5 - C#Josh M.View Answer on Stackoverflow
Solution 6 - C#bluishView Answer on Stackoverflow
Solution 7 - C#Khawaja AsimView Answer on Stackoverflow
Solution 8 - C#XuemeiView Answer on Stackoverflow
Solution 9 - C#RBTView Answer on Stackoverflow