1

バージョン管理に名前空間の選択を使用する Web API 2.2 プロジェクトにカスタム コントローラー セレクターを使用しようとしています。プロジェクトはセルフホスティングです。

これに関する多くの記事がインターネット上にありますが、それらのほとんどは 1 つのユース ケース (つまり、従来のルーティングのみ、または属性ルーティングのみでルート プレフィックスなしなど) のみをカバーしています。

私の場合、すべての Cookie を使用したいと思います。言い換えれば、私のセレクターがしなければならないことは、これらをサポートすることです:

namespace WebProject.Controllers.v1
{
    [RoutePrefix("accounts")]
    public class AccountsController : ApiController
    {
        [Route("")]
        public IHttpActionResult Get()
        {
            var accounts = accountList.ConvertAll(LogicMgr.ConvertModelToView);
            return Ok(accounts);
        }
    }
}

namespace WebProject.Controllers.v2
{
    [RoutePrefix("accounts")]
    public class AccountsController : ApiController
    {
        [Route("")]
        public IHttpActionResult Get()
        {
            var accounts = accountList.ConvertAll(LogicMgr.ConvertModelToView);
            return Ok(accounts);
        }
    }
}

セレクターの主要部分は、リクエストからコントローラー名を抽出することです。ほとんどの記事では、これは特定のキー (「コントローラー」) を持つ辞書を介して行われます。ただし、これは従来のテンプレート ルーティングでのみ機能します。

属性ルーティングを扱う場合は、ルート制約を使用し、デフォルトのコントローラー セレクターを維持することをお勧めします。私にはうまくいきません。

現在、次のようにコントローラー名を抽出します。

static string GetControllerName(IHttpRouteData route)
{
    var controller = route.GetSubRoutes()
        .Select(s => new
        {
            Name = ((HttpActionDescriptor[])s.Route.DataTokens.Single(t => t.Value is HttpActionDescriptor[]).Value)
            .FirstOrDefault().ControllerDescriptor.ControllerName
        }).FirstOrDefault();

    return controller.Name;
}

私には少しハックに思えますが、機能し、魔法の定数を使用しません (検索用の辞書のキーとして「アクション」を使用する場合など)。

ともかく。(リゾルバーを介して) コントローラーのリストを作成し、リクエストからコントローラー名を抽出し、バージョンに基づいて適切な HttpControllerDescriptor を見つけた後、SelectController() メソッドからそれを返す必要があります。

そして、ここで KeyNotFoundException 例外が発生します。検索した後、これについての言及が1つだけ見つかりました(HttpControllerDispatcher の例外

解決策は、着信要求に正しいサブルート データを入力することです。今、私はインターネット上でこれやその他の公式の言及を見つけていません. この投稿のみ。

私が思いついたのは、別のハッキーなコードです:

static void FillSubRoutes(IHttpRouteData route, string version)
{
    var subroutes = route.GetSubRoutes()
        .Where(s =>
            ((HttpActionDescriptor[])s.Route.DataTokens.Single(t => t.Value is HttpActionDescriptor[]).Value)
                .Any(d => d.ControllerDescriptor.ControllerType.Namespace.EndsWith(version, StringComparison.OrdinalIgnoreCase)));
    var values = route.Values.Single(v => v.Value is IHttpRouteData[]);
    route.Values[values.Key] = subroutes.ToArray();
}

私の場合、最初はルートに 4 つのサブルートがあります (コントローラーのバージョンごとに 2 つ)。ここで何が起こるかというと、最後の部分にあるコントローラーの名前空間に特定のバージョンのコントローラー記述子を持つサブルートを検索することです。私の場合、それは常に2つです(「GET」リクエスト用と「POST」リクエスト用で、簡単にするために以前のコントローラーの例では省略しました)。

だから最後に私は私の質問に行きます:

  1. リクエストからコントローラー名を抽出する他の (できればより公式で適切な) 方法はありますか?
  2. サブルートを満たさない場合に発生する KeyNotFoundException 例外を解決する他の (より公式で適切な方法が望ましい) 方法はありますか?
  3. IIS でホストされている場合、これらはすべて機能しますか?
4

0 に答える 0