IPageFilter
The Razor Pages-specific filter implementation is represented by the
IPageFilter
interface and its asynchronous counterpart, IAsyncPageFilter
.The
examples here will use the asynchronous version because that is what you are
most likely to use if you re getting data from elsewhere. The
IAsyncPageFilter
interface is implemented by the Razor Pages
PageModel
class and enables you to insert processing logic at the point
that the page's handler method has been selected, but before model binding has
happened (OnPageHandlerSelectionAsync
method), and at the point before the handler is executed, but after
model binding has taken place (OnPageHandlerExecutionAsync
method)
When you use either of these methods from within a class that derives from
PageModel
(e.g. any Razor Pages "code behind" file), you automatically have access to the current PageModel
and its ViewData.
Filters are mostly used to execute code that runs for any number of pages.
Therefore you are more likely to implement the IPageFilter
or
IAsyncPageFilter
methods in a base PageModel
class
that your individual pages derive from to adhere to DRY
principals rather then re-implement the same
code in numerous PageModel files. Again, PageModel properties declared in this type of class are readily accessible.
Alternatively, if you have multiple filters, you might create separate filter classes
that implement IAsyncPageFilter
and register them globally. When you do that, the model is not so obviously accessible.
Global Filters
The following example demonstrates how to access the model from within a
globally registered filter. It assumes that you have derived from
PageModel
to create a base PageModel class that all or most of your other
Razor Pages will inherit. You might do this when you want to make the same data
available to multiple pages. One example where this approach can be used is a permissions-based authorisation system. You need to be
able to check if the current user has permission to e.g. view orders, create orders,
edit orders etc, and then show or hide certain sections of the page (including the
navigation) based on that. Filters are a good way of centralising the
acquisition of the necessary data for those types of checks.
This particular Pagemodel
class has one property for demo
purposes: Found
:
There are a couple of ways to access this property from within a globally
registered filter class. They both begin with the context
property
that's passed in as an argument to the filter method that you implement. Here is
an implementation of an IAsyncPageFilter
illustrating both methods:
In the OnPageHandlerSelectionAsync
method, the HandlerInstance
property of the
context
parameter (representing a PageHandlerSelectedContext
object) is accessed. The HandlerInstance
property represents the object that the selected handler method resides within
i.e. the current page model. The code uses GetType
to establish whether the current page model derives from BasePageModel
,
and if so, it is cast to that type so that the Found
property can
be set.
The OnPageHandlerExecutionAsync
method's context
parameter (a
PageHandlerExecutingContext
) also exposes a
HandlerInstance
property so the previous approach can also be used in this method. However, this example demonstrates an alternative that is only available in this method.
This time, the context's Result
property is accessed. This
represents the
ActionResult that the handler method will generate. We are only interested
in results that render a Razor Page i.e. a PageResult
type, so the
code filters out other results. The result is cast to the correct type, and the
Model
property can be accessed directly as can the ViewData
dictionary if desired:
var viewData = ((PageResult)result).ViewData;
Once again, GetType
is used to establish that the current model
derives from BasePageModel
and the Found
property is accessed
accordingly.
Filters as Attributes
If you want to implement your filter as an attribute, you have two options:
derive from ActionFilterAttribute
or from
ResultFilterAttribute
. In either case, you should override the
OnResultExecutionAsync
method because the OnActionExecutionAsync
method is only used for MVC. And in both cases the ResultExecutingContext
parameter passed into the methods exposes a
Result
property which can be used in the same way as the global filter implementation:
Summary
Filters in Razor Pages are very flexible and can be implemented in a number or ways. Regardless of your chosen implementation, it is relatively easy to access the PageModel once you know how.