__Scenario__:
Its popular with users to use Uri path extensions to get content in a particular format even though one could use Accept headers. My understanding is that this is for users from browsers who cannot modify headers of the request that a browser sends.
I have the following ValuesController which uses AttributeRouting.
```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[HttpGet("{id}")]
public string GetSingle(int id)
{
return "value";
}
[HttpPost("")]
public void Post([FromBody]string value)
{
}
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```
Now I would like to use UriPathExtensionMapping for the GetAll and GetSingle actions. I would like users to do "/api/values.xml" and "/api/values/10.xml" etc.
__Issue__:
I cannot do something like below for GetAll action, because we append the RoutePrefix with the action's RouteTemplate (ex: api/values/.{ext}). As you can notice this is not the desired behavior.
```
[HttpGet("")]
[HttpGet(".{ext}")]
public IEnumerable<string> GetAll()
```
__Workaround__:
__NOTE__: Here I would be placing the controller name on each of the individual action's route template, which ideally I would like to avoid.
```
[RoutePrefix("api")]
public class ValuesController : ApiController
{
[HttpGet("values")]
[HttpGet("values.{ext}")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[HttpGet("values/{id}")]
[HttpGet("values/{id}.{ext}")]
public string GetSingle(int id)
{
return "value";
}
[HttpPost("values")]
public void Post([FromBody]string value)
{
}
[HttpPut("values/{id}")]
public void Put(int id, [FromBody]string value)
{
}
[HttpDelete("values/{id}")]
public void Delete(int id)
{
}
}
```
__Impact__:
1. User experience would be bad as users could be having many controllers and if they like to support Uri path extension on all of them, then they have to do the above workaround.
2. Alternatively, I can think of having non-attribute routes in WebApiConfig.cs which could probably fix this, what do you think?
Example:
```
config.Routes.MapHttpRoute(
name: "DefaultApiWithExtension2",
routeTemplate: "api/{controller}/{id}.{ext}"
);
config.Routes.MapHttpRoute(
name: "DefaultApiWithExtension1",
routeTemplate: "api/{controller}.{ext}");
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
```
__Proposal__:
Could we introduce ability for individual actions' route attribute to ignore the RoutePrefix.
Example(__Notice__ the GetAll action's attribute):
```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("")]
[HttpGet("~/api/values.{ext}")] //NOTE
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[HttpGet("{id}")]
[HttpGet("{id}.{ext}")]
public string GetSingle(int id)
{
return "value";
}
[HttpPost("")]
public void Post([FromBody]string value)
{
}
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```
Comments: Does not seem like a very important scenario, and it has workarounds. If we hear about this more we will revisit.
Its popular with users to use Uri path extensions to get content in a particular format even though one could use Accept headers. My understanding is that this is for users from browsers who cannot modify headers of the request that a browser sends.
I have the following ValuesController which uses AttributeRouting.
```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[HttpGet("{id}")]
public string GetSingle(int id)
{
return "value";
}
[HttpPost("")]
public void Post([FromBody]string value)
{
}
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```
Now I would like to use UriPathExtensionMapping for the GetAll and GetSingle actions. I would like users to do "/api/values.xml" and "/api/values/10.xml" etc.
__Issue__:
I cannot do something like below for GetAll action, because we append the RoutePrefix with the action's RouteTemplate (ex: api/values/.{ext}). As you can notice this is not the desired behavior.
```
[HttpGet("")]
[HttpGet(".{ext}")]
public IEnumerable<string> GetAll()
```
__Workaround__:
__NOTE__: Here I would be placing the controller name on each of the individual action's route template, which ideally I would like to avoid.
```
[RoutePrefix("api")]
public class ValuesController : ApiController
{
[HttpGet("values")]
[HttpGet("values.{ext}")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[HttpGet("values/{id}")]
[HttpGet("values/{id}.{ext}")]
public string GetSingle(int id)
{
return "value";
}
[HttpPost("values")]
public void Post([FromBody]string value)
{
}
[HttpPut("values/{id}")]
public void Put(int id, [FromBody]string value)
{
}
[HttpDelete("values/{id}")]
public void Delete(int id)
{
}
}
```
__Impact__:
1. User experience would be bad as users could be having many controllers and if they like to support Uri path extension on all of them, then they have to do the above workaround.
2. Alternatively, I can think of having non-attribute routes in WebApiConfig.cs which could probably fix this, what do you think?
Example:
```
config.Routes.MapHttpRoute(
name: "DefaultApiWithExtension2",
routeTemplate: "api/{controller}/{id}.{ext}"
);
config.Routes.MapHttpRoute(
name: "DefaultApiWithExtension1",
routeTemplate: "api/{controller}.{ext}");
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
```
__Proposal__:
Could we introduce ability for individual actions' route attribute to ignore the RoutePrefix.
Example(__Notice__ the GetAll action's attribute):
```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("")]
[HttpGet("~/api/values.{ext}")] //NOTE
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[HttpGet("{id}")]
[HttpGet("{id}.{ext}")]
public string GetSingle(int id)
{
return "value";
}
[HttpPost("")]
public void Post([FromBody]string value)
{
}
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```
Comments: Does not seem like a very important scenario, and it has workarounds. If we hear about this more we will revisit.