web-dev-qa-db-ja.com

複数のオプションパラメータルーティング

私のwebapiプロジェクトには次のルート定義があります。パラメータの1つが渡されないという問題があります。例えば;

/ Controller/Action/param2/startdate/enddateを呼び出すと、param2に渡した値がparam1に使用され、その逆も同様です。問題は、RoutingModuleが、指定されたルート値がparam1ではなくparam2にあることを検出できないことです。

URLでクエリ文字列を使用しているがクエリ文字列を使用したくない場合は機能します。あなたの助けに感謝。

私が期待することを達成する方法はありますか?

config.Routes.MapHttpRoute(
    name: "RetrieveHistory",
    routeTemplate: "{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}",
    defaults: new
    {
        controller = "Vend",
        action = "RetrieveUtrnHistory",
        param1 = RouteParameter.Optional,
        param2 = RouteParameter.Optional,
        starDate = RouteParameter.Optional,
        endDate = RouteParameter.Optional
    });

ありがとう

7
Akil Deepak

問題を解決するには、次のことを考慮に入れる必要があります。

  • 複数のルートを登録できます。 URLを処理できる最初に登録されたルートがそれを処理します。
  • スラッシュ/以外のものを区切り文字として使用して、ルートの一部を区別できるようにすることができます
  • パラメータ制約(通常は正規表現)を使用して、パラメータが1つまたは他の種類であるかどうかを簡単に見つけられるようにすることができます。
  • パラメーターのデフォルト値を指定できます。その場合、actionメソッドにはパラメーターのデフォルト値が必要です(MVCの場合を除き、パラメーターがnull可能または参照型である必要がある場合のみ)。

URLがどのように見えるかを教えてくれなかったので、私自身の例を紹介します。

次のようなアクションを持つTestController WebAPIコントローラークラスがあるとします。

// GET api/Test/TestAction/ ...
[HttpGet]
public object TestAction(int param1, DateTime startDate, DateTime endDate, 
                         int? param2 = null)
{
    return new
    {
        param1 = param1,
        param2 = param2,
        startDate = startDate,
        endDate = endDate
    }.ToString();
}

注:デフォルトルートでは、GetXxxという名前のWebAPIコントローラーのメソッドがHTTPGETで使用でき、PostXxxという名前のメソッドがHTTPで使用できますPOST =など。ただし、URLテンプレートにControllerActionを含めたら、[HttpXxx]属性を使用して、必要なHTTPメソッドでメソッドを使用できるようにする必要があります。

中央のオプションのパラメータ

この最初の例では、param1param2の両方が整数であり、stardDateendDateが日付であると想定しています。

http://myhost/api/Mycontroller/Myaction/12/22/2014-12-01/2014-12-31
http://myhost/api/Mycontroller/Myaction/22/2014-12-01/2014-12-31

最初のURLを次のようなパラメータに一致させる場合:

param1 = 12; param2 = 22; startDate = 2014-12-01; endData = 2014-12-31

そしてこれらのような2番目:

param1 = 12; param2 = null; startDate = 2014-12-01; endData = 2014-12-31

2つのルートを登録する必要があります。1つは可能な各URL構造に一致します。

// for the 1st
routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}"
// for the 2nd
routeTemplate: "api/{controller}/{action}/{param1}/{startDate}/{endDate}"

この場合、両方のルートは相互に排他的であることに注意してください。つまり、単一のURLは一方のルートにのみ一致するため、他のルートに登録できます。

ただし、2番目のURLはparam2の値を定義しておらず、TestActionメソッドはそれを必要とすることに注意する必要があります。これは機能しません。コントローラーのメソッドとルート登録の両方に、このパラメーターのデフォルト値を含める必要があります。

  • アクションパラメータint? param2 = null(C#ではオプションのパラメータを最後にする必要があります)。
  • ルートにはデフォルトが含まれている必要があります:defaults: new { param2 = RouteParameter.Optional }

これは、真ん中の問題のオプションのパラメータを解決する方法です。一般に、オプションのパラメーターの数に応じていくつかのルートを定義し、WebAPIアクションメソッドでこのパラメーターをデフォルト値で宣言する必要があります。

注:上記で書いたように、MVCでは、これを機能させるためにメソッドパラメーターにデフォルト値を指定する必要はありません。

パラメータの制約

ルートパラメータに制約を指定すると、次の2つの結果が生じます。

  1. パラメータ値が期待される形式であるという保証があります
  2. 最も重要なことは、ルートは、フォーマットが予期されたものである場合にのみURLを処理することです。したがって、これはURLをより選択的にするのに役立ち、したがってより柔軟になります。

次のように、ルート登録にconstraintパラメータを追加するだけです。

config.Routes.MapHttpRoute(
    name: "Multiparam2",
    routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}",
    constraints: new
    {
        startDate = @"20\d\d-[0-1]?\d-[0-3]?\d", // regex
        endDate = @"20\d\d-[0-1]?\d-[0-3]?\d" // regex
    },
    defaults: new object { }
);

