ControllerFactory で使用可能なすべてのコントローラーを取得することは可能ですか?
私がやりたいことは、アプリケーション内のすべてのコントローラー タイプのリストを取得することですが、一貫した方法で取得します。
私が取得するすべてのコントローラーが、デフォルトのリクエスト解決が使用しているものと同じになるようにします。
(実際のタスクは、特定の属性を持つすべてのアクション メソッドを見つけることです)。
ControllerFactory で使用可能なすべてのコントローラーを取得することは可能ですか?
私がやりたいことは、アプリケーション内のすべてのコントローラー タイプのリストを取得することですが、一貫した方法で取得します。
私が取得するすべてのコントローラーが、デフォルトのリクエスト解決が使用しているものと同じになるようにします。
(実際のタスクは、特定の属性を持つすべてのアクション メソッドを見つけることです)。
リフレクションを使用して、アセンブリ内のすべてのクラスを列挙し、コントローラー クラスから継承するクラスのみをフィルター処理できます。
最も参考になるのはasp.net mvc source codeです。ControllerTypeCacheおよびActionMethodSelectorクラスの実装を見てください。ControllerTypeCache は、使用可能なすべてのコントローラー クラスを取得する方法を示しています。
internal static bool IsControllerType(Type t) {
return
t != null &&
t.IsPublic &&
t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
!t.IsAbstract &&
typeof(IController).IsAssignableFrom(t);
}
public void EnsureInitialized(IBuildManager buildManager) {
if (_cache == null) {
lock (_lockObj) {
if (_cache == null) {
List<Type> controllerTypes = GetAllControllerTypes(buildManager);
var groupedByName = controllerTypes.GroupBy(
t => t.Name.Substring(0, t.Name.Length - "Controller".Length),
StringComparer.OrdinalIgnoreCase);
_cache = groupedByName.ToDictionary(
g => g.Key,
g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
}
}
}
}
ActionMethodSelector は、メソッドに必要な属性があるかどうかを確認する方法を示しています。
private static List<MethodInfo> RunSelectionFilters(ControllerContext controllerContext, List<MethodInfo> methodInfos) {
// remove all methods which are opting out of this request
// to opt out, at least one attribute defined on the method must return false
List<MethodInfo> matchesWithSelectionAttributes = new List<MethodInfo>();
List<MethodInfo> matchesWithoutSelectionAttributes = new List<MethodInfo>();
foreach (MethodInfo methodInfo in methodInfos) {
ActionMethodSelectorAttribute[] attrs = (ActionMethodSelectorAttribute[])methodInfo.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), true /* inherit */);
if (attrs.Length == 0) {
matchesWithoutSelectionAttributes.Add(methodInfo);
}
else if (attrs.All(attr => attr.IsValidForRequest(controllerContext, methodInfo))) {
matchesWithSelectionAttributes.Add(methodInfo);
}
}
// if a matching action method had a selection attribute, consider it more specific than a matching action method
// without a selection attribute
return (matchesWithSelectionAttributes.Count > 0) ? matchesWithSelectionAttributes : matchesWithoutSelectionAttributes;
}
この質問には、IControllerFactory の実装など、さまざまなことに依存するため、簡単に答えることはできないと思います。
たとえば、完全にカスタム ビルドされた IControllerFactory 実装がある場合、あらゆる種類のメカニズムを使用して Controller インスタンスを作成する可能性があるため、すべてが当てはまります。
ただし、DefaultControllerFactory は、RouteCollection (global.asax で構成) で定義されたすべてのアセンブリで適切なコントローラーの型を管理します。
この場合、RouteCollection に関連付けられているすべてのアセンブリをループして、それぞれでコントローラーを探すことができます。
特定のアセンブリでコントローラーを見つけるのは比較的簡単です。
var controllerTypes = from t in asm.GetExportedTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
ここasm
で、Assembly インスタンスです。