MVC4 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の処理を担当するテンプレートクラスを表します。
エラー:
http://localhost:52370/api/VTRouting/TSPRoute
またはhttp://localhost:52370/api/VTRouting/Route
に対してFiddlerを使用してリクエストを行うと、エラーが発生します。
要求に一致する複数のアクションが見つかりました
上記の方法のいずれかを削除すると、正常に機能します。
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のjsonをRequestBodyに渡します。
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}"
);
あなたの問題に対するより良い解決策は、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;
}
}
つかいます:
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のすべての素晴らしい機能(ハンドラーの委任、コンテンツネゴシエーション、mediatypeformatterなど)を引き続き活用できます。RESTfulアプローチを捨てるだけです。
Web APIエンドポイント(コントローラー)は、get/post/put/delete動詞を受け入れる単一のリソースです。これは、not通常のMVCコントローラーです。
必然的に、/api/VTRouting
には、送信するパラメーターを受け入れるoneHttpPostメソッドしか存在できません。 [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) {}
}
Ajaxを使用するために多くのことを行う1つのクラスを作成する場合、標準のコントローラー/アクションパターンを使用しない大きな理由はありません。唯一の本当の違いは、メソッドシグネチャがそれほどきれいではないことであり、それらを返す前に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' } )
同じWeb APIコントローラーに複数のGetおよびPostメソッドを追加することが可能です。ここで、デフォルトルートは問題の原因です。 Web APIは、上から下に一致するルートをチェックするため、すべてのリクエストでデフォルトルートが一致します。デフォルトルートごとに、1つのコントローラーでは1つのGetおよびPostメソッドのみが可能です。次のコードを先頭に配置するか、デフォルトルートをコメントアウト/削除します。
config.Routes.MapHttpRoute("API Default",
"api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
ルートプレフィックス[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()
{
}
}
}
質問はすでに答えられていると思います。また、署名された同じ方法で名前が異なる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で認証/許可を設定するだけで完了です!
お役に立てれば!
「action = action_name」をURLに追加しただけで、ルーティングエンジンは必要なアクションを認識します。 ActionName属性もアクションに追加しましたが、それが必要かどうかわかりません。