为什么我的REST方法没有被这个jQuery调用?

我有一个类似的问题关于jQuery按钮点击处理程序代码在这里根本没有被解雇。

在这种情况下,它被触发(当jQuery被添加到静态页面(Index.cshtml)),但我的REST方法仍未被访问。 控制台消息解释原因是:

The resource cannot be found. Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly. Requested URL: /LandingPage/GetQuadrantData Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.6.1055.0 

这是jQuery,当单击按钮时确实会被触发,但是没有进行REST调用:

  $(function () { var btnGetData = document.getElementById('btnGetData'); btnGetData.addEventListener("click", function () { alert("It works"); var unitval = 'ABUELOS'; var begdateval = '2016-08-07'; var enddateval = '2016-08-13'; $.ajax({ type: 'GET', url: '@Url.Action("GetQuadrantData", "LandingPage")', data: { unit: unitval, begdate: begdateval, enddate: enddateval }, contentType: 'application/json', cache: false, success: function (returneddata) { }, error: function () { alert('hey, boo-boo!'); } }); }); });  

REST方法在LandingPageController.cs中设置如下:

 [Route("{unit}/{begdate}/{enddate}")] public HttpResponseMessage GetQuadrantData(string unit, string begdate, string enddate) { _unit = unit; _beginDate = begdate; _endDate = enddate; . . . 

我在“_unit = unit”上有一个断点 线,但没有到达; 为什么不? 我在这里想念的是什么?

正在讨论的REST控制器类开始如下:

 [RoutePrefix("api")] public class LandingPageController : ApiController 

注意:如果我在jQuery中使用它(附加“Controller”):

 url: '@Url.Action("GetQuadrantData", "LandingPageController")' 

… IDE(Visual Studio)编辑器中的“GetQuadrantData”和“LandingPageController”均为红色 – 字母为红色。

OTOH,如果我使用它(没有附加“控制器”):

 url: '@Url.Action("GetQuadrantData", "LandingPage")' 

(过去曾为我工作,将“控制器”保留在控制器名称之外),“GetQuadrantData”和“LandingPage”都以红色显示,但字体仍然是正常颜色。

UPDATE

在下面的评论中使用Nico的链接,我将jQuery“url”行更改为:

 url: '@Url.Action("GetQuadrantData", "LandingPage", new { httproute = "" })', 

…但它仍然没有导致达到Controller方法。

更新2

通过(Chrome)浏览器中的javascript,我看到“url”行已经从设计时的动态更改:

 url: '@Url.Action("GetQuadrantData", "LandingPage", new { httproute = "" })', 

…至:

 url: '/api/LandingPage?action=GetQuadrantData', 

我认为应该解决的问题更像是:

 url: '/api/ABUELOS/2016-08-14/2016-08-20', 

我对吗? 为什么不这样解决?

如果我在浏览器中手动输入该URL,以便URL栏显示“ http://localhost:52194/api/ABUELOS/2016-08-21/2016-08-27 ”它可以工作 – 到达方法并且它“做到了。”

更新3

我也尝试过这个:

 $(function () { $("#btnGetData").click(function () { document.body.style.cursor = 'wait'; $.ajax({ type: "GET", url: '@Url.Action("GetQuadrantData", "LandingPage")', success: function (retval) { $("body").append($(retval)); document.body.style.cursor = 'pointer'; }, error: function () { alert('error in btnGetData'); } }); // end AJAX }); // end click }); // end ready function 

…但只看到“btnGetData中的错误”

更新4

我最近的失败是这样的:

 $("#btnGetData").click(function () { document.body.style.cursor = 'wait'; var unitval = $('#unitName').val(); var begdateval = $('#datepickerFrom').val(); var enddateval = $('#datepickerTo').val(); $.ajax({ type: 'GET', url: '@Url.Action("GetQuadrantData", "LandingPage")', data: { unit: unitval, begdate: begdateval, enddate: enddateval }, cache: false, success: function (returneddata) { alert($(returneddata)); }, error: function () { alert('error in ajax'); } }); }); 

再次,我只看到“ajax中的错误”

更新5

注意 :最大的赏金(200分,我认为是)将奖励给能够解决这个难题的人。 如果不止一个人这样做,那么赏金就会归于最能解决问题的人(这对我来说意味着最简单易行的方式)。

为了完全公开和绝望,这里是WEB API应用程序运行时显示的第一页的全部内容(带有省略/无意义的部分省略省略号)(来自\ Views \ Home \ Index.cshtml:

      eServices Reporting - Customer Dashboard         body { padding-top: 20px; padding-bottom: 20px; background-color: white; } . . .   $(function () { $("#btnGetData").click(function () { document.body.style.cursor = 'wait'; var unitval = "ABUELOS"; //$('#unitName').val(); var begdateval = $('#datepickerFrom').val(); var enddateval = $('#datepickerTo').val(); $.ajax({ type: 'GET', url: '@Url.Action("GetQuadrantData", "LandingPage")', data: { unit: unitval, begdate: begdateval, enddate: enddateval }, cache: false, success: function (returneddata) { alert($(returneddata)); }, error: function () { alert('error in ajax'); } }); }); }); // end ready function    
PRO*ACT usa logo


Top 10 Items Purchased

Item Code Description Qty
101200 ASPARAGUS, STANDARD 11/1# 32
140200 MUSHROOMS, MEDIUM 10# 20
140000 MUSHROOMS, BUTTON 10# 14
127100 LETTUCE, ROMAINE 24 CT 14
300123 BEANS, GREEN TRIM 2/5# (BAGS) 13
173100 POTATOES, 50 CT IDAHO 12
234225 BERRIES, STRAWBERRY 1# CLAM 11
188500 TOMATOES, GRAPE 12/1 PT 10
122500 LETTUCE, ICEBERG LINER 24 CT 10
121050 LETTUCE, GREEN LEAF 24 CT 10

Pricing Exceptions - Weekly Recap


PRO*ACT Member Total Occurrences of Summary Items Total Summary Exceptions Total Percentage of Summary Exceptions
Stern 205 2 99.02%
Hardies Dallas 1,597 0 100.00%
Hardies South 612 1 99.84%
Go Fresh 482 0 100.00%
Segovias 1,360 2 99.85%
Potato Spec 1,605 0 100.00%
TOTAL 5,861 5 99.79%

Forecasted Spend - $9,814.81

Item Code Last Week's Usage This Week's Price Forecasted Spend
261650 49 3.14 153.86
231083 52 1.25 65.00
398980 46 4.95 227.70
351135 40 0.75 30.00
398036 42 3.00 126.00
208110 42 2.50 105.00
102800 1835 2.25 4,128.75
367050 1910 1.95 3,724.50
173100 66 19.00 1,254.00
TOTAL 4082 -- $9,814.81

Delivery Performance

PRO*ACT Distributor Restaurant Location Avg Order Amount Avg Package Count Total Sales
Sunrise FL A1A ALEWORKS - #4405 - ST. AUGUSTINE $475.78 28.50 $1,903.10
Sunrise FL RAGTIME TAVERN - #4404 - ATLANTIC BEACH $221.46 17.50 $885.82
Sunrise FL SEVEN BRIDGES - #4403 - JACKSONVILLE $367.49 22.67 $1,102.47
T&T BIG RIVER - #4201 - CHATTANOOGA $396.06 22.83 $2,376.34
T&T BIG RIVER - #4205 - HAMILTON PL $424.74 26.00 $1,698.95
TOTAL 3,770.42 23.50 $1,592.60

更新6

我知道Arturo的答案不仅仅是这个,但到目前为止只是添加了这个:

 config.Routes.MapHttpRoute( name: "QuadrantData", routeTemplate: "api/{unit}/{begdate}/{enddate}" ); 

…帮助了,因为我的方法中的断点正在达到。 不幸的是,它在“位置0”的JSON中发出“SyntaxError:Unexpected token <

关于如何生成路由以及如何尝试访问路径,您遇到了一些问题。

您的Web API操作正在使用属性路由,因此默认情况下没有像基于约定的路由中那样匹配的路由名称。

更新route属性以包含要在路由表中查找的名称。

 [RoutePrefix("api")] public class LandingPageController : ApiController { [HttpGet] [Route("{unit}/{begdate}/{enddate}", Name="QuadrantData")] public HttpResponseMessage GetQuadrantData(string unit, string begdate, string enddate) { _unit = unit; _beginDate = begdate; _endDate = enddate; //...other code } //...other code } 

接下来,即使您有名称,您还需要包含模板参数,以便从MVC获得匹配,并让它在您在操作上定义的模板中生成URL。

要生成到Web API的链接,它将如下所示

 @Url.RouteUrl(routeName : "QuadrantData", routeValues : new { httpRoute = true , unit = "ABUELOS", begdate = "2016-08-07", enddate = "2016-08-13" }) 

要么

 @Url.HttpRouteUrl(routeName : "QuadrantData", routeValues : new { unit = "ABUELOS", begdate = "2016-08-07", enddate = "2016-08-13" }) 

这会将httpRoute添加到路由值。

参考: 使用属性路由为Web Api构建URL视图

现在,如果您的方法不合适,我建议采用以下替代方法。

KISS原则。 将Web API(REST)端点更改为POST并更改其模板。

 [RoutePrefix("api")] public class LandingPageController : ApiController { //eg POST api/QuadrantData [HttpPost] [Route("QuadrantData", Name="GenerateQuadrantData")] public HttpResponseMessage QuadrantData(string unit, string begdate, string enddate) { _unit = unit; _beginDate = begdate; _endDate = enddate; //...other code } //...other code } 

并在JSON POST请求的正文中发送数据

 $(function () { $("#btnGetData").click(function () { document.body.style.cursor = 'wait'; var unitval = "ABUELOS"; //$('#unitName').val(); var begdateval = $('#datepickerFrom').val(); var enddateval = $('#datepickerTo').val(); var jsonBody = JSON.stringify({ unit: unitval, begdate: begdateval, enddate: enddateval }); $.ajax({ type: 'POST', url: '@Url.HttpRouteUrl("GenerateQuadrantData", null)', contentType: 'application/json', dataType: 'json', data: jsonBody, cache: false, success: function (returneddata) { alert($(returneddata)); }, error: function () { alert('error in ajax'); } }); }); }); // end ready function 

个人不是在javascript代码中使用@ Url.Action的忠实粉丝; 这是我如何进行ajax调用:

  • 在布局页面中创建隐藏字段以存储根URL –
  • 有一个常量json文件来保持我的客户端常量(constants.js) – 将隐藏的字段值赋给serviceRoot变量:

     (function () { window.constants = { serviceRoot: $("#hdnRoot").val() + "api/", objectState: { added: "Added", modified: "Modified", unchanged: "Unchanged", deleted: "Deleted" }, ..other values... }; })(); 
  • 将您的ajax调用修改为:

     var root = window.constants.serviceRoot; $.ajax({ type: 'GET', url: root + 'LandingPage/GetQuadrantData/'+unitval+'/'+begdateval+'/'+enddateval, // data: { unit: unitval, begdate: begdateval, enddate: enddateval }, contentType: 'application/json', cache: false, success: function (returneddata) { }, error: function () { alert('hey, boo-boo!'); } }); [RoutePrefix("api")] public class LandingPageController : ApiController { [HttpGet] [Route("GetQuadrantData/{unit}/{begdate}/{enddate}", Name="GetQuadrantDataFromLandingPage")] public HttpResponseMessage GetQuadrantData(string unit, string begdate, string enddate) 

好的,这个解决方案解决了你的问题,但暗示你的代码有些变化:

在视图中,当您调用Url.Action ,您尝试从mvc控制器生成webapi路由。 您可以在我说明如何执行此操作时看到此问题 。

基本上这个想法是使用Url.RouteUrl和额外的路由值httproute = true

现在,您需要更改代码中的某些部分才能使用此代码:

首先,您使用属性来定义Web api路由,因此将在WebApiConfig类中定义的路由之后添加此路由,并且正如我在引用问题的答案中所述, Url.RouteUrl将返回匹配的第一个路由路线值。 因此,您需要在默认路由之前在WebApiConfig声明路由:

 /* attributes removed */ public class LandingPageController : ApiController { public HttpResponseMessage GetQuadrantData(string unit, string begdate, string enddate) { ... public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); /* Route added before the default one */ config.Routes.MapHttpRoute( name: "QuadrantData", routeTemplate: "api/{unit}/{begdate}/{enddate}" ); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } 

如果不这样做,将匹配默认路由,因为{id}是可选的, unitbegdateenddate将作为查询参数传递。

一旦修复了这个问题,你就会遇到另一个问题,为了能够使用Url.RouteUrl你需要知道所有的路由值(unit,begdate,enddate),这些值只有在脚本函数执行时才可用。 但是,当为客户端生成html时,在服务器中处理.cshtml中的所有剃刀代码。

正如您所看到的,当执行javascript时,您没有执行'@Url.RouteUrl...''@Url.Action...' ,此时您只是处理一个字符串,当剃刀表达式返回值时被处理了。

您可以做的一件事是将“模板”值传递给Url.RouteUrl调用,并在使用实际值执行脚本时替换它:

 var url = '@Url.RouteUrl(new { unit = "(unit)", begdate = "(begdate)", enddate = "(enddate)", httproute = true })' url = url.replace("(unit)", unitval) .replace("(begdate)", begdateval) .replace("(enddate)", enddateval) $.ajax({ type: 'GET', url: url, contentType: 'application/json', cache: false, success: function (returneddata) { }, error: function () { alert('hey, boo-boo!'); } }); 

replace之后,变量url的值将如下/api/ABUELOS/2016-08-07/2016-08-13


如果您不想将路由移动到WebApiConfig ,可以在RouteAttribute设置名称:

 [RoutePrefix("api")] public class LandingPageController : ApiController { [Route("{unit}/{begdate}/{enddate}", Name = "QuadrantData")] public HttpResponseMessage GetQuadrantData(string unit, string begdate, string enddate) { ... 

并在Url.RouteUrl调用中指定路由名称:

 var url = '@Url.RouteUrl("QuadrantData", new { unit = "(unit)", begdate = "(begdate)", enddate = "(enddate)", httproute = true })' 

这种方式在您的代码中不那么具有侵入性,但您需要知道要使用的路由的名称。

希望这可以帮助。

关于你的观点:

如果我在浏览器中手动输入该URL,以便URL栏显示“ http:// localhost:52194 / api / ABUELOS / 2016-08-21 / 2016-08-27 ”它可以工作 – 到达方法并且它“做到了。”

修改您的Ajax调用如下所示应解决您的问题,并将向映射的URL发送GET请求( 使用按钮单击事件处理程序显示 ):

  $("#btnGetData").click(function () { var unitval = 'ABUELOS'; var begdateval = '2016-08-21'; var enddateval = '2016-08-27'; $.getJSON("api/" + unitval + "/" + begdateval + "/" + enddateval, function (Data) { // do what ever you want with the success response }) .fail( function (jqXHR, textStatus, err) { // do what ever you want with the failed response }); }); 

当你需要完整的url来完成请求时,你只给你的jQuery控制器和动作名称。 此外,您的终点有一个’api’前缀。 如果您的服务器在本地运行,则需要您的url属性类似于http:// localhost :{port} / api / {controller} / {action}。