I\'m working on moving an API project from raw http handlers where I\'m using periods in the paths:
http://server/collection/id.format
I wo
IIS intercepts requests with a period as file downloads. In your web.config, you can configure IIS to ignore specific URL paths because the webapi will handle the requests instead. If you want IIS to handle file downloads as well as process webapi calls, you can add a ManagedDllExtension configuration to system.webServer.handlers in web.config.
<add name="ManagedDllExtension" path="collection/*.*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
I am unable to reproduce the problem. This should work. Here's my setup:
Microsoft.AspNet.WebApi.SelfHost
NuGetDefine a Product
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
A corresponding API Controller:
public class ProductsController : ApiController
{
public Product Get(int id)
{
return new Product
{
Id = id,
Name = "prd " + id
};
}
}
And a host:
class Program
{
static void Main(string[] args)
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute(
name: "DefaultApiRoute",
routeTemplate: "{controller}/{id}.{format}",
defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
constraints: null
);
using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
Now when you run this console application you could navigate to http://localhost:8080/products/123.xml
. But of course you could navigate to http://localhost:8080/products/123.json
and you will still get XML. So the question is: How to enable content negotiation using a route parameter?
You could do the following:
class Program
{
static void Main(string[] args)
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Formatters.XmlFormatter.AddUriPathExtensionMapping("xml", "text/html");
config.Formatters.JsonFormatter.AddUriPathExtensionMapping("json", "application/json");
config.Routes.MapHttpRoute(
name: "DefaultApiRoute",
routeTemplate: "{controller}/{id}.{ext}",
defaults: new { id = RouteParameter.Optional, formatter = RouteParameter.Optional },
constraints: null
);
using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
and now you can use the following urls:
http://localhost:8080/products/123.xml
http://localhost:8080/products/123.json
Now you might be wondering what's the relation between the {ext}
route parameter that we used in our route definition and the AddUriPathExtensionMapping
method because nowhere we did not specify it. Well, guess what: it's hardcoded in the UriPathExtensionMapping
class to ext
and you cannot modify it because it is readonly:
public class UriPathExtensionMapping
{
public static readonly string UriPathExtensionKey;
static UriPathExtensionMapping()
{
UriPathExtensionKey = "ext";
}
...
}
All this to answer your question:
Can periods be used in Asp.Net Web Api Routes?
Yes.
Be careful to set runAllManagedModulesForAllRequests option in modules attribute in your web.config
<modules runAllManagedModulesForAllRequests="true">..</modules>
Otherwise it will not work in IIS (probably it would be handled by non-managed handlers).
I was able to achieve this by doing the following:
replace "*."
with "*"
in system.webServer.handlers in web.config, i.e. remove the period.
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
I'm accepting Darin's answer (yes, periods can be used in route urls) because it was specifically correct to my example, yet unhelpful to me. This is my fault for not specifically indicating that "id" is a string, not an integer.
To use a period following a string parameter the routing engine needs hints in the form of a constraint:
var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
name: "DefaultApiRoute",
routeTemplate: "{controller}/{id}.{format}",
defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
constraints: new { id = "[^\\.]+" } // anything but a period
);
Adding the constraint to the preceding token allows inbound URLs to be correctly decomposed and processed. Without the hint, the "id" token can be interpreted to match the remaining extent of the URL. This is just a specific case of needing constraints to delineate boundaries between string parameters in general.
Yes, periods can be used in URL routes in the Asp.Net Web API, but if they are to follow a string parameter be sure to apply the correct constraint to the route.