Original: Interpretation of ASP. 5 & MVC6 Series: Controller and action
We know that in MVC5 and previous versions, the life cycle of the two frames is not the same, in the new MVC6, the MVC controller/web API Controller has been merged, this chapter we mainly explain the Controller and action definition and use, And in the MVC framework, how to query the corresponding controller and action based on the route.
Definition and use of controller&action
In the new MVC6 framework, a controller base class is still provided, where, in addition to the,,,,, and Url
RouteData
HttpContent
Request
Response
Other, a IServiceProvider
type of Resovler
attribute is provided, which is a container of dependency injection. Used to get an instance object of the specified type within the current request scope.
It complies with the following rules:
- Inherited
Microsoft.AspNet.Mvc.Controller
classes are definitely controllers, regardless of the controller suffix.
- Custom xxxcontroller that do not inherit
Microsoft.AspNet.Mvc.Controller
if you want to be an MVC controller, you must refer to Microsoft.AspNet.Mvc
the associated assembly.
- If you do not want a controller class that satisfies the above conditions as a controller, you need to add attributes to the class
NonControllerAttribute
.
- Similarly, if you do not want a method in a controller to act as an action, you need to add an attribute to the method
NonActionAttribute
.
There are several other features to note:
features |
Description |
Actionnameattribute |
Defines the name of the action (which can be different from the action method name) |
Acceptverbsattribute |
Defines the supported HTTP method names, supporting single or multiple method. |
Activateattribute |
A tag that relies on injection, which can be placed on a property or field with set permissions. |
Responsecacheattribute |
Sets the client cache for a controller or action. |
Requirehttpsattribute |
The limit must be an HTTPS request. |
Remoteattribute |
Marked as an AJAX request, the server side does not validate validation of form forms. |
Noncontrollerattribute |
Flag This class is not a controller. |
Nonactionattribute |
Flag This method is not an action. |
The lookup mechanism of controller
From the above section, we know that MVC6 not only supports the normal controller (inherited from the Controller base class subclass), but also supports POCO controller, this section we will examine the controller's mechanism of finding principle.
First, to determine whether a class is a controller, you must first decide how many assemblies are defined in such a class. The Microsoft.AspNet.Mvc
interface under the namespace IAssemblyProvider
is the override to find all the assemblies that might define the controller, the default implementation of which is the class, DefaultAssemblyProvider
in which the necessary conditions are set, The controller that defines MVC must refer to one or more assemblies in the following assembly as follows:
Microsoft.AspNet.MvcMicrosoft.AspNet.Mvc.CoreMicrosoft.AspNet.Mvc.ModelBindingMicrosoft.AspNet.Mvc.RazorMicrosoft.AspNet.Mvc.Razor.HostMicrosoft.AspNet.Mvc.TagHelpersMicrosoft.AspNet.Mvc.XmlMicrosoft.AspNet.PageExecutionInstrumentation.Interfaces
That is, if you define a referenced Microsoft.AspNet.Mvc
DLL class library, the Poco controller inside it will be considered an MVC controller. In other words, if you define a Poco controller class that does not reference any of the assemblies in the above assembly, then these controller classes are not considered to be MVC controllers.
Lookup of Assemblies
There are two ways to customize the lookup mechanism of a controller, the first of which is to inherit the IAssemblyProvider
implementation CandidateAssemblies
method (or overload DefaultAssemblyProvider
) to define your own logic. The interface is defined as follows:
public interface IAssemblyProvider{ IEnumerable<Assembly> CandidateAssemblies { get; }}
Another way, which may be relatively simple, is to use the IServicesCollection
extension method defined above to define the assembly to find:
services.AddMvc().WithControllersAsServices(new[]{ typeof(MyController).Assembly, typeof(ExternalPocoController).Assembly});
Using the above code, the system will DefaultAssemblyProvider
switch FixedSetAssemblyProvider
to achieve the above judgment mechanism, namely: in the fixed scope of the assembly to find.
Filtering for assemblies
Once the assembly has been identified, the other question is, how do you tell if an assembly refers to the assemblies listed in the MVC prerequisites above? The answer is that Microsoft.Framework.Runtime
in the method of the ILibraryManager
interface instance GetReferencingLibraries
, you can find out how many assemblies refer to one of the assemblies in the preceding list. For example, depending on the assembly, you can Microsoft.AspNet.Mvc
find out how many assemblies reference the assembly, as shown in the following example:
var col = this.Resolver.GetRequiredService<ILibraryManager>();var data = col.GetReferencingLibraries("Microsoft.AspNet.Mvc");
The use code for this feature in the Defaultassemblyprovider default implementation class is as follows:
protected virtual IEnumerable<ILibraryInformation> GetCandidateLibraries(){ if (ReferenceAssemblies == null) { return Enumerable.Empty<ILibraryInformation>(); } // GetReferencingLibraries returns the transitive closure of referencing assemblies // for a given assembly. return ReferenceAssemblies.SelectMany(_libraryManager.GetReferencingLibraries) .Distinct() .Where(IsCandidateLibrary);}
Controller's judgment
Once you have determined which assembly meets the requirements, you can iterate through all the types in the assembly and then determine if the type is a controller. In the new version of Controller judgment, the implementation of this function is an IControllerTypeProvider
interface, which provides a ControllerTypes
read-only property to obtain all the defined controller, the interface is defined as follows:
public interface IControllerTypeProvider{ IEnumerable<TypeInfo> ControllerTypes { get; }}
The
defaultcontrollertypeprovider
is the default implementation of this interface, and when you query a qualified controller, the default implementation class defines a Iscontroller
method, which is used to determine whether a type is a controller, with the following logic:
protected internal virtual bool Iscontroller ([Notnull] TypeInfo typeinfo, [not Null] iset<assembly> candidateassemblies) {if (!typeinfo.isclass)//The type must be a class {return false; } if (typeinfo.isabstract)//The class must not be abstract class {return false; }//We only consider public top-level classes as controllers. IsPublic returns FALSE for nested//classes, regardless of visibility modifiers if (!typeinfo.ispublic)//The class must be a P Ublic class (and not nested), the nested class cannot be a controller {return false; } if (typeinfo.containsgenericparameters)//The class cannot be a generic class {return false; } if (!typeinfo.name.endswith (Controllertypename, stringcomparison.ordinalignorecase) &&! Derivesfromcontroller (TypeInfo, candidateassemblies))//The class ends with a controller, or inherits from the Controller base class, or its parent class is also a controller. {return false; } if (Typeinfo.isdefined (typeof (Noncontrollerattribute)))//The class cannot set the Noncontrollerattribute attribute {REturn false; } return true;
You can also implement your own IControllerTypeProvider
interface to define your own controller judgment logic, but with fixed certain assembly types, MVC IServicesCollection
also provides an extension method for restricting some controller-specific types, as shown in the following example:
services.AddMvc().WithControllersAsServices(new[] { typeof(MyController), typeof(ExternalPocoController) });
Using the above code, the system will DefaultControllerTypeProvider
switch FixedSetControllerTypeProvider
to achieve the above-mentioned judgment mechanism, that is: restricting certain classes as controller, other types can not be used as controller.
Find mechanism for action
The action is chosen by the IActionSelector
default implementation class of the interface DefaultActionSelector
, and in the implemented SelectAsync
method, the best matching action is selected through the context and routing data, with the following schematic code:
public Task<ActionDescriptor> SelectAsync([NotNull] RouteContext context){ // ...}
There is another place to determine whether a method is an action, that is the IActionModelBuilder
interface, the default implementation of the interface is a DefaultActionModelBuilder
class, the implementation method is as follows:
public IEnumerable<ActionModel> BuildActionModels([NotNull] TypeInfo typeInfo, [NotNull] MethodInfo methodInfo){ if (!IsAction(typeInfo, methodInfo)) { return Enumerable.Empty<ActionModel>(); } // ....省略其它代码}
The implementation method, through an internal IsAction
method to determine whether the method is a real action method, the specific code is as follows:
Protected virtual bool Isaction ([Notnull] TypeInfo typeinfo, [notnull] MethodInfo MethodInfo) {//the SpecialName bit I s set to flag members that is treated in a special-some compilers//(such as property accessors and operator O Verloading methods). if (methodinfo.isspecialname)//cannot be a special name (such as an overloaded operator or property accessor) {return false; } if (Methodinfo.isdefined (typeof (Nonactionattribute)))//cannot declare Nonactionattribute attribute {return false; }//Overriden methods from object class, e.g. Equals (object), GetHashCode (), etc, is not valid. if (Methodinfo.getbasedefinition (). DeclaringType = = typeof (object)//cannot be an overloaded method, such as Equals and GetHashCode {return false; }//Dispose method implemented from IDisposable are not valid if (Isidisposablemethod (MethodInfo, TypeInfo))//cannot be Dispose method {return false; } if (methodinfo.isstatic)//cannot be a static method {return false; } if (Methodinfo.isabstract)//cannot be an abstract method {return FALse } if (Methodinfo.isconstructor)//cannot be a constructor {return false; } if (Methodinfo.isgenericmethod)//cannot be a generic method {return false; } return methodinfo.ispublic; Must be public method}
The above is about controller and action lookup related important code, detailed principle steps, please refer to Microsoft.AspNet.Mvc.Core
the assembly of all source code.
Synchronization and recommendations
This article has been synchronized to the Catalog index: Interpreting ASP. & MVC6 Series
Interpreting ASP 5 & MVC6 Series: Controller and action