Reputation:
I am using an MVC controller to create a dynamic JavaScript file (I am not happy with that part, but I'm trying to maintain compatibility with a previous version) in a Web Api project...
The client is consuming a URL like:
~/api/assessments/{id:int}.js?locale={locale?}
I created an MVC JavaScriptController
and added a method like this:
[Route("~/api/data/{id:int}.js")]
public async Task<PartialViewResult> GetData(int id, string locale)
{
try
{
Response.ContentType = "application/javascript";
ViewBag.Locale = locale ?? "en";
var model = await this._dataService.GetData(id.ToString());
return PartialView(model);
}
catch (Exception ex)
{
this._logger.Error("Task<PartialViewResult> GetData(int, string)", ex);
return PartialView("JavaScriptError", SelectException(ex));
}
}
When I try to invoke this call, however, I get a 404:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://.../api/data/29.js?locale=en'.
</Message>
<MessageDetail>
No type was found that matches the controller named 'data'.
</MessageDetail>
</Error>
I'm thinking that the WebApi "~/api" prefix is stepping on the MVC 5 route, although I suppose it could be something completely different. How can I render this MVC view at the specified URL?
Upvotes: 2
Views: 590
Reputation:
Well, it appears I was correct; the WebApi routing mechanism steps on the MVC attribute routing. Ultimately, I had to commment out the following line in my WebApiConfig.cs
file:
//config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new {id = RouteParameter.Optional});
After that, the MVC routing worked as expected.
Upvotes: 0
Reputation: 12817
You don't need to include the query string parameters or the relative path as part of your route:
[Route("api/data/{id:int}.js")]
protected async Task<PartialViewResult> GetData(int id, string locale)
{
try
{
Response.ContentType = "application/javascript";
ViewBag.Locale = locale ?? "en";
var model = await this._dataService.GetData(id.ToString());
return PartialView(model);
}
catch (Exception ex)
{
this._logger.Error("Task<PartialViewResult> GetData(int, string)", ex);
return PartialView("JavaScriptError", SelectException(ex));
}
}
Since only a specific part of your API is actually templated (the name of the "file") you only need to include that as part of the route.
However, you'll still run into issues where .NET will try to treat the request for a .js as being a request for a file.
For this to work, you'll likely have to enable the relaxed filesystem mapping:
<httpRuntime relaxedUrlToFileSystemMapping="true" />
However, you do need to be aware of security implications of enabling this. You'll be opening yourself up to potential attacks where remote users can access files on your filesystem if you don't set up NTFS permissions correctly.
Upvotes: 1
Reputation: 1082
Do you call MapHttpAttributeRoutes()
during your route registration?
See http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2#why
Upvotes: 0