Interpretation of ASP. NET 5 MVC6 Series Tutorials (10): Controller and Action
- 2021-07-26 07:29:34
- OfStack
We know that in MVC5 and previous versions, the life cycles of the two frameworks are different. In the new version of MVC6, MVC, Controller/Web, API and Controller have been combined into 1. In this chapter, we mainly explain the definition and use of Controller and Action, and how to query the corresponding Controller and Action according to routes in MVC framework.
Controller & Definition and Use of Action
In the new version of MVC6 framework, one Controller base class is still provided, except that it is still provided here
Url
,
RouteData
,
HttpContext
,
Request
,
Response
In addition, 1 is also provided
IServiceProvider
Type of
Resovler
Property that is the container for dependency injection and is used to get an instance object of the specified type within the scope of the current request.
It abides by the following rules:
Inherit from
Microsoft.AspNet.Mvc.Controller
The class of is definitely a controller, with or without the Controller suffix. Do not inherit
Microsoft.AspNet.Mvc.Controller
To use the custom XXXController of MVC Controller, you must refer to
Microsoft.AspNet.Mvc
The associated assembly. If you don't want the Controller class that meets the above conditions to be Controller, you need to add
RouteData
0
Characteristics. Similarly, if you don't want a method in an Controller to be an Action, you need to add
NonActionAttribute
Characteristics.
There are also several features to note:
特性 | 描述 |
---|---|
ActionNameAttribute | 定义Action的名称(可以和Action方法名不同) |
AcceptVerbsAttribute | 定义支持的Http Method名称,支持单个或多个Method。 |
ActivateAttribute | 依赖注入的标记,可以放在具有set权限的属性或字段上。 |
ResponseCacheAttribute | 针对某个Controller或Action设置客户端缓存。 |
RequireHttpsAttribute | 限制必须是Https请求。 |
RemoteAttribute | 标记为Ajax请求,服务器端不验证form表单的验证。 |
NonControllerAttribute | 标记该类不是Controller。 |
NonActionAttribute | 标记该方法不是Action。 |
Lookup Mechanism of Controller
From the above chapters, we know that MVC6 not only supports normal Controller (inherited from the subclass of Controller base class), but also supports Controller of POCO. In this section, we will study the lookup principle and mechanism of Controller under 1.
First, to determine whether a class is an Controller, you must first determine how many assemblies have such a class defined.
Microsoft.AspNet.Mvc
Namespace
IAssemblyProvider
Interface is to override and find all assemblies that may define Controller. The default implementation of this interface is
DefaultAssemblyProvider
Class, where the necessary condition is that Controller that defines MVC must refer to one or more of the following assemblies, as listed below:
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
That is, if you define a reference
Microsoft.AspNet.Mvc
DLL class library, POCO Controller in it will be considered as Controller of MVC. In other words, if you define POCO Controller classes that do not refer to any one of these assemblies, then these Controller classes will not be considered Controller of MVC.
Lookup of assemblies
At present, there are two ways to customize the lookup mechanism of Controller. The first is inheritance
IAssemblyProvider
Realization
CandidateAssemblies
Method (or overload
DefaultAssemblyProvider
) to define its own logic. The interface is defined as follows:
public interface IAssemblyProvider
{
IEnumerable<Assembly> CandidateAssemblies { get; }
}
Another way, which may be relatively simpler, is to use
IServicesCollection
To define the assembly to find:
services.AddMvc().WithControllersAsServices(new[]
{
typeof(MyController).Assembly,
typeof(ExternalPocoController).Assembly
});
After using the above code, the system will put
DefaultAssemblyProvider
Switch to
FixedSetAssemblyProvider
To realize the above judgment mechanism, that is, to find in a fixed range of assemblies.
Filtering of assemblies
Once the assemblies have been identified, another question arises. How do you determine whether an assembly refers to the assemblies listed in the above MVC prerequisites? The answer is,
Microsoft.Framework.Runtime
In
ILibraryManager
Object of the interface instance
GetReferencingLibraries
Method to find out how many assemblies refer to one of the assemblies in the above list. For example, you can base on the
Microsoft.AspNet.Mvc
Assembly to find out how many assemblies refer to the assembly, as shown in the following example:
var col = this.Resolver.GetRequiredService<ILibraryManager>();
var data = col.GetReferencingLibraries("Microsoft.AspNet.Mvc");
The code for using this function 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);
}
Judgment of Controller
Once you have identified an assembly that meets the requirements, you can iterate through all the types in the assembly and then determine whether the type is Controller. In the new version of Controller judgment, it is 1 to realize this function
IControllerTypeProvider
Interface, which provides a
ControllerTypes
The read-only attribute is used to get all defined Controller, and the interface definition is as follows:
public interface IControllerTypeProvider
{
IEnumerable<TypeInfo> ControllerTypes { get; }
}
DefaultControllerTypeProvider
Is the default implementation of this interface. When querying the qualified Controller, the default implementation class defines 1
IsController
Method is used to determine whether a type is Controller. The specific logic is as follows:
protected internal virtual bool IsController([NotNull] TypeInfo typeInfo,
[NotNull] ISet<Assembly> candidateAssemblies)
{
if (!typeInfo.IsClass) // The type must be 1 Category
{
return false;
}
if (typeInfo.IsAbstract) // This class must not be an 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 1 A Public Class (and not nested), nested classes cannot be used as Controller
{
return false;
}
if (typeInfo.ContainsGenericParameters) // This class cannot be a generic class
{
return false;
}
if (!typeInfo.Name.EndsWith(ControllerTypeName, StringComparison.OrdinalIgnoreCase) &&
!DerivesFromController(typeInfo, candidateAssemblies)) // Class with Controller End, or inherit from Controller Base class, or its parent class is also Controller .
{
return false;
}
if (typeInfo.IsDefined(typeof(NonControllerAttribute))) // This class cannot be set NonControllerAttribute Characteristic
{
return false;
}
return true;
}
You can also do it yourself
IControllerTypeProvider
Interface to define its own Controller decision logic, however, and to fix some assembly types, MVC in the
IServicesCollection
There is also an extension method provided on to restrict 1 Controller specific types, such as the following example:
services.AddMvc().WithControllersAsServices(new[]
{
typeof(MyController),
typeof(ExternalPocoController)
});
After using the above code, the system will put
DefaultControllerTypeProvider
Switch to
FixedSetControllerTypeProvider
To implement the above judgment mechanism, that is, to restrict some specific classes as Controller, and other types as Controller.
Lookup Mechanism of Action
Action is selected by
IActionSelector
The default implementation class for the interface
DefaultActionSelector
To achieve, in the implementation of
SelectAsync
Method, the best matching Action is selected through 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 Action, and that is
IActionModelBuilder
Interface, the default implementation of which is
DefaultActionModelBuilder
Class, implemented as follows:
public IEnumerable<ActionModel> BuildActionModels([NotNull] TypeInfo typeInfo,
[NotNull] MethodInfo methodInfo)
{
if (!IsAction(typeInfo, methodInfo))
{
return Enumerable.Empty<ActionModel>();
}
// .... Omit other codes
}
This implementation method is implemented through an internal
IsAction
Method to determine whether the method is a real Action method, the specific code is as follows:
public interface IAssemblyProvider
{
IEnumerable<Assembly> CandidateAssemblies { get; }
}
0
The above content is about Controller and Action search related important code, detailed principle steps, please refer to
Microsoft.AspNet.Mvc.Core
All source code under the assembly.