Web APIルーティング-api / {controller} / {action} / {id}「dysfunctions」api / {controller} / {id}


94

Global.asaxにデフォルトルートがあります。

 RouteTable.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

特定の機能をターゲットにしたいので、別のルートを作成しました。

RouteTable.Routes.MapHttpRoute(
         name: "WithActionApi",
         routeTemplate: "api/{controller}/{action}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

だから、私のコントローラーでは、私は:

    public string Get(int id)
    {
        return "object of id id";
    }        

    [HttpGet]
    public IEnumerable<string> ByCategoryId(int id)
    {
        return new string[] { "byCategory1", "byCategory2" };
    }

電話をかける.../api/records/bycategoryid/5と私が欲しいものをくれます。しかし、呼び出し.../api/records/1は私にエラーを与えます

リクエストに一致する複数のアクションが見つかりました:...

ルートはちょうどURLが有効であるかを定義しますが、それが機能マッチング、両方に来るとき-私はそれがある理由を理解Get(int id)し、ByCategoryId(int id)一致api/{controller}/{id}するもので、混乱の枠組みを。

デフォルトのAPIルートを再び機能させるために何をする必要があります{action}か?RecordByCategoryIdControllerリクエストするデフォルトのAPIルートに一致する名前の別のコントローラーを作成することを考えました.../api/recordbycategoryid/5。しかし、私はそれが「汚い」(したがって不十分な)解決策であることがわかりました。私はこれに関する答えを探しましたが、{action}この問題について言及しているルートの使用に関するチュートリアルはありません。

回答:


104

ルートエンジンは、ルールを追加するときと同じシーケンスを使用します。最初に一致したルールを取得すると、他のルールのチェックを停止し、これを実行してコントローラーとアクションを検索します。

したがって、次のことを行う必要があります。

  1. 特定のルールを一般的なルール(デフォルトなど)の前に置きます。つまり、RouteTable.Routes.MapHttpRoute最初に「WithActionApi」、次に「DefaultApi」をマップするために使用します。

  2. defaults: new { id = System.Web.Http.RouteParameter.Optional }idがオプションになると、「/ api / {part1} / {part2}」のようなURLは「DefaultApi」に移動しないため、「WithActionApi」ルールのパラメーターを削除します。

  3. 名前付きアクションを「DefaultApi」に追加して、ルートエンジンに入力するアクションを指示します。そうしないと、コントローラーに複数のアクションがあると、エンジンはどのアクションを使用すべきかを認識できず、「リクエストに一致する複数のアクションが見つかりました:...」をスローします。次に、それをGetメソッドと一致させるには、ActionNameAttributeを使用します。

したがって、ルートは次のようになります。

// Map this rule first
RouteTable.Routes.MapRoute(
     "WithActionApi",
     "api/{controller}/{action}/{id}"
 );

RouteTable.Routes.MapRoute(
    "DefaultApi",
    "api/{controller}/{id}",
    new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
);

そしてあなたのコントローラー:

[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public string Get(int id)
{
    return "object of id id";
}        

[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
    return new string[] { "byCategory1", "byCategory2" };
}

1
上記のアドバイスを試したところ、すべてが期待どおりに機能しました。その「秘密」をありがとうございました。
Mickael Caruso

回答のポイント2で、idオプションの場合、ルートに一致するアクションが見つからない/api/{part1}/{part2}場合でも、URL like はDefaultApiルートに入る可能性がありますWithActionApi。私が間違っていたら訂正してください。
orad 2015

api / {controller} / {action}のみを使用したい場合はどうなりますか。IDなし。他の誰かが同じ問題に直面している場合。WebApiConfigを忘れてください。属性ルーティングについて読んでください。
-ahsant

40

属性ルーティングの助けを借りて問題を解決でき ます

コントローラ

[Route("api/category/{categoryId}")]
public IEnumerable<Order> GetCategoryId(int categoryId) { ... }

jqueryのURI

api/category/1

ルート構成

using System.Web.Http;

namespace WebApplication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            // Other Web API configuration not shown.
        }
    }
}

デフォルトのルーティングがデフォルトのコンベンションベースのルーティングとして機能している

コントローラ

public string Get(int id)
    {
        return "object of id id";
    }   

JqueryのURI

/api/records/1 

ルート構成

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

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

詳細については、こちらの記事をご覧ください。属性ルーティングと発明ベースのルーティングはこちらこれ


神の答え。しかし、api / {controller} / {id}と一緒にapi / {controller} / {action} / {id}をすべて追加することはできませんか?
karim 2014年

属性ルーティングは間違いなく問題を解決します。重要なポイントの1つ:Web API 2より前のバージョンでは、Web APIプロジェクトテンプレートは次のようなコードを生成しました:protected void Application_Start(){WebApiConfig.Register(GlobalConfiguration.Configuration); }属性ルーティングが有効な場合、このコードは例外をスローします。既存のWeb APIプロジェクトをアップグレードして属性ルーティングを使用する場合は、必ずこの構成コードを次のように更新してください。protected void Application_Start(){GlobalConfiguration.Configure(WebApiConfig.Register); }
Deeb

0

これを試して。

public class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        var json = config.Formatters.JsonFormatter;
        json.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        // Web API routes
        config.MapHttpAttributeRoutes();

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

        );
    }
}

0

考えられる理由は、ApiControllerからControllerを継承していない可能性もあります。同じことを理解するのにしばらく時間がかかりました。


0

ルートを区別するには、idが数値でなければならないという制約を追加してみます。

RouteTable.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         constraints: new { id = @"\d+" }, // Only matches if "id" is one or more digits.
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );  
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.