当我尝试使用$ .getJSON调用我的Web API控制器方法时,我遇到了一个令人沮丧的问题:它总是最终在控制台中显示以下消息:“无法加载资源:服务器回复状态为405(方法不允许)“
这是我的控制器:
using MyProject.Domain;
using MyProject.WebApp.Session;
using System;
using System.Linq;
using System.Web.Mvc;
namespace MyProject.WebApp.ApiControllers.Favorites
{
public class FavoriteArticlesController : BaseController<FavoriteArticle, Guid>
{
[HttpGet]
public object SetFavorite(Guid articleId, bool isFavorite)
{
try
{
if (isFavorite)
{
var favorite = new FavoriteArticle
{
UserId = UserInfo.GetUserId(),
ArticleId = articleId
};
_repo.Upsert(favorite);
}
else
{
var favorite = _repo.GetAll()
.First(fa => fa.ArticleId.CompareTo(articleId) == 0);
_repo.Delete(favorite.Id);
}
_repo.Commit();
return new { Success = true, Error = (string)null };
}
catch (Exception ex)
{
return new { Success = false, Error = ex.Message };
}
}
}
}
如果以任何方式相关,BaseController自然派生自ApiController。如果需要,这是代码:
using MyProject.Data.Repository;
using MyProject.Data.Services;
using MyProject.Domain;
using System.Web.Http;
namespace MyProject.WebApp.ApiControllers
{
public class BaseController<TEntity, TKey> : ApiController
where TEntity : class, IEntity<TKey>, new()
{
protected UnitOfWork _unitOfWork;
protected Repository<TEntity, TKey> _repo;
protected BaseController()
{
_unitOfWork = new UnitOfWork();
_repo = _unitOfWork.GetRepository<TEntity, TKey>();
}
}
}
以下是拨打电话的其中一项功能:
$.fn.bindFavoriteArticle = function () {
this.click(function () {
var link = $(this);
$.getJSON('/api/FavoriteArticles/SetFavorite', { ajax: true, articleId: link.attr('data-target-id'), isFavorite: true }, function (response) {
if (response.Success === true) {
link.children('i').removeClass('fa-heart-o')
.addClass('fa-heart');
link.attr('data-toggle', 'unfavoriteArticle')
.unbind('click')
.bindUnfavoriteArticle();
} else {
// TODO : use bootstrap alert messages
alert(response.Error);
}
});
});
};
我在这里和那里看到路由配置可能是问题的根源,所以这里是RouteConfig.cs的内容:
using System.Web.Mvc;
using System.Web.Routing;
namespace MyProject.WebApp
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "ApiDefault",
url: "api/{controller}/{action}/{id}",
defaults: new { controller = "SubscriptionsController", action = "GetSelectList", id = UrlParameter.Optional }
);
}
}
}
知道发生了什么事吗?我觉得有很多关于Web API如何工作的遗漏...
答案 0 :(得分:1)
您正在RouteConfig
而非WebApiConfig
内配置api路由。
您需要WebApiConfig.cs
文件夹中的App_Start
文件:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
...因此您可以移除routes.MapRoute()
内api/{controller}/{action}/{id}
的{{1}}。
然后在RouteConfig.cs
中,您可以这样称呼它:
Global.asax
有了这个,两个链接都应该适用于你的控制器样本:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); // only if you have areas...
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
您通过/api/FavoriteArticles?articleId=a7d944f7-66be-4200-9b89-26eda5173dca&isFavorite=true
/api/FavoriteArticles/SetFavorite?articleId=a7d944f7-66be-4200-9b89-26eda5173dca&isFavorite=true
调用它的方式是正确的,根本不需要更改它。
答案 1 :(得分:1)
正如其他一个答案所述,代码配置了错误的路由。对于web api,配置WebApiConfig
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Web API routes
//Enable Attribute routing is they are being used.
config.MapHttpAttributeRoutes();
//Convention based routes.
//Matches GET /api/FavoriteArticles/SetFavorite
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Matches GET /api/FavoriteArticles
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
确保在MVC路由之前配置它。
protected void Application_Start() {
// Pass a delegate to the Configure method.
GlobalConfiguration.Configure(WebApiConfig.Register);
//...other configurations
}
关于重构控制器的一些建议要更加安静一些。尝试从操作中返回IHttpActionResult
。简化了框架,使您可以更好地控制响应的返回方式。
[RoutePrefix("api/favoritearticles"]
public class FavoriteArticlesController : BaseController<FavoriteArticle, Guid> {
[HttpPost]
[Route("{articleId:guid}")] //Matches POST api/favoritearticles/{articleId:guid}
public IHttpActionResult SetFavorite(Guid articleId) {
var favorite = new FavoriteArticle
{
UserId = UserInfo.GetUserId(),
ArticleId = articleId
};
_repo.Upsert(favorite);
_repo.Commit();
return Ok(new { Success = true, Error = (string)null });
}
[HttpDelete]
[Route("{articleId:guid}")] //Matches DELETE api/favoritearticles/{articleId:guid}
public IHttpActionResult RemoveFavorite(Guid articleId) {
var favorite = _repo.GetAll()
.First(fa => fa.ArticleId == articleId);
if(favorite == null) return NotFound();
_repo.Delete(favorite.Id);
_repo.Commit();
return Ok(new { Success = true, Error = (string)null });
}
}
控制器应尽可能精确,因此即使通过注入服务进入控制器,上述应该更加精简。
错误处理是一个贯穿各领域的问题,也应该通过框架的可扩展性点来提取和处理。
答案 2 :(得分:0)
我相信默认情况下JSON请求会阻止GET方法以避免JSON劫持。尝试将您的方法转换为POST(并更新ajax调用)或将当前函数返回到
x=rand(113,1);
y=rand(113,1);
x=sort(x, 'descend');
v=[x,y];
n_vect = [];
b_vect = [];
for i=2:113
m=max(v(1:i-1,2));
if v(i,2) > m == true
n=(v(i-1,2))
b=(v(i-1,1))
n_vect = [n_vect,n];
b_vect = [b_vect,b];
end
end