ASPを解読する.NET 5&MVC 6シリーズチュートリアル(10):ControllerとAction
9246 ワード
MVC 5と以前のバージョンでは、2つのフレームワークのライフサイクルが異なることを知っています.新版MVC 6では、MVC Controller/Web API Controllerが統合されています.本章では、ControllerとActionの定義と使用、およびMVCフレームワークで、ルーティングに基づいて対応するControllerとActionをクエリーする方法について説明します.
Controller&Actionの定義と使用
新版MVC 6フレームワークでは、依然として1つのControllerベースクラスが提供されている.ここでは、依然として
以下のルールを遵守します.
また、以下の特性に注意する必要があります.
とくせい
説明
ActionNameAttribute
アクションの名前を定義します(アクションメソッド名とは異なります).
AcceptVerbsAttribute
サポートされるHttp Methodの名前を定義し、単一または複数のMethodをサポートします.
ActivateAttribute
注入されたタグに依存して、set権限を持つ属性またはフィールドに置くことができます.
ResponseCacheAttribute
コントローラまたはアクションに対してクライアントキャッシュを設定します.
RequireHttpsAttribute
制限はHttpsリクエストでなければなりません.
RemoteAttribute
Ajaxリクエストとしてマークされ、サーバ側はformフォームの検証を検証しません.
NonControllerAttribute
クラスがControllerではないことをマークします.
NonActionAttribute
このメソッドをマークするのはアクションではありません.
コントローラの検索メカニズム
上記の章から,MVC 6は正常なController(Controllerベースクラスに継承されたサブクラス)だけでなく,POCOのControllerもサポートしていることが分かるが,本節ではControllerの検索原理メカニズムについて検討する.
まず,クラスがControllerであるかどうかを判断するには,まず,このようなクラスがどのくらいのプログラムセットで定義されているかを決定しなければならない.
つまり、
プログラムセットの検索
現在、Controllerの検索メカニズムをカスタマイズできる方法は2つあります.1つ目は、継承
もう1つの方法は、比較的簡単かもしれません.それは、
上記コードを使用すると、システムは
プログラムセットのフィルタ
プログラムセットが確定すると、もう一つの問題が来ますが、一つのプログラムセットが上記MVCの必要条件に記載されているプログラムセットを引用しているかどうかをどのように判断しますか?答えは、
この機能は、DefaultAssemblyProviderのデフォルト実装クラスで次のように使用されます.
コントローラの判断
必要条件を満たすプログラムセットが決定されると、そのプログラムセット内のすべてのタイプを巡回し、そのタイプがControllerであるか否かを判断することができる.新版のController判定では、この機能を実現したのは
自分で実現することもできます
上記コードを使用すると、システムは
Actionの検索メカニズム
Actionの選択は、
もう一つ、アクションかどうかを判断する方法があります.それは
この実装方法は、1つの内部の
以上、ControllerとAction検索に関する重要なコードについて詳しくは、
Controller&Actionの定義と使用
新版MVC 6フレームワークでは、依然として1つのControllerベースクラスが提供されている.ここでは、依然として
Url
RouteData
HttpContext
Request
・Response
・の他に、現在のリクエストドメイン内で指定されたタイプのインスタンスオブジェクトを取得するために、注入に依存するコンテナに属するIServiceProvider
タイプのResovler
属性が提供されている.以下のルールを遵守します.
Microsoft.AspNet.Mvc.Controller
に継承されているクラスは、Controller接尾辞の有無にかかわらずコントローラであることは間違いありません.引き継がないMicrosoft.AspNet.Mvc.Controller
のカスタムXXXXControllerをMVC Controllerとするには、Microsoft.AspNet.Mvc
関連するプログラムセットを参照する必要があります.上記の条件を満たすControllerクラスをControllerとしたくない場合は、そのクラスにNonControllerAttribute
特性を加える必要があります.同様に,あるControllerのメソッドをActionとしたくない場合は,そのメソッドにNonActionAttribute
特性を加える必要がある.また、以下の特性に注意する必要があります.
とくせい
説明
ActionNameAttribute
アクションの名前を定義します(アクションメソッド名とは異なります).
AcceptVerbsAttribute
サポートされるHttp Methodの名前を定義し、単一または複数のMethodをサポートします.
ActivateAttribute
注入されたタグに依存して、set権限を持つ属性またはフィールドに置くことができます.
ResponseCacheAttribute
コントローラまたはアクションに対してクライアントキャッシュを設定します.
RequireHttpsAttribute
制限はHttpsリクエストでなければなりません.
RemoteAttribute
Ajaxリクエストとしてマークされ、サーバ側はformフォームの検証を検証しません.
NonControllerAttribute
クラスがControllerではないことをマークします.
NonActionAttribute
このメソッドをマークするのはアクションではありません.
コントローラの検索メカニズム
上記の章から,MVC 6は正常なController(Controllerベースクラスに継承されたサブクラス)だけでなく,POCOのControllerもサポートしていることが分かるが,本節ではControllerの検索原理メカニズムについて検討する.
まず,クラスがControllerであるかどうかを判断するには,まず,このようなクラスがどのくらいのプログラムセットで定義されているかを決定しなければならない.
Microsoft.AspNet.Mvc
ネーミングスペース下のIAssemblyProvider
インターフェースは、MVCを定義したコントローラをすべて上書きして検索するプログラムセットである.このインターフェースのデフォルト実装はDefaultAssemblyProvider
クラスである.このクラスでは、MVCを定義したコントローラは、次のようなプログラムセットの1つ以上のプログラムセットを参照しなければならない必要がある.リストは以下の通りである.
Microsoft.AspNet.Mvc
Microsoft.AspNet.Mvc.Core
Microsoft.AspNet.Mvc.ModelBinding
Microsoft.AspNet.Mvc.Razor
Microsoft.AspNet.Mvc.Razor.Host
Microsoft.AspNet.Mvc.TagHelpers
Microsoft.AspNet.Mvc.Xml
Microsoft.AspNet.PageExecutionInstrumentation.Interfaces
つまり、
Microsoft.AspNet.Mvc
を引用したDLLクラスライブラリを定義すると、その中のPOCO ControlはMVCのControlとみなされます.言い換えれば、定義したPOCO Controlクラスが上記のプログラムセットのいずれかのプログラムセットを参照していない場合、これらのControlクラスはMVCのControlとはみなされません.プログラムセットの検索
現在、Controllerの検索メカニズムをカスタマイズできる方法は2つあります.1つ目は、継承
IAssemblyProvider
実装CandidateAssemblies
メソッド(またはリロードDefaultAssemblyProvider
)で、独自のロジックを定義します.インタフェースの定義は次のとおりです.
public interface IAssemblyProvider
{
IEnumerable CandidateAssemblies { get; }
}
もう1つの方法は、比較的簡単かもしれません.それは、
IServicesCollection
で定義された拡張メソッドを使用して、検索するプログラムセットを定義することです.
services.AddMvc().WithControllersAsServices(new[]
{
typeof(MyController).Assembly,
typeof(ExternalPocoController).Assembly
});
上記コードを使用すると、システムは
DefaultAssemblyProvider
をFixedSetAssemblyProvider
に切り替え、一定範囲内のプログラムセットで検索するという判断メカニズムを実現する.プログラムセットのフィルタ
プログラムセットが確定すると、もう一つの問題が来ますが、一つのプログラムセットが上記MVCの必要条件に記載されているプログラムセットを引用しているかどうかをどのように判断しますか?答えは、
Microsoft.Framework.Runtime
のILibraryManager
インタフェースインスタンスのGetReferencingLibraries
メソッドで、上記リストのいずれかのプログラムセットを参照しているプログラムがどれだけあるかを検索できます.たとえば、Microsoft.AspNet.Mvc
プログラムセットに基づいて、このプログラムセットを参照しているプログラムセットの数を検索できます.例は次のとおりです.
var col = this.Resolver.GetRequiredService();
var data = col.GetReferencingLibraries("Microsoft.AspNet.Mvc");
この機能は、DefaultAssemblyProviderのデフォルト実装クラスで次のように使用されます.
protected virtual IEnumerable GetCandidateLibraries()
{
if (ReferenceAssemblies == null)
{
return Enumerable.Empty();
}
// GetReferencingLibraries returns the transitive closure of referencing assemblies
// for a given assembly.
return ReferenceAssemblies.SelectMany(_libraryManager.GetReferencingLibraries)
.Distinct()
.Where(IsCandidateLibrary);
}
コントローラの判断
必要条件を満たすプログラムセットが決定されると、そのプログラムセット内のすべてのタイプを巡回し、そのタイプがControllerであるか否かを判断することができる.新版のController判定では、この機能を実現したのは
IControllerTypeProvider
インタフェースであり、このインタフェースはControllerTypes
すべての定義のControllerを取得するための読み取り専用属性を提供し、インタフェース定義は以下の通りである.
public interface IControllerTypeProvider
{
IEnumerable ControllerTypes { get; }
}
DefaultControllerTypeProvider
このインタフェースのデフォルト実装であり、条件に合致するControllerを問い合わせる際に、このデフォルト実装クラスは、1つのタイプがControllerであるか否かを判断するための方法を定義するIsController
方法であり、具体的なロジックは以下の通りである.
protected internal virtual bool IsController([NotNull] TypeInfo typeInfo,
[NotNull] ISet candidateAssemblies)
{
if (!typeInfo.IsClass) //
{
return false;
}
if (typeInfo.IsAbstract) //
{
return false;
}
// We only consider public top-level classes as controllers. IsPublic returns false for nested
// classes, regardless of visibility modifiers
if (!typeInfo.IsPublic) // Public ( ), Controller
{
return false;
}
if (typeInfo.ContainsGenericParameters) //
{
return false;
}
if (!typeInfo.Name.EndsWith(ControllerTypeName, StringComparison.OrdinalIgnoreCase) &&
!DerivesFromController(typeInfo, candidateAssemblies)) // Controller , Controller , Controller。
{
return false;
}
if (typeInfo.IsDefined(typeof(NonControllerAttribute))) // NonControllerAttribute
{
return false;
}
return true;
}
自分で実現することもできます
IControllerTypeProvider
インタフェースは自分のController判断ロジックを定義しますが、一部のプログラムセットタイプを固定することと、MVCはIServicesCollection
いくつかのControllerの特定のタイプを制限するための拡張方法を提供しています.例は以下の通りです.
services.AddMvc().WithControllersAsServices(new[]
{
typeof(MyController),
typeof(ExternalPocoController)
});
上記コードを使用すると、システムは
DefaultControllerTypeProvider
をFixedSetControllerTypeProvider
に切り替え、特定のクラスをコントローラとして制限し、他のタイプをコントローラとして使用できないという判断メカニズムを実現する.Actionの検索メカニズム
Actionの選択は、
IActionSelector
インタフェースのデフォルト実装クラスDefaultActionSelector
によって実現され、実装SelectAsync
メソッドでは、コンテキストとルーティングデータによって最も一致するActionが選択され、概略コードは以下の通りである.
public Task SelectAsync([NotNull] RouteContext context)
{
// ...
}
もう一つ、アクションかどうかを判断する方法があります.それは
IActionModelBuilder
インタフェースです.このインタフェースのデフォルトはDefaultActionModelBuilder
クラスで、実現方法は以下の通りです.
public IEnumerable BuildActionModels([NotNull] TypeInfo typeInfo,
[NotNull] MethodInfo methodInfo)
{
if (!IsAction(typeInfo, methodInfo))
{
return Enumerable.Empty();
}
// ....
}
この実装方法は、1つの内部の
IsAction
方法によって、その方法が真のAction方法であるか否かを判断し、具体的なコードは以下の通りである.
protected virtual bool IsAction([NotNull] TypeInfo typeInfo, [NotNull] MethodInfo methodInfo)
{
// The SpecialName bit is set to flag members that are treated in a special way by some compilers
// (such as property accessors and operator overloading methods).
if (methodInfo.IsSpecialName) // ( )
{
return false;
}
if (methodInfo.IsDefined(typeof(NonActionAttribute))) // NonActionAttribute
{
return false;
}
// Overriden methods from Object class, e.g. Equals(Object), GetHashCode(), etc., are not valid.
if (methodInfo.GetBaseDefinition().DeclaringType == typeof(object)) // , Equals GetHashCode
{
return false;
}
// Dispose method implemented from IDisposable is not valid
if (IsIDisposableMethod(methodInfo, typeInfo)) // Dispose
{
return false;
}
if (methodInfo.IsStatic) //
{
return false;
}
if (methodInfo.IsAbstract) //
{
return false;
}
if (methodInfo.IsConstructor) //
{
return false;
}
if (methodInfo.IsGenericMethod) //
{
return false;
}
return
methodInfo.IsPublic; // Public
}
以上、ControllerとAction検索に関する重要なコードについて詳しくは、
Microsoft.AspNet.Mvc.Core
プログラムセットのすべてのソースコードを参照してください.