web-dev-qa-db-ja.com

Web APIルーティング-api / {controller} / {action} / {id}「機能不全」api / {controller} / {id}

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}に一致しますconfusesフレームワーク。

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

92
Mickael Caruso

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

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

  1. 一般的なルール(デフォルトなど)の前に特定のルールを置きます。つまり、RouteTable.Routes.MapHttpRouteを使用して最初に "WithActionApi"をマッピングし、次に "DefaultApi"をマッピングします。

  2. 「WithActionApi」ルールのdefaults: new { id = System.Web.Http.RouteParameter.Optional }パラメータを削除します。IDがオプションになった場合、「/ api/{part1}/{part2}」などのURLは「DefaultApi」になりません。

  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" };
}
101
Chris Li

属性ルーティングを使用して問題を解決できます

コントローラー

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

詳細については、記事を参照してください ここで属性ルーティングとonvention-basedルーティングthis

36
MSTdev

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

0
Paritosh Tiwari

これを試して。

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
Amit

ルートを区別するには、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 }
         );  
0
Derek Wade