132

HttpPostMVC4 Web API プロジェクトの使用を開始しています。複数のメソッドを持つコントローラーがあります。コントローラーは次のようになります。

コントローラ

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

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

ここでMyRequestTemplateは、リクエストから来る Json の処理を​​担当するテンプレート クラスを表します。

エラー:

Fiddler for を使用してリクエストを行うとhttp://localhost:52370/api/VTRouting/TSPRoutehttp://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 を渡します。

4

11 に答える 11

148

1 つのコントローラーで複数のアクションを実行できます。

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

  • ActionName最初に次のような属性でアクションを装飾します

     [ActionName("route")]
     public class VTRoutingController : ApiController
     {
       [ActionName("route")]
       public MyResult PostRoute(MyRequestTemplate routingRequestTemplate)
       {
         return null;
       }
    
      [ActionName("tspRoute")]
      public MyResult PostTSPRoute(MyRequestTemplate routingRequestTemplate)
      {
         return null;
      }
    }
    
  • 次に、ファイルで次のルートを定義しWebApiConfigます。

    // 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}"
    );
    
于 2012-10-03T07:02:54.550 に答える
47

問題に対する別の解決策はRoute、アノテーションによってメソッドのルートを指定できるようにすることです。

[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;
    }
}
于 2015-11-26T23:43:56.917 に答える
28

使用する:

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

これはもはや RESTful なアプローチではありませんが、次のように (Web API が動詞に基づいてアクションを自動的に決定するのではなく) 名前でアクションを呼び出すことができるようになりました。

[POST] /api/VTRouting/TSPRoute

[POST] /api/VTRouting/Route

一般に信じられていることとは反対に、このアプローチには何も問題はなく、Web API を悪用していません。Web API のすべての優れた機能 (ハンドラーの委任、コンテンツ ネゴシエーション、メディアタイプフォーマッターなど) を引き続き活用できます。RESTful なアプローチを捨てるだけです。

于 2012-07-10T07:02:52.423 に答える
13

Web APIエンドポイント(コントローラー)は、get / post / put/delete動詞を受け入れる単一のリソースです。通常のMVCコントローラーではありません。

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

編集: これは機能しません。解決する際には、型にモデルバインドしようとするのではなく、パラメーターの数によって進むようです。

関数をオーバーロードして、さまざまなパラメーターを受け入れることができます。自分のやり方で宣言すれば大丈夫だと確信していますが、メソッドとは異なる(互換性のない)パラメーターを使用しました。パラメータが同じである場合、モデルバインディングはどちらを意味するのかわからないため、運が悪いことになります。

[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) {}
}

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

編集:

単純型を使用するときに標準テンプレート(含めるように編集)を使用する場合、オーバーロードは問題なく機能します。署名の異なる2つのカスタムオブジェクトを使用して、別の方法でテストしました。それを機能させることはできませんでした。

  • 複雑なオブジェクトとのバインドは「深く」見えないので、それはダメです
  • クエリ文字列に追加のパラメータを渡すことで、これを回避できます
  • 私が利用可能なオプションについて与えることができるよりも良い記事

この場合、これは私のために働きました、それがあなたをどこに連れて行くか見てください。テストのみの例外。

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' } )
于 2012-07-10T07:27:11.703 に答える
6

同じ Web API コントローラーに複数の Get メソッドと Post メソッドを追加することができます。ここでは、デフォルト ルートが問題の原因となっています。Web API は、上から下への一致するルートをチェックするため、すべてのリクエストに対してデフォルト ルートが一致します。デフォルト ルートでは、1 つのコントローラーで 1 つの Get および Post メソッドのみが可能です。次のコードを先頭に配置するか、デフォルト ルートをコメント アウト/削除します。

    config.Routes.MapHttpRoute("API Default", 
                               "api/{controller}/{action}/{id}",
                               new { id = RouteParameter.Optional });
于 2015-04-04T05:48:42.330 に答える
0

質問はすでに答えられていると思います。私はまた、署名されたメソッドが同じで名前が異なるwebApiコントローラーを探していました。Calculator を WebApi として実装しようとしていました。Calculator には、署名は同じで名前が異なる 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 で認証/承認を設定するだけで完了です。

お役に立てれば!

于 2015-01-14T11:50:39.200 に答える
-1
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 の概念に違反しているかどうかはわかりませんが、機能します。誰かがこの問題について啓発できたなら。URIが次の場合はどうなりますか

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

私のジャーナルがaggregaterootのようなものであることがわかるかもしれませんが、公開専用の別のコントローラーを定義して、私のURLで公開のID番号を渡すことはできますが、これははるかに理にかなっています. ジャーナル自体がなければ私の出版物は存在しないからです。

于 2012-07-12T11:51:59.243 に答える