This document provides an overview of controllers and filters in ASP.NET Core MVC. It defines controllers as classes that handle browser requests, retrieve model data, and specify view templates. Actions are public methods on controllers that handle requests. Filters allow running code before and after stages of the execution pipeline and can be used to handle concerns like authorization, caching, and exception handling. The document discusses implementing different filter types, configuring filters through attributes and dependency injection, and controlling filter order.
Simplifying Microservices & Apps - The art of effortless development - Meetup...
.NET Core, ASP.NET Core Course, Session 9
1. .NET Core + ASP.NET Core Training Course
Session 9
2. .NET Core
What we learned?
Session 6 ~ 8 Overview
• Overview on HTTP Protocol
• Introducing ASP.NET Core applications
• Startup Class and Middleware in ASP.NET core
• Working with Static Files
• Error Handling and Logging
• Working with Configuration
• Working with app secrets
4. .NET Core
C like Controller
Controller – Basic overview
1. Classes that handle browser requests
2. Retrieve model data
3. specify view templates that return a response to the browser
In an MVC app, the view only displays information; the controller handles and
responds to user input and interaction.
In ASP.NET MVC, a Controller is used to define and group a set of actions. An action
(or action method) is a method on a controller that handles incoming requests.
5. .NET Core
Controllers
Controllers
In ASP.NET Core MVC, a controller can be any instantiable class that ends in
“Controller” or inherits from a class that ends with “Controller”.
By convention, controller classes:
• Are located in the root-level “Controllers” folder
• Inherit from Microsoft.AspNetCore.Mvc.Controller
But these two conventions are not required.
6. .NET Core
Controllers
Controllers
The Controller is a UI level abstraction. Its responsibility is to ensure incoming request
data is valid and to choose which view (or result for an API) should be returned.
In well-factored apps it will not directly include data access or business logic, but
instead will delegate to services handling these responsibilities.
7. .NET Core
Controllers, Actions
Controllers - Actions
Any public method on a controller type is an action. Parameters on actions are bound
to request data and validated using model binding.
Action methods that accept parameters should verify the ModelState.IsValid property
is true.
Action methods should contain logic for mapping an incoming request to a business
concern. Business concerns should typically be represented as services that your
controller accesses through dependency injection.
8. .NET Core
Controllers, Actions
Controllers - Actions
Actions can return anything, but frequently will return an instance of IActionResult (or
Task<IActionResult> for async methods) that produces a response. The action method
is responsible for choosing what kind of response; the action result does the
responding.
9. .NET Core
Controller Helper Methods
Controllers - Helper Methods
Although not required, most developers will want to have their controllers inherit
from the base Controller class. Doing so provides controllers with access to many
properties and helpful methods, including the following helper methods designed to
assist in returning various responses:
• View
• HTTP status code
• Formatted Response
• Content negotiated response
• Redirect
• Returning an Object
10. .NET Core
Cross-Cutting Concerns
Controllers - Cross-Cutting Concerns
In most apps, many actions will share parts of their workflow. For instance, most of an
app might be available only to authenticated users, or might benefit from caching.
When you want to perform some logic before or after an action method runs, you can
use a filter. You can help keep your actions from growing too large by using Filters to
handle these cross-cutting concerns. This can help eliminate duplication within your
actions, allowing them to follow the Don’t Repeat Yourself (DRY) principle.
11. .NET Core
Filters
Controllers - Filters
Filters in ASP.NET MVC allow you to run code before or after a particular stage in the
execution pipeline. Filters can be configured globally, per-controller, or per-action.
12. .NET Core
How do filters work?
Controllers - Filters
Each filter type is executed at a different stage in the pipeline,
and thus has its own set of intended scenarios.
Different filter types run at different points within the pipeline. Some filters, like
authorization filters, only run before the next stage in the pipeline, and take no action
afterward. Other filters, like action filters, can execute both before and after other
parts of the pipeline execute.
13. .NET Core
Selecting a Filter
Controllers - Filters
Authorization filters are used to determine whether the current user is authorized for the request being
made.
Resource filters are the first filter to handle a request after authorization, and the last one to touch the
request as it is leaving the filter pipeline. They’re especially useful to implement caching or otherwise short-circuit the
filter pipeline for performance reasons.
Action filters wrap calls to individual action method calls, and can manipulate the arguments passed into an
action as well as the action result returned from it.
Exception filters are used to apply global policies to unhandled exceptions in the MVC app.
Result filters wrap the execution of individual action results, and only run when the action method has
executed successfully. They are ideal for logic that must surround view execution or formatter execution.
14. .NET Core
Filter Implementation
Controllers – Implementing Filters (sync)
All filters support both synchronous and asynchronous implementations through different interface
definitions.
Synchronous filters define both an OnStageExecuting and OnStageExecuted method (with noted
exceptions).
The OnStageExecuting method will be called before the event
pipeline stage by the Stage name, and the OnStageExecuted
method will be called after the pipeline stage named by the Stage
name.
15. .NET Core
Filter Implementation
Controllers – Implementing Filters (Async)
Asynchronous filters define a single OnStageExecutionAsync method that will surround execution
of the pipeline stage named by Stage.
The OnStageExecutionAsync method is provided a
StageExecutionDelegate delegate which will execute the
pipeline stage named by Stage when invoked and awaited.
16. .NET Core
Filter Implementation
Controllers – Implementing Filters
You should only implement either the synchronous or the async version of a filter interface, not both.The
framework will check to see if the filter implements the async interface first, and if so, it will call it. If not, it will
call the synchronous interface’s method(s). If you were to implement both interfaces on one class, only the
async method would be called by the framework. Also, it doesn’t matter whether your action is async or not,
your filters can be synchronous or async independent of the action.
17. .NET Core
Filter Scopes
Controllers - Filters
Filters can be scoped at three different levels
• Particular action as an attribute
• All actions within a controller with attribute
• Register a filter globally, to be run with every MVC action (ConfigureServices method in Startup)
18. .NET Core
Filter Scopes
Controllers - Filters
Filters can be added by type, or an instance can be added.
• If you add an instance, that instance will be used for every request.
• If you add a type, it will be type-activated, meaning an instance will be created for each
request and any constructor dependencies will be populated by DI. Adding a filter by type
is equivalent to filters.Add(new TypeFilterAttribute(typeof(MyFilter))).
It’s often convenient to implement filter interfaces as Attributes. Filter attributes are applied to
controllers and action methods. The framework includes built-in attribute-based filters that you
can subclass and customize.
19. .NET Core
Filter Scopes
Controllers - Filters
inherits from ResultFilterAttribute,
and overrides its OnResultExecuting
method to add a header to the
response
20. .NET Core
Cancellation and Short Circuiting
Controllers - Filters
short-circuit the filter pipeline at any
point by setting the Result property on
the context parameter provided to the
filter method
both the ShortCircuitingResourceFilter and the AddHeader
filter target the SomeResource action method. However,
because the ShortCircuitingResourceFilter runs first and
short-circuits the rest of the pipeline, the AddHeader filter
never runs for the SomeResource action. This behavior
would be the same if both filters were applied at the action
method level, provided the ShortCircuitingResourceFilter
ran first
21. .NET Core
Configuring Filters
Controllers - Filters
Global filters are configured within Startup.cs
Attribute-based filters that do not require any dependencies can simply inherit from an existing
attribute of the appropriate type for the filter in question
To create a filter without global scope that requires dependencies from DI, apply the
ServiceFilterAttribute or TypeFilterAttribute attribute to the controller or action.
22. .NET Core
Dependency Injection
Controllers - Filters
Filters that are implemented as attributes and added directly to controller classes or action methods cannot
have constructor dependencies provided by dependency injection (DI).
This is because attributes must have their constructor parameters supplied where they are applied. This is a
limitation of how attributes work.
if your filters have dependencies you need to access from DI, there are several supported approaches. You
can apply your filter to a class or action method using
• ServiceFilterAttribute
• TypeFilterAttribute
• IFilterFactory implemented on your attribute
23. .NET Core
Dependency Injection
Controllers - Filters
A TypeFilter will instantiate an instance, using services from DI for its dependencies. A ServiceFilter retrieves
an instance of the filter from DI. The following example demonstrates using a ServiceFilter:
Using ServiceFilter without registering the filter type in ConfigureServices, throws the following exception:
System.InvalidOperationException: No service for type
'FiltersSample.Filters.AddHeaderFilterWithDI' has been registered.
To avoid this exception, you must register the AddHeaderFilterWithDI type in ConfigureServices:
24. .NET Core
Dependency Injection
Controllers - Filters
ServiceFilterAttribute implements IFilterFactory, which exposes a single method for creating an
IFilter instance.
In the case of ServiceFilterAttribute, the IFilterFactory interface’s CreateInstance method is
implemented to load the specified type from the services container (DI).
TypeFilterAttribute is very similar to ServiceFilterAttribute (and also implements IFilterFactory),
but its type is not resolved directly from the DI container. Instead, it instantiates the type using a
Microsoft.Extensions.DependencyInjection.ObjectFactory.
25. .NET Core
Dependency Injection
Controllers - Filters
Types that are referenced using the TypeFilterAttribute do not need to be registered with the
container first (but they will still have their dependencies fulfilled by the container).
Also, TypeFilterAttribute can optionally accept constructor arguments for the type in question.
The following example demonstrates how to pass arguments to a type using TypeFilterAttribute:
26. .NET Core
Dependency Injection
Controllers - Filters
If you have a simple filter that doesn’t require any arguments, but which has constructor
dependencies that need to be filled by DI, you can inherit from TypeFilterAttribute, allowing you
to use your own named attribute on classes and methods (instead of
[TypeFilter(typeof(FilterType))]). This filter can be applied to classes or methods
using the [SampleActionFilter] syntax, instead of
having to use [TypeFilter] or [ServiceFilter].
27. .NET Core
Dependency Injection
Controllers - Filters
IFilterFactory implements IFilter. Therefore, an IFilterFactory instance can be used as an IFilter
instance anywhere in the filter pipeline.
When the framework prepares to invoke the filter,
attempts to cast it to an IFilterFactory. If that cast
succeeds, the CreateInstance method is called to
create the IFilter instance that will be invoked.
This provides a very flexible design, since the
precise filter pipeline does not need to be set
explicitly when the application starts.
28. .NET Core
Ordering
Controllers - Filters
Filters can be applied to action methods or controllers (via attribute) or added to the global
filters collection. Scope also generally determines ordering. The filter closest to the action runs
first; generally you get overriding behavior without having to explicitly set ordering. This is
sometimes referred to as “Russian doll” nesting, as each increase in scope is wrapped around
the previous scope, like a nesting doll.
In addition to scope, filters can override their sequence of execution by implementing
IOrderedFilter. This interface simply exposes an int Order property, and filters execute in
ascending numeric order based on this property.
29. .NET Core
Ordering
Controllers - Filters
All of the built-in filters, including TypeFilterAttribute and ServiceFilterAttribute, implement
IOrderedFilter, so you can specify the order of filters when you apply the attribute to a class or
method.
By default, the Order property is 0 for all of the built-in filters, so scope is used as a tie-breaker
and (unless Order is set to a non-zero value) is the determining factor.
30. .NET Core
Ordering
Controllers - Filters
Every controller that inherits from the Controller base class includes OnActionExecuting and
OnActionExecuted methods. These methods wrap the filters that run for a given action, running
first and last. The scope-based order, assuming no Order has been set for any filter, is:
1. The Controller OnActionExecuting
2. The Global filter OnActionExecuting
3. The Class filter OnActionExecuting
4. The Method filter OnActionExecuting
5. The Method filter OnActionExecuted
6. The Class filter OnActionExecuted
7. The Global filter OnActionExecuted
8. The Controller OnActionExecuted
31. .NET Core
Ordering
Controllers - Filters
To modify the default, scope-based order, you could explicitly set the Order property of a class-level or method-level
filter. For example, adding Order=-1 to a method level attribute:
[MyFilter(Name = "Method Level Attribute", Order=-1)]
In this case, a value of less than zero would ensure this filter ran before both the Global and Class level filters (assuming
their Order property was not set).
The new order would be:
1. The Controller OnActionExecuting
2. The Method filter OnActionExecuting
3. The Global filter OnActionExecuting
4. The Class filter OnActionExecuting
5. The Class filter OnActionExecuted
6. The Global filter OnActionExecuted
7. The Method filter OnActionExecuted
8. The Controller OnActionExecuted
32. .NET Core
Authorization Filters
Controllers - Filters
Authorization Filters control access to action methods, and are the first filters to be executed
within the filter pipeline. They have only a before stage, unlike most filters that support before
and after methods.
You should only write a custom authorization filter if you are writing your own authorization
framework. Note that you should not throw exceptions within authorization filters, since nothing
will handle the exception (exception filters won’t handle them). Instead, issue a challenge or find
another way.
33. .NET Core
Resource Filters
Controllers - Filters
Resource Filters implement either the IResourceFilter or IAsyncResourceFilter interface, and their
execution wraps most of the filter pipeline (only Authorization Filters run before them - all other
filters and action processing happens between their OnResourceExecuting and
OnResourceExecuted methods).
Resource filters are especially useful if you need to short-circuit most of the work a request is doing.
Caching would be one example use case for a resource filter, since if the response is already in the cache,
the filter can immediately set a result and avoid the rest of the processing for the action.
35. .NET Core
Action Filters
Controllers - Filters
Action Filters implement either the IActionFilter or IAsyncActionFilter interface and their
execution surrounds the execution of action methods. Action filters are ideal for any logic that
needs to see the results of model binding, or modify the controller or inputs to an action
method. Additionally, action filters can view and directly modify the result of an action method.
The OnActionExecuting method runs before the action method, so it can manipulate the inputs to the
action by changing ActionExecutingContext.ActionArguments or manipulate the controller through
ActionExecutingContext.Controller. An OnActionExecuting method can short-circuit execution of the action
method and subsequent action filters by setting ActionExecutingContext.Result. Throwing an exception in
an OnActionExecuting method will also prevent execution of the action method and subsequent filters, but
will be treated as a failure instead of successful result.
36. .NET Core
Action Filters
Controllers - Filters
The OnActionExecuted method runs after the action method and can see and manipulate the
results of the action through the ActionExecutedContext.Result property.
ActionExecutedContext.Canceled will be set to true if the action execution was short-circuited by
another filter. ActionExecutedContext.Exception will be set to a non-null value if the action or a
subsequent action filter threw an exception.
Setting ActionExecutedContext.Exception to null effectively ‘handles’ an exception, and
ActionExectedContext.Result will then be executed as if it were returned from the action method
normally.
37. .NET Core
Action Filters
Controllers - Filters
For an IAsyncActionFilter the OnActionExecutionAsync combines all the possibilities of
OnActionExecuting and OnActionExecuted.
A call to await next() on the ActionExecutionDelegate will execute any subsequent action filters
and the action method, returning an ActionExecutedContext.
To short-circuit inside of an OnActionExecutionAsync, assign ActionExecutingContext.Result to
some result instance and do not call the ActionExectionDelegate.
38. .NET Core
Exception Filters
Controllers - Filters
Exception Filters implement either the IExceptionFilter or IAsyncExceptionFilter interface.
Exception filters handle unhandled exceptions, including those that occur during controller
creation and model binding. They are only called when an exception occurs in the pipeline. They
can provide a single location to implement common error handling policies within an app. The
framework provides an abstract ExceptionFilterAttribute that you should be able to subclass for
your needs.