2012-07-10 26 views
109

MVC4 Web APIプロジェクトを使用し始めましたが、複数のコントローラを持つHttpPostメソッドがあります。コントローラは、次のようになります。ここではWeb APIコントローラで複数のHttpPostメソッド

コントローラ

public class VTRoutingController : ApiController 
{ 
    [HttpPost] 
    public MyResult Route(MyRequestTemplate routingRequestTemplate) 
    { 
     return null; 
    } 

    [HttpPost] 
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate) 
    { 
     return null; 
    } 
} 

MyRequestTemplate要求から入るJSONの処理を担当テンプレートクラスを表します。

エラー:私はそれが正常に動作します上記の方法のいずれかを削除した場合

Multiple actions were found that match the request

:私はhttp://localhost:52370/api/VTRouting/TSPRouteまたはhttp://localhost:52370/api/VTRouting/Routeためのフィドラーを使用して要求を行うと

私はエラーを取得します。

Global.asaxの

私はglobal.asaxにデフォルトのルーティングテーブルを変更しようとしているが、私はまだエラーを取得しています、私は私がのglobal.asax内のルートを定義する際に問題があると思います。ここで私はglobal.asaxでやっていることです。

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.MapHttpRoute(
      name: "MyTSPRoute", 
      routeTemplate: "api/VTRouting/TSPRoute", 
      defaults: new { } 
    ); 

    routes.MapHttpRoute(
     name: "MyRoute", 
     routeTemplate: "api/VTRouting/Route", 
     defaults: new {action="Route" } 
    ); 
} 

私は、POSTを使用してFiddlerでリクエストを行い、MyRequestTemplateのRequestBodyにjsonを渡します。

答えて

126

複数のアクションを1つのコントローラに含めることができます。

