Unable to invoke WebAPI controller through AJAX when hosted with MVC

I have an MVC application with a few simple pages that will basically run when the Web API is called. For simplicity, I want to include them in the same project. I can start and go to my page just fine, but when I try to call my API through Ajax, I get a 404 error all the time - it cannot find the API function.

Here is my javascript file:

$(document).ready(function () { //set the login button to call our test API function document.getElementById("login_submit").addEventListener("click", GetUser); }); function GetUser() { var response = $.ajax({ url: '/api/User', method: 'GET', contentType: 'application/json; charset=utf-8', success: function (data) { alert("Success!"); }, error: function (request, status, error) { alert(error); } }); } 

And here is my controller:

 namespace MyProject.Controllers.API { public class UserController : ApiController { // GET api/<controller> [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/<controller>/5 [HttpGet] public string Get(int id) { return "value"; } } } 

The API controllers are located in their own folder (called the "API") inside my Controllers folder in my project - why the namespace contains an "API" on this sample controller.

When I use F12 in the browser to capture the request being sent, I see that my call has the following information:

 Request URL: http://localhost:50035/api/User Request Method: GET Status Code: 404 / Not Found 

Now I understand that this should find an API called UserController and find a function with the [HttpGet] tag without arguments, and then return an array of strings ("value1", "value2"). Instead, he finds nothing.

As a final note, here is my routing configuration (and yes, it initializes to Global.asax):

 public static class WebApiConfig { 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 } ); } } 

UPDATE:

Based on the feedback I have received so far, I have moved my Global.asax configuration. It now looks like this:

  protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); GlobalConfiguration.Configure(WebApiConfig.Register); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } 

Now, when I call my API function, I get ... Pending. It does not return a success message. He is just hanging. I do not get "Success!". a warning.

+5
source share
2 answers

Although I'm not sure that the same problem that I guessed in my comment, but this is a probable cause. Therefore, anyone who encounters a similar problem is a problem.

The MVC routing mechanism attempts to match incoming requests with routes in the same order in which they were registered.

  • So, if you first register the MVC route - {controller} / {action} / {id} id: optional
  • And then register the WebAPI route - api / {controller} / {id} ID: optional

Then, incoming requests will be mapped to MVC traffic and IF IT DOES NOT MARK the PATTERN route, then only it will be mapped to the WebAPI route.

Now, if you have a request of type api/User , it will be MATCH with the MVC route pattern and will NOT be mapped to the WebAPI route. As a result, MvcHandler will try to create the ApiController MVC controller class and call the User() method. As a result, the client will receive 404 - the resource was not found!

In addition, if you do not use attribute routing, you can delete / comment on this line

 //config.MapHttpAttributeRoutes(); 

And for more secure http-verb-to-api-method routing, you can add the following to the api configuration.

 routes.MapHttpRoute("RestApiRoute", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" }); //this replaces your current api route routes.MapHttpRoute("ApiWithActionRoute", "Api/{controller}/{action}/{id}", new { id = RouteParameter.Optional }); routes.MapHttpRoute("DefaultApiGetRoute", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(new string[] { "GET" }) }); routes.MapHttpRoute("DefaultApiPostRoute", "Api/{controller}", new { action = "Post" }, new { httpMethod = new HttpMethodConstraint(new string[] { "POST" }) }); routes.MapHttpRoute("DefaultApiPutRoute", "Api/{controller}", new { action = "Put" }, new { httpMethod = new HttpMethodConstraint(new string[] { "PUT" }) }); routes.MapHttpRoute("DefaultApiDeleteRoute", "Api/{controller}", new { action = "Delete" }, new { httpMethod = new HttpMethodConstraint(new string[] { "DELETE" }) }); 

The first two routes allow you to call the endpoints in [1] the pure REST method and [2] call them with the method name (not consistent with REST standards, though!)

+2
source

Try

 /api/User/Get 

instead of just / api / user. If you want to get an idea of ​​this, check out [RoutePrefix] and [Route] so you can manage this stuff manually.

+1
source

All Articles