2

私は 2 つのメソッドを持つ Web API コントローラーを持っています。最初のメソッドが単純なプロジェクト リストを返し、2 番目のメソッドが特定のユーザーに割り当てられたすべてのプロジェクトを返すとしましょう。

public class ProjectController: ApiController
{
    public IQueryable<Project> Get() { ... }

    [HttpGet]
    public IQueryable<Project> ForUser(int userId) { ... }
}

この場合、メソッドの実装は重要ではありません。

Web API のルート構成も、カスタム メソッド名をサポートするように調整されています。

config.Routes.MapHttpRoute(
    "DefaultApi",
    "api/v1/{controller}/{id}",
    new { id = RouteParameter.Optional }
);

config.Routes.MapHttpRoute(
    "DefaultApiWithAction",
    "api/v1/{controller}/{action}");

/api/v1/projects/正常に動作し、とエンドポイントの両方にアクセスできます/api/v1/projects/forUser/が、ルート エンジンがあまりにもスマートであるように思われるため、リクエストがメソッドに/api/v1/projects?userId=1一致する可能性があると判断し (引数名のためだと思います) 、ルートの一部を無視します。ForUser(..)userId{action}

この動作を回避し、アクション部分を URL で明示的に指定する必要がある方法はありますか?

4

3 に答える 3

3

カップルのもの。まず第一に、このルート:

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

オプションのパラメータとして「アクション」はありません。オプションとして含めidましたが(タイプミスだと思います)、ルートに存在しないため、補足セグメントが1つしかない場合は一致しません。このルートを通過するのは、コントローラーとアクションの2つの部分を含むURLのみです。このURL:

/api/v1/projects?userId=1

...単一のセグメントが含まれますが、含まれません。このルート、および2番目のコンポーネントがないその他のルートは、デフォルトでこのルートになります。

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

...これはコントローラーとオプションのIDのみを取ります。アクションパラメータを取得するために指定されたURLを再フォーマットするか、アクションをオプションにして必要に応じてデフォルトを設定するようにルートを書き直す必要があります。これはすべてアプリケーションアーキテクチャに依存しますが、常に単純さの面で誤りがあります。ルートは非常に複雑になる可能性があります。一般的には、単純な方が優れています。

必須/オプションのルートコンポーネントについては、次の2つの点に注意してください。

  • 匿名オブジェクトでオプションとして設定されていない限り、すべてのルートセグメントが必要です。
  • セグメントにデフォルト値がある場合は、セグメントを除外することもできます。デフォルト値は、匿名オブジェクトに.の形式で指定することで設定されますplaceholder = value
于 2012-12-03T10:26:00.247 に答える
0

私はあなたの問題を完全には理解していません。/api/v1/projects?userId=1実際にForUserアクションを呼び出すべきではありませんか?

とにかく、必要なアクションを実行するには、HttpRouteを次のようにします。

   name: "DefaultApi",
   routeTemplate: "api/v1/{controller}/{action}/{id}",
   defaults: new { id = System.Web.Http.RouteParameter.Optional });

今、あなたはこのように呼び出すことができます: /api/v1/projects/ForUser/2

于 2012-12-03T10:25:50.683 に答える
0

私は最終的に私の要件を満たすソリューションを思いつきました。この回答と、 leviとuser1797792によって提案されたアイデアを次の構成に組み合わせました。

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

config.Routes.MapHttpRoute(
    "DefaultApiGet",
    "api/v1/{controller}",
    new { action = "Get" },
    new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });

ここでは、構成の順序が非常に重要であることに注意してください。

まず、任意のクエリ文字列 (他のアクションのパラメーターと名前が一致する引数を含む)/api/v1/projectsを含むリクエストは、2 番目のルートを介してメソッドにディスパッチされます。実際のプロジェクトでは、提供されたリクエスト引数に基づいて返されるアクションをフィルター処理するカスタム アクション フィルターがこのアクションにアタッチされているため、これは重要です。Get()IQueryable

api/v1/projects/forUser/1ForUser(int id)のようなリクエストは、最初のルートによって method にディスパッチされます。よりクリーンな URL を構築するために、userIdパラメータの名前を allowed に変更しました。id

明らかに、このアプローチにはいくつかの制限がありますが、私の特定のケースで必要なのはそれだけです。

于 2012-12-03T14:14:34.257 に答える