2017-05-18 42 views
2

$ .getJSONを使用してWeb APIコントローラメソッドを呼び出そうとすると、不満を感じています。常に次のメッセージが表示されて終了します。コンソール:「リソースの読み込みに失敗しました:サーバーは、405の状態で応答が(メソッド許可されていません)」ここ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から。そう、ここだ、

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

は、私がここで見て、ルート設定は、問題の原因があるかもしれない:ここでは、必要に応じてコードです:

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

は、そして、ここで電話をかける機能の一つです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

'/ api/FavoriteArticles/SetFavorite'にlink.attr( 'data-target-id')を取ろうとしてください –

答えて

1

他の回答の1つで述べたように、コードでは間違ったルートが設定されていました。ウェブ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 }); 
    } 
} 

コントローラーは注入されたサービスを介してコントローラーにさらにスリム化されるように、できるだけリーンにする必要があります。

エラー処理はクロスカッティングの問題であり、フレームワークの拡張ポイントによっても抽出して処理する必要があります。

+0

本当にありがとうございました。あなたのアドバイスは本当に役に立ちました。 – ZipionLive

0

JSONリクエストは、JSONハイジャックを避けるために、デフォルトではGETメソッドをブロックすると考えています。あなたはRouteConfigはなくWebApiConfig内のAPIのルートを設定しているPOSTにあなたの変換方法のいずれか試してみてください(とAJAX呼び出しを更新)、または

return Json(new { Success = true, Error = (string)null }, JsonRequestBehavior.AllowGet); 
1

にあなたの現在の関数の戻り値を変更します。

あなたはこれであなたApp_Startフォルダ内のファイルWebApiConfig.cs必要があります。

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 
    } 
} 

を...ので、あなたのRouteConfig.csapi/{controller}/{action}/{id}ためroutes.MapRoute()を削除することができます。 、両方のリンクをお使いのコントローラのサンプルのため正常に動作する必要があります。これにより

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

は、その後、あなたのGlobal.asaxであなたはこのようにそれを呼び出す

/api/FavoriteArticles?articleId=a7d944f7-66be-4200-9b89-26eda5173dca&isFavorite=true 
/api/FavoriteArticles/SetFavorite?articleId=a7d944f7-66be-4200-9b89-26eda5173dca&isFavorite=true 

あなたはjQueryを経由して、それを呼び出している方法がありますそれをまったく変更する必要はありません。

+0

2番目のリンクは動作しませんアクション名を取るルートテンプレートはありません – Nkosi

+0

@Nkosi実際に動作します私は自分自身をテストしました。 – Alisson

+1

これは最も奇妙です。 OK。私はそれを考え出した。デフォルトテンプレートの '{id}'プレースホルダに 'SetFavorite'をマッチさせて、クエリ文字列とマッチさせています。それは偽陽性になります。アクションにidパラメータを指定すると、それが正しいことがわかります。 – Nkosi

関連する問題