空の場合でも、defaultsパラメーターを指定する必要があることに注意してください。

注:この場合の制約は、20XX年の日付、1桁、または0xまたは1xとして表される月、および1桁または0x、1x、2xとして表される日付にのみ一致する正規表現です。または3x、ダッシュで区切ります。したがって、この正規表現は2012-1-1または2015-12-30と一致しますが、1920-12-30とは一致しません。必要に応じて正規表現を調整する必要があります。

最後のオプションパラメータ

この時点で、オプションのパラメーターをサポートする方法と、ルートテンプレートに一致するようにそれらの形式(制約)を指定する方法について説明しました。

オプションのパラメータを定義する通常の方法は、URLテンプレートの最後で行うことです。この場合、ルートにパラメータがない場合は、すべてルートの最後にある必要があります。 (これを中央のオプションと比較してください:異なるルートが必要です)。

この例で、オプションのparam2、およびstartDateendDateを作成する場合は、ルート登録でそれらを定義し、アクションでデフォルトのパラメーター値を設定する必要があります。方法。

最終的なコードは次のようになります。

[HttpGet]
public object TestAction(int param1, int? param2 = null, DateTime? startDate = null, 
                         DateTime? endDate = null)
{
    return new
    {
        param1 = param1,
        param2 = param2,
        startDate = startDate,
        endDate = endDate
    }.ToString();
}



config.Routes.MapHttpRoute(
    name: "Multiparam1",
    routeTemplate: "api/{controller}/{action}/{param1}/{startDate}/{endDate}",
    constraints: new
    {
        startDate = @"20\d\d-[0-1]?\d-[0-3]?\d",
        endDate = @"20\d\d-[0-1]?\d-[0-3]?\d"
    },
    defaults: new
    {
        param2 = RouteParameter.Optional,
        startDate = RouteParameter.Optional,
        endDate = RouteParameter.Optional
    }
);

config.Routes.MapHttpRoute(
    name: "Multiparam2",
    routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}",
    constraints: new
    {
        startDate = @"(20\d\d-[0-1]?\d-[0-3]?\d)?",
        endDate = @"(20\d\d-[0-1]?\d-[0-3]?\d)?"
    },
    defaults: new
    {
        startDate = RouteParameter.Optional,
        endDate = RouteParameter.Optional
    }
);

この場合、次のことに注意してください。

  1. ルートが一致しない可能性があるため、図に示すように、正しい順序で登録する必要があります。最初にMultiparam2ルートを登録した場合、次のようなURLが誤って処理されます:http://localhost:1179/api/test/testaction/1/2014-12-12/2015-1-1param1=1; param2="2014-12-12"; startDate="2015-1-1"。 (param2=@"\d+"のように、数値のみを受け入れるparam2に追加の制約を設定することで、これを回避できます)
  2. アクションには、startDateおよびendDateのデフォルト値が必要です。

結論

慎重に、さまざまな位置でデフォルトパラメータを処理できます。

  • 正しい順序でルートを登録する
  • ルートのデフォルトパラメータを定義し、コントローラのアクションのデフォルト値も定義します
  • 制約を使用する

ルートがどのように見えるかを慎重に計画すると、いくつかのルートとオプションのパラメーターを使用して必要なものを取得できます。

17
JotaBe

JotaBeの答えは素晴らしく完全でした。パラメータがオプションであるかどうかを考慮する必要があります。最も低いパラメータから最も高いパラメータの順にrouteTemplateを記述する必要があります。

と同じように :

// for the 1st
routeTemplate: "api/{controller}/{action}/{param1}/{startDate}/{endDate}"

// for the 2nd
routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}"
0
ali mahmoodi