Appetere
Appetere

Reputation: 6261

WebAPI route with period in final parameter fails

The Problem

Using WebAPI where the final parameter in a request includes a period / full-stop / '.'

My questionis how can I get the more complex route to work?


Background

All of the tests below were using new projects created from the Visual Studio WebAPI templates.

I understand that my request looks like it has a file-extension so have set:

<modules runAllManagedModulesForAllRequests="true">

So after the StaticFile handler has not found the item, it will pass it into the managed handlers.

If I request /api/values/mamal/dog.cat/(with a trailing slash) this works fine, but unfortunately we're stuck with an API contract and I can't do this.

.NET versions

When targeting .NET4.0, and using the Visual Studio WebAPI template, the more complex route works fine.

When targeting .NET4.5, with the default WebAPI template, the more complex route returns 404.

Some production code we have is targeting .NET4.5 in the .csproj file but has <compilation targetFramework="4.0"in web.config (and no <httpRuntime> element) and does seem to handle more complex routes, with a period in the final parameter.

The two scenarios

Using the default route:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

And a simple action on a ValuesController:

public string Get(string id)
{
    return string.Format("Param id: '{0}'", id);
}

Request /api/values/dog.catand routing takes you to the action.

Now change the route to add an additional category parameter:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{category}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

And modify the endpoint in the ValuesController:

public string Get(string category, string id)
{
    return string.Format("category: {0}, id: {1}", category, id);
}

Request /api/values/mamal/dog.cat and you get 404 not found.

Request /api/values/mamal/dog.cat/and the action is invoked.

Other stackoverflow questions

There are various similar questions on stackoverflow, which have answers that look like they address this, but are actually not relevant (in case you were thinking of marking this question as a duplicate!).

For example:

This handler only deals with requests ending with a period, eg /api/values/dog.cat., and doesn't address a period within the parameter:

<system.webServer>
  <handlers>
    <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> 

Also the following mapping is only about allowing reserved words, not a period in the URL:

<httpRuntime relaxedUrlToFileSystemMapping="true" />

Possible workarounds

Could downgrade to .NET4.0, which seems to work. But don't want to do this because of using async/await functionality.

I could presumably use something like the IIS URL Rewrite module to add a trailing-slash to requests that are missing it, but I'd rather get to a solution based on understanding why binding is 'failing'.

Upvotes: 4

Views: 3486

Answers (1)

Joey V.
Joey V.

Reputation: 1926

Solved this by modifying web.config handlers section and in the path attribute, change it from path="*." to path="*"

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

Upvotes: 6

Related Questions