In addition to the execution of the action method by taking advantage of Actiondescriptor and the previous model binding and validation, Actioninvoker has an important task in the execution of the action. That is the execution of the related filter. The filter for ASP. NET MVC is a design based on AOP (aspect-oriented programming), we implement some non-business logic in the corresponding filter, and then apply it to the corresponding action method in a crosscutting (crosscutting) way. These filters are executed automatically before and after the action method executes. ASP. NET MVC provides four types of filters (Authorizationfilter, Actionfilter, Resultfilter, and Exceptionfilter). They correspond to the corresponding filter interfaces (Iauthorizationfilter, Iactionfilter, Iresultfilter, and Iexceptionfilter). [This article has been synced to ' how ASP. NET MVC Works ']
Directory
First, Filter
Second, Filterprovider
Third, FilterAttribute and Filterattributefilterprovider
Iv. Controller and Controllerinstancefilterprovider
Wu, Globalfiltercollection
Vi. Example Demo: Verifying the supply mechanism and execution order of the filter
First, Filter
Although the four types of filters provided by ASP. NET. NET MVC have their own interfaces implemented, all filters are represented by a filter type that has the following definition for the provider system. The core of filter is the instance property, because it represents the object that actually implements the filtering functionality, which implements one or more interfaces based on the four filter types mentioned above.
public class filter{Public const INT defaultorder =-1; Public Filter (object instance, filterscope scope, int? order); Public object Instance {get; protected set;} public int Order {get; protected set;} Public Filterscope Scope {get; protected set;}} public enum filterscope{ Action = $, Controller = 0, first = +, Global = 10, Last = 100}
Note: Because System.Web.Mvc.Filter and the types that implement Iauthorizationfilter, Iactionfilter, Iresultfilter, and iexceptionfilter can be called "filters", In order not to cause confusion, we use the English "filter" and the Chinese "filters" to represent each of them, without a clear explanation.
The order and scope properties of the filter ultimately determine the sequence in which the filters are executed. The lower the value of the Order property, the higher the priority of the execution, and the default value of the property is-1 (corresponds to the constant Defaultorder defined in filter). If two filter has the same order attribute value, then the Scope property ultimately determines which of the precedence is performed. The Scope property type of filter is an enumeration of type Filterscope. The enumeration represents the scope where the filter is applied, and the action and controller represent the action method and the Controller class level; First and last mean that you want to be executed as a filter ; Global represents a global filter.
With the code snippet above, we can see that the 5 enumeration options for Filterscope are set to a value that determines the order in which the filter is executed, with a smaller enumeration value being prioritized. From the definition of filterscope, it can be concluded that for multiple filter with the same order attribute value, the filter applied on the controller has a higher execution priority than the filter applied on the action method, A global filter has a higher execution priority than action-based filter.
Second, Filterprovider
The provision mechanism for filter is similar to the one we introduced earlier based on Modelbinder and Modelvalidator, all provided by corresponding provider. The Filterprovider that provides the filter implements the interface Ifilterprovider, as shown in the following code fragment. This interface defines a unique method Getfilters gets a collection of filter objects based on the specified controller context and the Actiondescriptor object that describes the target action.
public interface ifilterprovider{ ienumerable<filter> getfilters (ControllerContext controllercontext, Actiondescriptor actiondescriptor);}
We can register with the static type Filterproviders or get the filterprovider used by the current application. As shown in the following code snippet, Filterproviders has a read-only property of type filterprovidercollection providers, which represents a list of filterprovider that are used throughout the Web application. Filterprovidercollection is a collection of element types Ifilterprovider, which are used by getfilters methods or as a filter object provided by all Filterprovider objects in the collection.
public static class filterproviders{public static filterprovidercollection Providers {get;}} public class filterprovidercollection:collection<ifilterprovider>{ //Other members public ienumerable< Filter> getfilters (ControllerContext controllercontext, Actiondescriptor actiondescriptor); }
ASP. NET MVC provides three native Filterprovider, namely Filterattributefilterprovider, Controllerinstancefilterprovider and Globalfiltercollection, we're going to introduce them separately.
Third, FilterAttribute and Filterattributefilterprovider
We typically apply a filter definition as an attribute to a controller type or action method declaratively, and the abstract type FilterAttribute is the base class for all filters. As shown in the following code snippet, the FilterAttribute attribute implements the Imvcfilter interface, which defines the order and AllowMultiple two read-only properties. Each is used to control the order in which the filters are executed, as well as multiple filters that can be applied to the same target element (class or method) at the same time.
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Class, Inherited=true, Allowmultiple=false)]public abstract Class Filterattribute:attribute, imvcfilter{ protected FilterAttribute (); public bool AllowMultiple {get;} public int Order {get; set;}} public interface imvcfilter{ bool AllowMultiple {get;} int Order {get;}}
From the definition of AttributeUsageAttribute applied on FilterAttribute, it can be seen that this attribute can be applied to types and methods, which means that filters can generally be applied to the controller type and the action method. The read-only property AllowMultiple actually returns a property with the same name as AttributeUsageAttribute, which we can see by default that the property value is false.
Both the Controllerdescriptor and actiondescriptor that describe the Controller and action implement the ICustomAttributeProvider interface. We can use them directly to get all the features that the application has on the corresponding controller type or on the action method including FilterAttribute. In fact, these two description types provide a separate method getfilterattributes specifically for getting a list of filterattribute attributes. As shown in the following code snippet, the method has a Boolean type of parameter UseCache, which indicates whether the parsed FilterAttribute attribute needs to be cached to mitigate the performance impact of frequent reflection operations.
Public abstract class Controllerdescriptor:icustomattributeprovider, iuniquelyidentifiable{ //other Members public Virtual ienumerable<filterattribute> getfilterattributes (bool usecache); Public abstract class Actiondescriptor:icustomattributeprovider, iuniquelyidentifiable{ //other Members public Virtual ienumerable<filterattribute> getfilterattributes (bool usecache); }
The
Filter for the FilterAttribute attribute is provided through the Filterattributefilterprovider object. Filterattributefilterprovider directly invokes the Getfilterattributes method of the current Controllerdescriptor and actiondescriptor to get all applications in the controller type and current Actio The FilterAttribute attribute of the N method, which is used to create the corresponding filter object. The parameter cacheattributeinstances of the Filterattributefilterprovider constructor indicates whether the cache for FilterAttribute is enabled. It will be used as a parameter to invoke the Getfilterattributes method. By default (Filterattributefilterprovider created by calling the default parameterless constructor), the cache for FilterAttribute is used.
public class filterattributefilterprovider:ifilterprovider{public Filterattributefilterprovider (); Public Filterattributefilterprovider (bool cacheattributeinstances); Protected virtual ienumerable<filterattribute> getactionattributes (ControllerContext controllercontext, Actiondescriptor actiondescriptor); Protected virtual ienumerable<filterattribute> getcontrollerattributes (ControllerContext controllercontext, Actiondescriptor actiondescriptor); Public virtual ienumerable<filter> getfilters (ControllerContext controllercontext, Actiondescriptor Actiondescriptor);}
For the filter obtained by calling Getfilters, the corresponding FilterAttribute attribute is used as its instance property. The Order property is derived from the same name property of FilterAttribute. The scope property, however, depends on whether the FilterAttribute attribute is applied on the controller type (scope property value is controller) or the current action method (the scope property value is action).
Iv. Controller and Controllerinstancefilterprovider
Referring to the filter for ASP. NET MVC, most of them only think of the FilterAttribute feature, in fact the controller itself (inherited from the abstract class controller) is a filter. As shown in the following code snippet, the abstract class controller implements the four interfaces for Iactionfilter, Iauthorizationfilter, Iexceptionfilter, and iresultfilter that correspond to different filter types.
Public abstract class Controller:controllerbase, iactionfilter, iauthorizationfilter, Iexceptionfilter, iresultfilter, ... { //omit member}
The Filterprovider type for this unique filter for the Controller object is a controllerinstancefilterprovider with the following definition. In the implemented Getfilters method, it obtains the corresponding controller object based on the specified controller context and creates a filter (the Controller object as the instance property value of the Filter object). The filter scope is not a controller, but first, and the value of order is -2147483648 (Int32.minvalue), no doubt that such a filter must be executed.
public class controllerinstancefilterprovider:ifilterprovider{Public ienumerable<filter> getfilters ( ControllerContext ControllerContext, Actiondescriptor actiondescriptor); }
Wu, Globalfiltercollection
Filters defined in the form of filterattribute need to be explicitly labeled to the target controller type or action method, while in some cases a global filter is required. The so-called global filter, which does not need to be explicitly matched with a controller or action, is used by default to all action executions. The filterprovider corresponding to the type used to provide this global filter is a globalfiltercollection with the following definition.
public sealed class Globalfiltercollection:ienumerable<filter>, IEnumerable, ifilterprovider{public Globalfiltercollection (); public void Add (object filter); public void Add (object filter, int order); private void Addinternal (object filter, int? order); public void Clear (); public bool Contains (object filter); Public ienumerator<filter> GetEnumerator (); public void Remove (object filter); IEnumerator ienumerable.getenumerator (); Ienumerable<filter> ifilterprovider.getfilters (ControllerContext controllercontext, ActionDescriptor Actiondescriptor); public int Count {get;}}
By naming and the definitions given above, you can see that globalfiltercollection is just a list of filter, and the implementation of the Getfilters method returns itself. We can add, delete, and purge the global filter through the methods provided by Globalfiltercollection. The parameter of the Add method for adding filter is not a filter object, but rather a specific filter (implementing the corresponding filter interface), the filter object that is added is created from the Filters object, and its scope property is set to global. We specify the order property of the Filter object by specifying it in the Add method, and if the specified order is not displayed and the specified filter is a FilterAttribute attribute, the order of the attribute will be the order of the Filter object Otherwise, use 1 as the Order property value.
The registration and acquisition of global filter (or global Filterprovider) for the entire Web application can be achieved through static type Globalfilters. As shown in the following code snippet, Globalfilters has a static read-only property filters returns a Globalfiltercollection object.
public static class globalfilters{public static globalfiltercollection Filters {get;}}
So far, we've introduced the three types of filterprovider that ASP. NET MVC provides by default, as well as the filter delivery mechanism that each uses. When the static type used to register Filterprovider is loaded, the three types of objects are created by default and used as the providers property value representing the global Filterprovider collection, in the following code fragment. In other words, by default, ASP. NET MVC uses these three types of filterprovider to provide all the filter objects.
public static class filterproviders{ static Filterproviders () { Providers = new Filterprovidercollection ( ); Providers.add (globalfilters.filters); Providers.add (New Filterattributefilterprovider ()); Providers.add (New Controllerinstancefilterprovider ()); } public static filterprovidercollection providers{get;private set;}}
Vi. Example Demo: Verifying the supply mechanism and execution order of the filter
To give the reader a more profound image of the filter supply mechanism described above, let's do a simple example demonstration. In an empty Web project created with the ASP. NET MVC project template from Visual Studio, we define a few filterattribute. Filterbaseattribute is an abstract type that implements the Iactionfilter interface, with three specific filterattribute (Fooattribute, Barattribute and Bazattribute) are its successors.
Public abstract class Filterbaseattribute:filterattribute, iactionfilter{public void onactionexecuted ( ActionExecutedContext filtercontext) {} public void OnActionExecuting (ActionExecutingContext filtercontext ) {}}public Class Fooattribute:filterbaseattribute{}public class Barattribute:filterbaseattribute{}public class bazattribute:filterbaseattribute{}
We first register Bazattribute as a global filter in Global.asax by the following way. It is important to note that Application_ is defined in the Global.asax created by default The Start method calls the Registerglobalfilters method to register a exceptionfilter of type handleerrorattribute, and we need to comment on this line of code.
public class mvcapplication:system.web.httpapplication{ //other member protected void Application_Start () { //Other Operation //registerglobalfilters (globalfilters.filters); GLOBALFILTERS.FILTERS.ADD (New Bazattribute ());} }
Finally we create the following default HomeController, an empty action method that applies our defined Barattribute attribute on the data, and the Fooattribute attribute on the HomeController class. In the default action method index, we get all the filter objects for the action method data by using the global Filterprovider list represented by Filterproviders's static property providers. and present their basic information (type, order, and scope properties).
[Foo]public class homecontroller:controller{public void Index () { Reflectedcontrollerdescriptor Controllerdescriptor = new Reflectedcontrollerdescriptor (typeof (HomeController)); Actiondescriptor actiondescriptor = controllerdescriptor.findaction (ControllerContext, "Data"); foreach (var filter in FilterProviders.Providers.GetFilters (ControllerContext, actiondescriptor)) { Response.Write (String. Format ("{0}<br/>", filter. Instance)); Response.Write (String. Format (" {0}: {1}<br/>", "Order", filter.) Order)); Response.Write (String. Format (" {0}: {1}<br/><br/>", "Scope", filter. Scope)); } } [Bar] public void Data () {}}
After running our program, we will render the results shown in 7-5 in the browser. We can clearly see that not only the FilterAttribute applied to the action method is applied to the target action, but is applied to the filterattribute of the Controller class, The filter of the global registration and the filter that the Controller object itself embodies are applied back to all actions.
The order and scope properties of the 4 filter applied to the action method data are displayed. As we mentioned earlier, these two properties determine the order in which similar filters are executed, and we now use this procedure to confirm this. For this we need to make the following modifications to Filterbaseattribute, in which we present the method name of the type of filterattribute that is currently being executed in onactionexecuting.
Public abstract class Filterbaseattribute:filterattribute, iactionfilter{public void onactionexecuted ( ActionExecutedContext filtercontext) {} public void OnActionExecuting (ActionExecutingContext filtercontext ) { filterContext.HttpContext.Response.Write (string. Format ("{0}". OnActionExecuting () <br/> ", this. GetType ()));} }
Then we rewrite the HomeController onactionexecuting method in the same way, rendering the current method name of the type HomeController itself.
[Foo]public class homecontroller:controller{ //Other member protected override void OnActionExecuting ( ActionExecutingContext filtercontext) { Response.Write ("homecontroller.onactionexecuting () <br/>") ; } [Bar] public void Data () {}}
We run our program again and specify the correct address on the browser to access the action method data defined in HomeController, which renders the result as shown in the browser. The result of the output reflects the order of execution of the four Actionfilter applied to data on the action method, which is consistent with the order and scope property values of the filter.
Another question worth examining about the filter's availability: When we define FilterAttribute, we can set the AllowMultiple property of the AttributeUsageAttribute applied on that type to false so that it can only be applied once on the same target element 。 However, we can still apply them on the action method and the controller type on which they are located, and even register them as global filter, so will these filterattribute be valid?
Let's try to verify this by example. Now we delete all the FilterAttribute, define the following type of Fooattribute Actionfilter, We set the AllowMultiple property of the AttributeUsageAttribute attribute above it to false.
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = False)]public class Fooattribute:filterattribute, iactionfilter{public void onactionexecuted (ActionExecutedContext filtercontext) {} public void OnActionExecuting ( ActionExecutingContext filtercontext) {}}
Now we apply the Fooattribute attribute to both the HomeController type and the action method data, and then register a global filter for the Fooattribute attribute in Global.asax.
[Foo]public class homecontroller:controller{ //other member [Foo] public void Data () {}}public class mvcapplication:system.web.httpapplication{ //other member protected void Application_Start () { //other operations //registerglobalfilters (globalfilters.filters); GLOBALFILTERS.FILTERS.ADD (New Fooattribute ());} }
Now that we run our program directly, the Open browser will show the results shown in 7-7. It is clear to see that although we have registered Fooattribute in three places, the AllowMultiple property of this attribute is false, so only one of the Fooattribute is ultimately valid.
For a filterattribute with a AllowMultiple property of false, if we register multiple scopes with a different scope, which one is ultimately valid? As you can see, the Fooattribute applied to the action method (scope action) is valid. The exact logic is this: all the filter created is sorted by Order+scope (that is, the order in which the filter executes), whichever is the last. For our example, the three filter provided has the same order attribute value (-1), all of which will eventually be sorted by scope (scope, controller, and action), and the last one is the filter of the scope action.
The above is the whole content of this article, I hope that the content of this article on everyone's study or work can bring certain help, if there are questions you can message exchange, but also hope to support topic.alibabacloud.com!