バージョン管理に名前空間の選択を使用する 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」リクエスト用で、簡単にするために以前のコントローラーの例では省略しました)。
だから最後に私は私の質問に行きます:
- リクエストからコントローラー名を抽出する他の (できればより公式で適切な) 方法はありますか?
- サブルートを満たさない場合に発生する KeyNotFoundException 例外を解決する他の (より公式で適切な方法が望ましい) 方法はありますか?
- IIS でホストされている場合、これらはすべて機能しますか?