APIバージョン管理を追加しようとしていますが、バージョンごとに異なる名前空間にコントローラーを作成する予定です。私のプロジェクト構造は次のようになります(注:バージョンごとに個別の領域はありません)
Controllers
|
|---Version0
| |
| |----- ProjectController.cs
| |----- HomeController.cs
|
|---Version1
|
|----- ProjectController.cs
|----- HomeController.cs
ルートにRoutingAttributeを使用しています。したがって、Version0のProjectControllerには、次のようなルートを持つ関数があります。
namespace MyProject.Controllers.Version0
{
class ProjectController : BaseController
{
...
[Route(api/users/project/getProjects/{projectId})]
public async GetProjects(string projectId)
{
...
}
}
}
バージョン1のProjectControllerには、次のようなルートを持つ関数があります。
namespace MyProject.Controllers.Version1
{
class ProjectController : BaseController
{
...
[Route(api/v1/users/project/getProjects/{projectId})]
public async GetProjects(string projectId)
{
...
}
}
}
しかし、サービスを利用しようとすると404-NotFoundが表示されます。
コントローラの名前を一意の名前(Project1ControllerおよびProject2Controller)に変更すると、ルーティングが機能します。ただし、簡単にするために名前の変更は避けようとしています。
このリンクをたどって問題を解決しましたが、役に立ちませんでした。エリアを作成しましたが、それでも成功しませんでした。 global.aspxファイルにルーティングロジックを追加しても役に立ちません。名前空間も機能しません。 http://haacked.com/archive/2010/01/12/ambiguous-controller-names.aspx/
上記のリンクはエリアの作成を提案していますが、属性ルーティングはリンクに従ってエリアをサポートしていません: http://www.asp.net/web-api/overview/web-api-routing-and-actions/ attribute-routing-in-web-api-2
別の解決策はありますか? RoutingAttributesのバグ?
ありがとうございました!
まず、WebAPIルーティングとMVCルーティングはまったく同じようには機能しません。
最初のリンクは、エリアを含むMVCルーティングを指します。エリアはWebAPIで公式にサポートされていませんが、類似したものを作成することはできます。ただし、そのようなことを行おうとしても、Web APIがコントローラーを検索する方法ではコントローラーの名前空間が考慮されないため、同じエラーが発生します。
したがって、箱から出して、それは決して機能しません。
ただし、ほとんどのWeb APIの動作は変更でき、これも例外ではありません。
Web APIは、コントローラーセレクターを使用して目的のコントローラーを取得します。上で説明した動作は、Web APIに付属する DefaultHttpControllerSelector の動作ですが、独自のセレクターを実装してデフォルトのセレクターを置き換え、新しい動作をサポートすることができます。
「カスタムWebAPIコントローラーセレクター」をグーグルで検索すると、多くのサンプルが見つかりますが、これがまさにあなたの問題にとって最も興味深いと思います。
この実装も興味深いものです。
ご覧のとおり、基本的に次のことを行う必要があります。
IHttpControllerSelector
を実装します。これは、名前空間を考慮してコントローラーを検索し、名前空間のルート変数を使用して、それらの1つを選択します。私はこれがしばらくの間答えられて、元のポスターによってすでに受け入れられていることを知っています。しかし、あなたが私のようで、属性ルーティングの使用を必要とし、提案された答えを試した場合、それは完全には機能しないことがわかります。
これを試したところ、MapHttpAttributeRoutes
クラスの拡張メソッドHttpConfiguration
を呼び出すことによって生成されるはずのルーティング情報が実際には欠落していることがわかりました。
config.MapHttpAttributeRoutes();
これは、置換SelectController
実装のメソッドIHttpControllerSelector
が実際に呼び出されることはなく、リクエストがhttp404応答を生成する理由です。
この問題は、System.Web.Http
名前空間の下のSystem.Web.Http.Dispatcher
アセンブリの内部クラスであるHttpControllerTypeCache
と呼ばれる内部クラスが原因で発生します。問題のコードは次のとおりです。
private Dictionary<string, ILookup<string, Type>> InitializeCache()
{
return this._configuration.Services.GetHttpControllerTypeResolver().GetControllerTypes(this._configuration.Services.GetAssembliesResolver()).GroupBy<Type, string>((Func<Type, string>) (t => t.Name.Substring(0, t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length)), (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string, Type>, string, ILookup<string, Type>>((Func<IGrouping<string, Type>, string>) (g => g.Key), (Func<IGrouping<string, Type>, ILookup<string, Type>>) (g => g.ToLookup<Type, string>((Func<Type, string>) (t => t.Namespace ?? string.Empty), (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase)), (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
}
このコードでは、名前空間なしでタイプ名でグループ化されていることがわかります。 DefaultHttpControllerSelector
クラスは、コントローラーごとにHttpControllerDescriptor
の内部キャッシュを構築するときにこの機能を使用します。 MapHttpAttributeRoutes
メソッドを使用する場合、System.Web.Http.Routing
名前空間の一部であるAttributeRoutingMapper
と呼ばれる別の内部クラスを使用します。このクラスは、ルートを構成するためにGetControllerMapping
のメソッドIHttpControllerSelector
を使用します。
したがって、カスタムIHttpControllerSelector
を作成する場合は、それを機能させるためにGetControllerMapping
メソッドをオーバーロードする必要があります。私がこれに言及する理由は、私がインターネット上で見た実装のどれもこれを行わないからです。