そのためには、次の2つのことを行う必要があります。

  • 第一、第二はWebApiConfigファイルに次のルートを定義

    [ActionName("route")]` 
    public class VTRoutingController : ApiController 
    { 
        [ActionName("route")] 
        public MyResult PostRoute(MyRequestTemplate routingRequestTemplate) 
        { 
        return null; 
        } 
    
        [ActionName("tspRoute")] 
        public MyResult PostTSPRoute(MyRequestTemplate routingRequestTemplate) 
        { 
        return null; 
        } 
    } 
    
  • のようなActionName属性を持つアクションを飾ります。

    // Controller Only 
    // To handle routes like `/api/VTRouting` 
    config.Routes.MapHttpRoute(
        name: "ControllerOnly", 
        routeTemplate: "api/{controller}"    
    ); 
    
    
    // Controller with ID 
    // To handle routes like `/api/VTRouting/1` 
    config.Routes.MapHttpRoute(
        name: "ControllerAndId", 
        routeTemplate: "api/{controller}/{id}", 
        defaults: null, 
        constraints: new { id = @"^\d+$" } // Only integers 
    ); 
    
    // Controllers with Actions 
    // To handle routes like `/api/VTRouting/route` 
    config.Routes.MapHttpRoute(
        name: "ControllerAndAction", 
        routeTemplate: "api/{controller}/{action}" 
    ); 
    
+0

はうまく動作します..... – yogee

+0

IDのタイプに制限を設定したくない場合はどうすればいいですか?意味:私はどのように文字列IDも受け入れることができますか? – frapontillo

+5

@frapontillo:IDは、ルート名から区別されるようにインテグレータでなければなりません。さもなければ、ルーティングエンジンはそれをidではなくアクション名として扱います。 idを文字列として持つ必要がある場合は、アクションを作成できます。 –

23

使用:

routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{action}/{id}", 
    defaults: new { id = RouteParameter.Optional } 
); 

それはもうRESTfulなアプローチではないのですが、あなたは今、このような名前であなたの行動を呼び出します(というよりも、あなたが動詞に基づいためのWeb APIは、自動的に1を決定させる)ことができます。

[POST] /api/VTRouting/TSPRoute 

[POST] /api/VTRouting/Route 

一般的な考え方とは反対に、このアプローチには何も問題はなく、Web APIを乱用するものでもありません。 Web APIのすばらしい機能(委任ハンドラ、コンテンツネゴシエーション、メディアタイプフォーマッタなど)を引き続き活用することができます.RESTfulなアプローチをするだけです。

+0

回答ありがとうございますが、それでも私には同じエラーが表示されます。 – Habib

+0

これは不可能です。あなたのアプリで何か他のものが誤って設定されている必要があります。ルート設定全体を表示できますか?また、コントローラのアクションをどのように*正確に*呼んでいますか? –

+0

ルート設定全体がglobal.asaxにあります。質問を投稿するには、要求を行うために、Fiddler-> Compose->を使用し、操作としてポストを選択してください。 – Habib

11

web apiエンドポイント(コントローラ)は、get/post/put/delete動詞を受け入れる単一のリソースです。 ではなく、で、通常のMVCコントローラです。

/api/VTRoutingには、が1つだけあります。送信するパラメータを受け入れるHttpPostメソッド。関数名は、[http]のもので飾っている限り、とは関係ありません。私は試みたことはありません。

編集:これは機能しません。解決するには、型にバインドしようとするのではなく、パラメータの数だけ進んでいるようです。

異なるパラメータを受け入れるために関数をオーバーロードすることができます。私はあなたがあなたのやり方を宣言しても、そのメソッドとは異なる(互換性のない)パラメータを使用すると、あなたはOKになるだろうと確信しています。 paramsが同じであれば、モデルバインディングはあなたが意味するものが分からないので、あなたは不運です。

[HttpPost] 
public MyResult Route(MyRequestTemplate routingRequestTemplate) {...} 

[HttpPost] 
public MyResult TSPRoute(MyOtherTemplate routingRequestTemplate) {...} 

この部分は、あなたが新しいものは、これはかなり明示的になり、そして私はあなたがこの規則に固執すべきであると言うでしょう作成したとき、彼らが与える

デフォルトのテンプレートを働く:

public class ValuesController : ApiController 
{ 
    // GET is overloaded here. one method takes a param, the other not. 
    // GET api/values 
    public IEnumerable<string> Get() { .. return new string[] ... } 
    // GET api/values/5 
    public string Get(int id) { return "hi there"; } 

    // POST api/values (OVERLOADED) 
    public void Post(string value) { ... } 
    public void Post(string value, string anotherValue) { ... } 
    // PUT api/values/5 
    public void Put(int id, string value) {} 
    // DELETE api/values/5 
    public void Delete(int id) {} 
} 

ajax用に多くのことを行うクラスを作成したい場合は、標準のコントローラ/アクションパターンを使用しない大きな理由はありません。唯一の違いは、あなたのメソッドのシグネチャはあまり美しくないので、返す前にJson(returnValue)にラップする必要があることです。

編集:単純型を使用している場合(含めるように編集)標準テンプレートを使用している場合

オーバーロードだけで正常に動作します。私は別の署名を持つ2つのカスタムオブジェクトを使って、もう一方の方法を行ってテストしました。決してそれを働かせることはできませんでした。

  • あなたが利用可能なオプションのクエリ文字列
  • A better writeup than I can giveに、余分のparamを渡すことでこれを回避できた無行く
  • thatsのように、複雑なオブジェクトを結合すると、「深い」を見ていない

このケースでは、これは私にとってはうまくいきました。テストの例外のみ。

public class NerdyController : ApiController 
{ 
    public void Post(string type, Obj o) { 
     throw new Exception("Type=" + type + ", o.Name=" + o.Name); 
    } 
} 

public class Obj { 
    public string Name { get; set; } 
    public string Age { get; set; } 
} 

そして、このフォームのようなコンソールと呼ばれる:

$.post("/api/Nerdy?type=white", { 'Name':'Slim', 'Age':'21' }) 
+0

パラメータタイプを変更しようとしましたが、コントローラー内の単一のPostメソッドしか使用できないようです。あなたの返信をありがとう – Habib

+0

私はあなたが過負荷になる可能性があるので、それを見つけるためにモデルバインディングを試みると仮定しました。しかし、それはさまざまなparamsで動作します。しかし、まだソースコードを公開していないので、醜い逆アセンブリを見ているだけです。 –

+2

+1実際には動作していない理由を説明しています。 Web APIの背後にある哲学。 – MEMark

0
public class Journal : ApiController 
{ 
    public MyResult Get(journal id) 
    { 
     return null; 
    } 
} 

public class Journal : ApiController 
{ 

    public MyResult Get(journal id, publication id) 
    { 
     return null; 
    } 
} 

私は、get/postメソッドをオーバーロードすることはrestfull APIの概念に違反するかどうかわからないが、それはworkds。誰かがこの問題を啓発していた可能性があります。私は

uri:/api/journal/journalid 
uri:/api/journal/journalid/publicationid 

としてURIを持っている場合はどうので、私はもっぱら公開のための別のコントローラを定義し、私のURLに掲載のID番号を渡すことができますが、あなたが、aggregaterootの私のジャーナルの並べ替えを見たかもしれないとして、しかしこれは、はるかに意味を与えます。ジャーナル自体がなければ私の出版物は存在しないからです。

0

私は、URLと、ルーティングエンジンは、私が何をしたいアクションを知っている、このように「アクション= ACTION_NAME」を追加しました。アクションにActionName属性も追加しましたが、必要であるかどうかはわかりません。

0

私は質問がすでに答えられていると思います。私も、同じ名前のmehtodsしかし異なる名前を持つwebApiコントローラを探していました。私はWebApiとして電卓を実装しようとしていました。電卓には、同じ署名であるが名前が異なる4つのメソッドがあります。

public class CalculatorController : ApiController 
{ 
    [HttpGet] 
    [ActionName("Add")] 
    public string Add(int num1 = 1, int num2 = 1, int timeDelay = 1) 
    { 
     Thread.Sleep(1000 * timeDelay); 
     return string.Format("Add = {0}", num1 + num2); 
    } 

    [HttpGet] 
    [ActionName("Sub")] 
    public string Sub(int num1 = 1, int num2 = 1, int timeDelay = 1) 
    { 
     Thread.Sleep(1000 * timeDelay); 
     return string.Format("Subtract result = {0}", num1 - num2); 
    } 

    [HttpGet] 
    [ActionName("Mul")] 
    public string Mul(int num1 = 1, int num2 = 1, int timeDelay = 1) 
    { 
     Thread.Sleep(1000 * timeDelay); 
     return string.Format("Multiplication result = {0}", num1 * num2); 
    } 

    [HttpGet] 
    [ActionName("Div")] 
    public string Div(int num1 = 1, int num2 = 1, int timeDelay = 1) 
    { 
     Thread.Sleep(1000 * timeDelay); 
     return string.Format("Division result = {0}", num1/num2); 
    } 
} 

とWebApiConfigに

config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: new { id = RouteParameter.Optional }); 

ちょうどIISの認証/認可を設定していると、作業が完了し、すでにあなたを提出!

希望すると便利です。

5

複数のGetメソッドとPostメソッドを同じWeb APIコントローラに追加することは可能です。ここではデフォルトルートが問題を引き起こしています。 Web APIは、TopからBottomへのルートの照合をチェックします。したがって、すべてのリクエストに対してデフォルトルートが一致します。既定のルートでは、1つのコントローラで1つのGetとPostメソッドしか使用できません。どちらのデフォルトルートを削除します/上に次のコードを配置するか、コメントアウト

config.Routes.MapHttpRoute("API Default", 
           "api/{controller}/{action}/{id}", 
           new { id = RouteParameter.Optional }); 
13

アノテーションによる方法へのルートを指定することができますRoute使用するAあなたの問題へのよりよい解決策は次のようになります。

[RoutePrefix("api/VTRouting")] 
public class VTRoutingController : ApiController 
{ 
    [HttpPost] 
    [Route("Route")] 
    public MyResult Route(MyRequestTemplate routingRequestTemplate) 
    { 
     return null; 
    } 

    [HttpPost] 
    [Route("TSPRoute")] 
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate) 
    { 
     return null; 
    } 
} 
+0

どのような名前空間がルートになりますか?私はMVC4を使用しており、ルートは認識されません。 – eaglei22

+0

次の2つのソースを参照してください。http://www.asp.net/web-api/overview/web-api-routing-and-actions/create-a-rest-api-with-attribute-routing http:// www .asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2 – Wisienkas

+0

はい、これはすべき方法です。ありがとう。 – newman

1

コントローラレベルでRoute Prefix [RoutePrefix( "api/Profiles")]を置き、アクションメソッド[Route( "LikeProfile")]にルートを設定します。 global.asaxファイルで何も変更する必要はありません

namespace KhandalVipra.Controllers 
{ 
    [RoutePrefix("api/Profiles")] 
    public class ProfilesController : ApiController 
    { 
     // POST: api/Profiles/LikeProfile 
     [Authorize] 
     [HttpPost] 
     [Route("LikeProfile")] 
     [ResponseType(typeof(List<Like>))] 
     public async Task<IHttpActionResult> LikeProfile() 
     { 
     } 
    } 
} 
関連する問題