使用 MVC 托管时无法通过 AJAX 调用 WebAPI 控制器

Unable to call WebAPI Controller through AJAX, when hosted with MVC

我有一个包含几个简单页面的 MVC 应用程序,这些页面主要 运行 Web API 调用。为简单起见,我想将它们包含在同一个项目中。我可以正常启动并导航到我的页面,但是当我尝试通过 Ajax 调用我的 API 时,我不断收到 404 错误 - 它找不到 API 函数。

这是我的 javascript 文件:

$(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);
        }
    });
}

这是我的控制器:

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";
        }
    }
}

API 控制器位于我的项目中我的控制器文件夹内的它们自己的文件夹(称为 "API")中 - 这就是此示例控制器上命名空间包含 "API" 的原因。

当我在浏览器上使用 F12 捕获发送的请求时,我可以看到我的调用具有以下信息:

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

现在我的理解是,这应该找到名称为 UserController 的 API 并找到带有 [HttpGet] 标签且不带参数的函数,然后 return 字符串数组("value1", "value2").相反,它没有找到任何东西。

最后一点,这是我的路由配置(是的,它正在 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 }
            );
        }
    }

更新:

根据目前收到的反馈,我调整了 Global.asax 配置。它现在看起来像这样:

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

    }

现在,当我调用我的 API 函数时,我得到...待处理。它不是 return 成功消息。它只是挂起。我没有收到 "Success!" 警报。

虽然我不确定这是否与我在评论中猜测的问题相同,但这是一个可能的原因。所以任何遇到类似问题的人,这就是问题所在。

MVC 路由引擎尝试按照它们注册的相同顺序将传入请求与路由匹配。

  1. 因此,如果您先注册 MVC 路由 - {controller}/{action}/{id} id:optional
  2. 然后注册WebAPI路由-api/{controller}/{id} id:optional

Then incoming requests will be matched with the MVC route and IF it does NOT MATCH a route PATTERN, then only it will be matched against the WebAPI route.

现在,如果您有类似 api/User 的请求,它将匹配 MVC 路由模式,而不匹配 WebAPI 路由。结果,MvcHandler 将尝试创建一个 ApiController MVC 控制器 class 并在其上调用 User() 方法。结果,客户端将收到 404 - 未找到资源!

此外,如果您不使用属性路由,您可能需要 remove/comment 这一行

//config.MapHttpAttributeRoutes();

为了更安全的 http-verb-to-api-method 路由,您可以在 api 配置中添加以下内容。

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" }) });

前两条路由可以以 [1] 纯 REST 方式调用端点,并可以 [2] 使用方法名称调用它们(虽然不符合 REST 标准!)

尝试

/api/User/Get 

而不仅仅是 /api/user。如果您想体验一下,请查看 [RoutePrefix] and [Route] 以便您可以手动管理这些内容。