Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Exception Filters returns an empty body in asp.net-core 1.1 #5594

Closed
robertovanoli opened this issue Dec 5, 2016 · 31 comments
Closed

Exception Filters returns an empty body in asp.net-core 1.1 #5594

robertovanoli opened this issue Dec 5, 2016 · 31 comments

Comments

@robertovanoli
Copy link

robertovanoli commented Dec 5, 2016

I have a very simple controller with an ExceptionFilterAttribute that throws an exception

   [TypeFilter(typeof(MyControllerExceptionFilterAttribute))]
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            throw new Exception("Hello Exception");
            return View();
        }
   }
}

this is the ExceptionFilterAttribute

   [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
    public class MyControllerExceptionFilterAttribute : ExceptionFilterAttribute
    {
        protected readonly IHostingEnvironment _hostingEnvironment;
        protected readonly IModelMetadataProvider _modelMetadataProvider;

        public MyControllerExceptionFilterAttribute(IHostingEnvironment hostingEnvironment, IModelMetadataProvider modelMetadataProvider)
        {
            _hostingEnvironment = hostingEnvironment;
            _modelMetadataProvider = modelMetadataProvider;
        }

        public override void OnException(ExceptionContext context)
        {
            if (context.ExceptionHandled) return;
            var result = new ViewResult { ViewName = "ApplicationError" };
            context.ExceptionHandled = true; // mark exception as handled
            context.HttpContext.Response.Clear();
            context.Result = result;
        }
    }

this works fine in asp.net core 1.0, while in asp.net core 1.1 the result is not rendered anymore and the returned http response is like this:

HTTP/1.1 200 OK
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcUHJvamVjdHNcaW50ZXJhaC52aXN1YWxzdHVkaW8uY29tXEludmVudGFyaW9cTWFpblxTb3VyY2VcRnJvbnRvZmZpY2Vcc3JjXEZyb250b2ZmaWNl?=
X-Powered-By: ASP.NET
Date: Wed, 30 Nov 2016 14:49:53 GMT
Content-Length: 0

You can reproduce very easily in this way

  1. create a new ASP.NET Core Web Application (.NET Framework). by default asp.net core 1.0 is installed. then add the controller the ExceptionFilterAttribute above and a very simple ApplicationError view: the view is rendered
  2. update to asp.net core 1.1 then excecute: the view is not rendered and the returned page is blank
  3. comment the row 'context.ExceptionHandled = true;' in ExceptionFilterAttribute: at this point the view is rendered as in step 1.

my conclusion is that 'context.ExceptionHandled = true' is not working as expected

I've made this small project to demostrate the behavior https://www.dropbox.com/s/dl1xa7d2nzy48o8/WebApplication3.zip?dl=0

@frankabbruzzese
Copy link

Not sure this is a bug. It appears just a change in the default state of context.ExceptionHandled. That value is not intended to inform the developer on the exception state, but on the contrary for the developer to inform the framework it handeld the exception, so the exception must stop propagation..

In a few words you dont need to check context.ExceptionHandled since if another component handles the exception yor handler will not be invoked at all.

What changed in the new version is that this value is pre-set to true, since it is more common developer handles exception. In case developer decide it is not able to recover exception he may set context.ExceptionHandled to false.

@robertovanoli
Copy link
Author

robertovanoli commented Dec 5, 2016

Hi @frankabbruzzese, thank you for your explanation.
I removed the check on ExceptionHandled, but I am still a bit confused about when to set it true or false:

the official sample set ExceptionHandled = true, then returns a view as result.

In my case the behavior seems to be very different :-(

  • if I set ExceptionHandled = true: a 200 httpstatus is returned (as in the sample), but the body of the response is empty
  • if I set ExceptionHandled = false (or if I don't set it at all - which should be equal true): 200 httpstatus is returned and the body of the response contains the rendered view

@frankabbruzzese
Copy link

You should set ExceptionHandled = true when you handle exception and false whenyou want exception coninue being thrown up. This should always work also if ExceptionHandled default changed.

Otherwise there is a bug somewhere. Have you tried removing:
context.HttpContext.Response.Clear();
?

@robertovanoli
Copy link
Author

robertovanoli commented Dec 5, 2016

Here my ExceptionFilterAttribute now

public override void OnException(ExceptionContext context) { var result = new ViewResult { ViewName = "ApplicationError" }; context.ExceptionHandled = true; // mark exception as handled context.Result = result; }

setting context.ExceptionHandled = true, a blank page is shown (response body empty)
The view is a single row
<h1>Errore Applicativo</h1>

the project is an empty ASP.NET Core Web Application (.NET Framework)
No other code is present on my side

@frankabbruzzese
Copy link

I downloaded your project and played with it. Basically context.ExceptionHandled = true,always cause a blank page while context.ExceptionHandled = false, correcly displays the custom error page, that makes absolutely no sense.

You are right there is a bug!

@juunas11
Copy link
Contributor

juunas11 commented Dec 7, 2016

@frankabbruzzese I thought the point of ExceptionHandled was to signal the framework that "I got it, it's ok". So it returning 200 OK should be expected no?

@frankabbruzzese
Copy link

@juunas11 ,
ExceptionHandled = true, says "ok I handled the exception, no need to propagate it further", so in the case of @robertovanoli 2oo ok is expected since he have not explicitely set an error header. What is not expected is the blank page!!! Why the the View passsed in ViewResult is not rendered???

It is strange also what happens when setting ExceptionHandled = false. In this case if no ViewResult is set you get an error header which is correct. However, if you set a ViewResult you still get a 200 ok, but this time View is rendered!

Thus it appears that `ExceptionHandled should alway be set to false, and the response depends if you set or not the ViewResult.

Maybe ExceptionHandled = true must be used only when ExceptionFilter write directly in the response stream?? This would explain everything. However, this behavior is different from what is written in the documentation...So some correction is needed anywau :)

@juunas11
Copy link
Contributor

juunas11 commented Dec 7, 2016

@frankabbruzzese Ohh, I misread it. The blank page is certainly weird since a view result was set. I'll have a look at this if I have a moment.

@juunas11
Copy link
Contributor

juunas11 commented Dec 7, 2016

@robertovanoli I got the error page to show just by commenting out context.HttpContext.Response.Clear();. The other thing is that as @frankabbruzzese mentioned the default for ExceptionHandled is now true, so you must set it to false if you don't want to handle the exception.

    public override void OnException(ExceptionContext context)
    {
        if (_hostingEnvironment.IsDevelopment())
        {
            context.ExceptionHandled = false;
            return;
        }
        var result = new ViewResult { ViewName = "ApplicationError" };
        context.Result = result;
    }

This works for me.

@frankabbruzzese
Copy link

@juunas11 ,
No actually. context.ExceptionHandled is not true as defaul, but it is false. I supposed it was true to explain the behavior,..but before downloading the project and debugging it.

Your code works simply bacause you dont set context.ExceptionHandled = true. Try setting explicitaly it to true, and you will see error page is not shown anymore.

@juunas11
Copy link
Contributor

juunas11 commented Dec 7, 2016

@frankabbruzzese You are right! I took a little dive into ControllerActionInvoker's state machine.

This line in particular seems to be the reason the behaviour is the way it is: https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionInvoker.cs#L675

if (exceptionContext.Result != null && !exceptionContext.ExceptionHandled)
{
    goto case State.ExceptionShortCircuit;
}

So the short-circuiting is only done if a result is set, and ExceptionHandled is false. The short-circuit state is the one that executes the result. Seems to be this commit that added this part. @rynowak was this intended behaviour? After more testing I can confirm the OP's code worked as expected on 1.0.0, but not on 1.1.0.

@frankabbruzzese
Copy link

@juunas11,
Either bug or change in intended meaning of ExceptionHandled = true from "exception handled" to "exception handled completely" by writing response in the response stream.

@rynowak
Copy link
Member

rynowak commented Dec 8, 2016

This seems like it should be an or.

So, to confirm this is working as expected when you set both .Result and .ExceptionHandled

@juunas11
Copy link
Contributor

juunas11 commented Dec 8, 2016

When you set a result, and leave ExceptionHandled false, the result gets executed. But if you set a result, and set ExceptionHandled to true, the result does not get executed.

@frankabbruzzese
Copy link

@rynowak ,
Not convinced must be an or. In any case it appears that !exceptionContext.ExceptionHandled should be substituted with exceptionContext.ExceptionHandled. IE the main error appears to be the negation.

About the or. It depends if one allows the exception be handled by writing directly in the Response stream instead of returning a result. I dont know if this scenario is properly handled anyway, since
State.ExceptionShortCircuit perform an InvokeAsymc of the Result in any case.

Another strange stuff is:

Since with ExceptionHandled = true at moment the if fails, so according to the state machine the exception should be rethrown...instead a 200 ok is returned with a blank page!

@robertovanoli
Copy link
Author

robertovanoli commented Dec 14, 2016

@frankabbruzzese
Francesco, for now I bypassed rendering a HTML response by myself . As you can see setting ExceptionHandled = true works fine. Obviously it's only a temporary workaround...
regards

public override void OnException(ExceptionContext context)
{
   context.ExceptionHandled = true; // mark exception as handled
   context.HttpContext.Response.Clear();
   context.HttpContext.Response.StatusCode = 400;
   context.HttpContext.Response.ContentType = new MediaTypeHeaderValue("text/html").ToString();
   var home = string.Format("{0}://{1}", context.HttpContext.Request.Scheme,context.HttpContext.Request.Host);
   var htmlString ="SI E' VERIFICATO UN ERRORE INATTESO";
   context.HttpContext.Response.WriteAsync(htmlString, Encoding.UTF8);
}

@Eilon
Copy link
Member

Eilon commented Jan 25, 2017

@dougbu @rynowak - any ideas on this?

@rynowak
Copy link
Member

rynowak commented Jan 25, 2017

We need to double check the behavior of short circuiting exception filters wrt compatibility with MVC5. This should be a patch candidate if we have a bug here

@dougbu dougbu added this to the 1.1.1 milestone Jan 27, 2017
@dougbu
Copy link
Member

dougbu commented Jan 28, 2017

Have confirmed IActionFilters in MVC 5.2.3 and ASP.NET Core 1.1.0 behave the same. However, IExceptionFitlers behave differently w.r.t. setting Result but leaving ExceptionHandled==false. Should remove this special case around setting Result.

1.1.0 behaviour is also a regression compared to ASP.NET Core 1.0.x.

Long story about a consistent behaviour for ASP.NET Core:

  • Users can short-circuit most IFilterMetadata implementations by setting Result. But, only on the way in e.g. OnActionExecuting() can short-circuit but OnActionExecuted() cannot.
  • To short-circuit IExceptionFilter implementations (which are only called on the way out), users must set ExceptionHandled==true.
  • Setting ExceptionHandled==true in all IFilterMetadata implementations also ensures an Exception thrown in an action is not rethrown. An overridden Result is used in that case.
  • In a small, intentional deviation from MVC 5.2.3, setting Exception==null is handled identically to setting ExceptionHandled==true.

Fix should be a one-line change in ControllerActionInvoker line 675.

@dougbu
Copy link
Member

dougbu commented Jan 31, 2017

Resetting labels other than Bug and patch-proposed. @Eilon / @danroth27

@Eilon
Copy link
Member

Eilon commented Feb 8, 2017

This patch bug is approved. Please use the normal code review process w/ a PR and make sure the fix is in the correct branch, then close the bug and mark it as done.

@Eilon Eilon assigned rynowak and unassigned dougbu Feb 9, 2017
@rynowak
Copy link
Member

rynowak commented Feb 10, 2017

@dougbu - I could use your help to fact check the following table:

I'm defining short circuit to mean that subsequent exception filters do not run, and no exception is thrown. If it doesn't say short circuit then it means that all exception filters will run.

I'm defining result executed to mean that the action result is executed and the original exception is not rethrown. If it doesn't say result executed then nothing is written to the output by MVC.


MVC 5.2.3 MVC Core 1.0.0 MVC Core 1.1.0 MVC Core 1.1.2 (proposed by me)
set Result exception thrown result executed @dougbu confirmed result executed @dougbu confirmed result executed
set ExceptionHandled @rynowak short circuit @dougbu just disables re-throwing short circuit short circruit short circruit
set Exception = null exception thrown short circuit short circuit short circruit
set Result && Exception Handled @rynowak short circuit && result executed @dougbu exception handlers never short circuit short circuit && result executed short circuit short circuit && result executed

Explanation

This bug is users broken by the change going from MVC Core 1.0.0 -> MVC Core 1.1.0. Namely that we don't run the result when you set exception handled. This seems like an obvious bug.

However, no one is complaining about the behavior changes going from MVC 5.2.3 -> MVC Core 1.X.X. Namely that setting .Result will short circuit and execute the result. Changing this to have the MVC 5.2.3 behavior wouldn't make much sense, why are you setting a result if you don't want it to run? It would also break a lot of people.

@rynowak
Copy link
Member

rynowak commented Feb 10, 2017

I'm going to move forward with a PR to make the behavior like the table above since that resolves the breaking change we accidentally made in 1.1.0. If there are any other changes we want to make here let's discuss that separately.

@dougbu
Copy link
Member

dougbu commented Feb 10, 2017

@rynowak I edited your table above with one tweak. But, I agree we should focus on the one thing customers have complained about. That's the unintended Core 1.0.0 to 1.1.0 change you're reverting in the 1.1.2 column.

BTW this could simply be a typo in one line of code. @frankabbruzzese mentioned the oddball at line 675 in ControllerActionInvoker above. None of the other ExceptionContext checks look like that one. The rest check exceptionContext.Exception == null and not exceptionContext.Result != null. (Well, there's another line with the same condition but that's just for logging.)

@rynowak
Copy link
Member

rynowak commented Feb 10, 2017

BTW this could simply be a typo in one line of code.

That's part of the fix.

@rynowak
Copy link
Member

rynowak commented Feb 13, 2017

#5777 (comment)

This has been fixed in dev and in rel/1.1.2

@grokky1
Copy link

grokky1 commented Feb 20, 2017

@rynowak Glad this bug was squashed.

However, since 1.1.2 hasn't been released yet, what is the recommended workaround right now?
i.e. Within an exception filter, to perform a redirect / set the Result / etc.?

@robertovanoli
Copy link
Author

@grokky1
Copy link

grokky1 commented Feb 20, 2017

@robertovanoli Yeah, pity we can't set .Result though, because it is more flexible, e.g. to redirect with arguments

@Ciantic
Copy link

Ciantic commented Jun 2, 2017

I came here from the docs they say at the moment:

In ASP.NET 1.1, the response is not sent if you set ExceptionHandled to true and write a response. In that scenario, ASP.NET Core 1.0 does send the response, and ASP.NET Core 1.1.2 will return to the 1.0 behavior.

Should this work again?

        public void OnException(ExceptionContext context)
        {
            if (context.Exception is ApiError)
            {
                context.Result = (context.Exception as ApiError).GetResult();
                context.Exception = null;
                context.ExceptionHandled = true;
            }

I keep getting empty result back

@Ciantic
Copy link

Ciantic commented Jun 2, 2017

I think I was confused by csproj, I changed:

<RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion>
to
<RuntimeFrameworkVersion>1.1.2</RuntimeFrameworkVersion>

Instead, of course one must update this line:

<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.1" />
to
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.2" />

Rick-Anderson added a commit to dotnet/AspNetCore.Docs that referenced this issue Oct 13, 2018
---
title: Filters in ASP.NET Core
author: ardalis
description: Learn how filters work and how to use them in ASP.NET Core MVC.
ms.author: riande
ms.date: 10/15/2018
uid: mvc/controllers/filters
---
# Filters in ASP.NET Core

By [Rick Anderson](https://twitter.com/RickAndMSFT), [Tom Dykstra](https://github.com/tdykstra/), and [Steve Smith](https://ardalis.com/)

*Filters* in ASP.NET Core MVC allow you to run code before or after specific stages in the request processing pipeline.

> [!IMPORTANT]
> This topic does **not** apply to Razor Pages. ASP.NET Core 2.1 and later supports [IPageFilter](/dotnet/api/microsoft.aspnetcore.mvc.filters.ipagefilter?view=aspnetcore-2.0) and [IAsyncPageFilter](/dotnet/api/microsoft.aspnetcore.mvc.filters.iasyncpagefilter?view=aspnetcore-2.0) for Razor Pages. For more information, see [Filter methods for Razor Pages](xref:razor-pages/filter).

 Built-in filters handle tasks such as:

 * Authorization (preventing access to resources a user isn't authorized for).
 * Ensuring that all requests use HTTPS.
 * Response caching (short-circuiting the request pipeline to return a cached response). 

Custom filters can be created to handle cross-cutting concerns. Filters can avoid duplicating code across actions. For example, an error handling exception filter could consolidate error handling.

[View or download sample from GitHub](https://github.com/aspnet/Docs/tree/master/aspnetcore/mvc/controllers/filters/sample).

## How do filters work?

Filters run within the *MVC action invocation pipeline*, sometimes referred to as the *filter pipeline*.  The filter pipeline runs after MVC selects the action to execute.

![The request is processed through Other Middleware, Routing Middleware, Action Selection, and the MVC Action Invocation Pipeline. The request processing continues back through Action Selection, Routing Middleware, and various Other Middleware before becoming a response sent to the client.](filters/_static/filter-pipeline-1.png)

### Filter types

Each filter type is executed at a different stage in the filter pipeline.

* [Authorization filters](#authorization-filters) run first and are used to determine whether the current user is authorized for the current request. They can short-circuit the pipeline if a request is unauthorized. 

* [Resource filters](#resource-filters) are the first to handle a request after authorization.  They can run code before the rest of the filter pipeline, and after the rest of the pipeline has completed. They're useful to implement caching or otherwise short-circuit the filter pipeline for performance reasons. They run before model binding, so they can influence model binding.

* [Action filters](#action-filters) can run code immediately before and after an individual action method is called. They can be used to manipulate the arguments passed into an action and the result returned from the action.

* [Exception filters](#exception-filters) are used to apply global policies to unhandled exceptions that occur before anything has been written to the response body.

* [Result filters](#result-filters) can run code immediately before and after the execution of individual action results. They run only when the action method has executed successfully. They are useful for logic that must surround view or formatter execution.

The following diagram shows how these filter types interact in the filter pipeline.

![The request is processed through Authorization Filters, Resource Filters, Model Binding, Action Filters, Action Execution and Action Result Conversion, Exception Filters, Result Filters, and Result Execution. On the way out, the request is only processed by Result Filters and Resource Filters before becoming a response sent to the client.](filters/_static/filter-pipeline-2.png)

## Implementation

Filters support both synchronous and asynchronous implementations through different interface definitions. 

Synchronous filters that can run code both before and after their pipeline stage define On*Stage*Executing and On*Stage*Executed methods. For example, `OnActionExecuting` is called before the action method is called, and `OnActionExecuted` is called after the action method returns.

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/SampleActionFilter.cs?name=snippet1)]

Asynchronous filters define a single On*Stage*ExecutionAsync method. This method takes a *FilterType*ExecutionDelegate delegate which executes the filter's pipeline stage. For example, `ActionExecutionDelegate` calls the action method or next action filter, and you can execute code before and after you call it.

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/SampleAsyncActionFilter.cs?highlight=6,8-10,13)]

You can implement interfaces for multiple filter stages in a single class. For example, the [ActionFilterAttribute](/dotnet/api/microsoft.aspnetcore.mvc.filters.actionfilterattribute?view=aspnetcore-2.0) class implements `IActionFilter`, `IResultFilter`, and their async equivalents.

> [!NOTE]
> Implement **either** the synchronous or the async version of a filter interface, not both. The framework checks first to see if the filter implements the async interface, and if so, it calls that. If not, it calls the synchronous interface's method(s). If you were to implement both interfaces on one class, only the async method would be called. When using abstract classes like [ActionFilterAttribute](/dotnet/api/microsoft.aspnetcore.mvc.filters.actionfilterattribute?view=aspnetcore-2.0) you would override only the synchronous methods or the async method for each filter type.

### IFilterFactory

[IFilterFactory](/dotnet/api/microsoft.aspnetcore.mvc.filters.ifilterfactory) implements [IFilterMetadata](/dotnet/api/microsoft.aspnetcore.mvc.filters.ifiltermetadata). Therefore, an `IFilterFactory` instance can be used as an `IFilterMetadata` instance anywhere in the filter pipeline. When the framework prepares to invoke the filter, it attempts to cast it to an `IFilterFactory`. If that cast succeeds, the [CreateInstance](/dotnet/api/microsoft.aspnetcore.mvc.filters.ifilterfactory.createinstance) method is called to create the `IFilterMetadata` instance that will be invoked. This provides a flexible design, since the precise filter pipeline doesn't need to be set explicitly when the app starts.

You can implement `IFilterFactory` on your own attribute implementations as another approach to creating filters:

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/AddHeaderWithFactoryAttribute.cs?name=snippet_IFilterFactory&highlight=1,4,5,6,7)]

### Built-in filter attributes

The framework includes built-in attribute-based filters that you can subclass and customize. For example, the following Result filter adds a header to the response.

<a name="add-header-attribute"></a>

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/AddHeaderAttribute.cs?highlight=5,16)]

Attributes allow filters to accept arguments, as shown in the example above. You would add this attribute to a controller or action method and specify the name and value of the HTTP header:

[!code-csharp[](./filters/sample/src/FiltersSample/Controllers/SampleController.cs?name=snippet_AddHeader&highlight=1)]

The result of the `Index` action is shown below - the response headers are displayed on the bottom right.

![Developer Tools of Microsoft Edge showing response headers, including Author Steve Smith @ardalis](filters/_static/add-header.png)

Several of the filter interfaces have corresponding attributes that can be used as base classes for custom implementations.

Filter attributes:

* `ActionFilterAttribute`
* `ExceptionFilterAttribute`
* `ResultFilterAttribute`
* `FormatFilterAttribute`
* `ServiceFilterAttribute`
* `TypeFilterAttribute`

`TypeFilterAttribute` and `ServiceFilterAttribute` are explained [later in this article](#dependency-injection).

## Filter scopes and order of execution

A filter can be added to the pipeline at one of three *scopes*. You can add a filter to a particular action method or to a controller class by using an attribute. Or you can register a filter globally for all controllers and actions. Filters are added globally by adding it to the `MvcOptions.Filters` collection in `ConfigureServices`:

[!code-csharp[](./filters/sample/src/FiltersSample/Startup.cs?name=snippet_ConfigureServices&highlight=5-8)]

### Default order of execution

When there are multiple filters for a particular stage of the pipeline, scope determines the default order of filter execution.  Global filters surround class filters, which in turn surround method filters. This is sometimes referred to as "Russian doll" nesting, as each increase in scope is wrapped around the previous scope, like a [nesting doll](https://wikipedia.org/wiki/Matryoshka_doll). You generally get the desired overriding behavior without having to explicitly determine ordering.

As a result of this nesting, the *after* code of filters runs in the reverse order of the *before* code. The sequence looks like this:

* The *before* code of filters applied globally
  * The *before* code of filters applied to controllers
    * The *before* code of filters applied to action methods
    * The *after* code of filters applied to action methods
  * The *after* code of filters applied to controllers
* The *after* code of filters applied globally
  
Here's an example that illustrates the order in which filter methods are called for synchronous Action filters.

| Sequence | Filter scope | Filter method |
|:--------:|:------------:|:-------------:|
| 1 | Global | `OnActionExecuting` |
| 2 | Controller | `OnActionExecuting` |
| 3 | Method | `OnActionExecuting` |
| 4 | Method | `OnActionExecuted` |
| 5 | Controller | `OnActionExecuted` |
| 6 | Global | `OnActionExecuted` |

This sequence shows:

* The method filter is nested within the controller filter.
* The controller filter is nested within the global filter. 

To put it another way, if you're inside an async filter's On*Stage*ExecutionAsync method, all of the filters with a tighter scope run while your code is on the stack.

> [!NOTE]
> 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:  `OnActionExecuting` is called before any of the filters, and `OnActionExecuted` is called after all of the filters.

### Overriding the default order

You can override the default sequence of execution by implementing `IOrderedFilter`. This interface exposes an `Order` property that takes precedence over scope to determine the order of execution. A filter with a lower `Order` value will have its *before* code executed before that of a filter with a higher value of `Order`. A filter with a lower `Order` value will have its *after* code executed after that of a filter with a higher `Order` value. 
You can set the `Order` property by using a constructor parameter:

```csharp
[MyFilter(Name = "Controller Level Attribute", Order=1)]
```

If you have the same 3 Action filters shown in the preceding example but set the `Order` property of the controller and global filters to 1 and 2 respectively, the order of execution would be reversed.

| Sequence | Filter scope | `Order` property | Filter method |
|:--------:|:------------:|:-----------------:|:-------------:|
| 1 | Method | 0 | `OnActionExecuting` |
| 2 | Controller | 1  | `OnActionExecuting` |
| 3 | Global | 2  | `OnActionExecuting` |
| 4 | Global | 2  | `OnActionExecuted` |
| 5 | Controller | 1  | `OnActionExecuted` |
| 6 | Method | 0  | `OnActionExecuted` |

The `Order` property trumps scope when determining the order in which filters will run. Filters are sorted first by order, then scope is used to break ties. All of the built-in filters implement `IOrderedFilter` and set the default `Order` value to 0. For built-in filters, scope determines order unless you set `Order` to a non-zero value.

## Cancellation and short circuiting

You can short-circuit the filter pipeline at any point by setting the `Result` property on the `context` parameter provided to the filter method. For instance, the following Resource filter prevents the rest of the pipeline from executing.

<a name="short-circuiting-resource-filter"></a>

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/ShortCircuitingResourceFilterAttribute.cs?highlight=12,13,14,15)]

In the following code, both the `ShortCircuitingResourceFilter` and the `AddHeader` filter target the `SomeResource` action method. The `ShortCircuitingResourceFilter`:

* Runs first, because it's a Resource Filter and `AddHeader` is an Action Filter.
* Short-circuits the rest of the pipeline.

Therefore 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. The `ShortCircuitingResourceFilter` runs first because of its filter type, or by explicit use of `Order` property.

[!code-csharp[](./filters/sample/src/FiltersSample/Controllers/SampleController.cs?name=snippet_AddHeader&highlight=1,9)]

## Dependency injection

Filters can be added by type or by instance. 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 [dependency injection](../../fundamentals/dependency-injection.md) (DI). Adding a filter by type is equivalent to `filters.Add(new TypeFilterAttribute(typeof(MyFilter)))`.

Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by [dependency injection](../../fundamentals/dependency-injection.md) (DI). This is because attributes must have their constructor parameters supplied where they're applied. This is a limitation of how attributes work.

If your filters have dependencies that you need to access from DI, there are several supported approaches. You can apply your filter to a class or action method using one of the following:

* `ServiceFilterAttribute`
* `TypeFilterAttribute`
* `IFilterFactory` implemented on your attribute

> [!NOTE]
> One dependency you might want to get from DI is a logger. However, avoid creating and using filters purely for logging purposes, since the [built-in framework logging features](xref:fundamentals/logging/index) may already provide what you need. If you're going to add logging to your filters, it should focus on business domain concerns or behavior specific to your filter, rather than MVC actions or other framework events.

### ServiceFilterAttribute

Service filter implementation types are registered in DI. A `ServiceFilterAttribute` retrieves an instance of the filter from DI. Add the `ServiceFilterAttribute` to the container in `ConfigureServices`, and reference it in a `ServiceFilterAttribute` attribute:

[!code-csharp[](./filters/sample/src/FiltersSample/Startup.cs?name=snippet_ConfigureServices&highlight=11)]

[!code-csharp[](../../mvc/controllers/filters/sample/src/FiltersSample/Controllers/HomeController.cs?name=snippet_ServiceFilter&highlight=1)]

When using `ServiceFilterAttribute`,  setting `IsReusable` is a hint that the filter instance *may* be reused outside of the request scope it was created within. The framework provides no guarantees that a single instance of the filter will be created or the filter will not be re-requested from the DI container at some later point. Avoid using `IsReusable` when using a filter that depends on services with a lifetime other than singleton.

Using `ServiceFilterAttribute` without registering the filter type results in an exception:

```
System.InvalidOperationException: No service for type
'FiltersSample.Filters.AddHeaderFilterWithDI' has been registered.
```

`ServiceFilterAttribute` implements `IFilterFactory`. `IFilterFactory` exposes the `CreateInstance` method for creating an `IFilterMetadata` instance. The `CreateInstance` method loads the specified type from the services container (DI).

### TypeFilterAttribute

`TypeFilterAttribute` is similar to `ServiceFilterAttribute`, but its type isn't resolved directly from the DI container. It instantiates the type by using `Microsoft.Extensions.DependencyInjection.ObjectFactory`.

Because of this difference:

* Types that are referenced using the `TypeFilterAttribute` don't need to be registered with the container first.  They do have their dependencies fulfilled by the container. 
* `TypeFilterAttribute` can optionally accept constructor arguments for the type.

When using `TypeFilterAttribute`, setting `IsReusable` is a hint that the filter instance *may* be reused outside of the request scope it was created within. The framework provides no guarantees that a single instance of the filter will be created. Avoid using `IsReusable` when using a filter that depends on services with a lifetime other than singleton.

The following example demonstrates how to pass arguments to a type using `TypeFilterAttribute`:

[!code-csharp[](../../mvc/controllers/filters/sample/src/FiltersSample/Controllers/HomeController.cs?name=snippet_TypeFilter&highlight=1,2)]

### IFilterFactory implemented on your attribute

If you have a filter that:

* Doesn't require any arguments.
* Has constructor dependencies that need to be filled by DI.

You can use your own named attribute on classes and methods instead of `[TypeFilter(typeof(FilterType))]`). The following filter shows how this can be implemented:

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/SampleActionFilterAttribute.cs?name=snippet_TypeFilterAttribute&highlight=1,3,7)]

This filter can be applied to classes or methods using the `[SampleActionFilter]` syntax, instead of having to use `[TypeFilter]` or `[ServiceFilter]`.

## Authorization filters

*Authorization filters:
* Control access to action methods.
* Are the first filters to be executed within the filter pipeline. 
* Have a before method, but no after method. 

You should only write a custom authorization filter if you are writing your own authorization framework. Prefer configuring your authorization policies or writing a custom authorization policy over writing a custom filter. The built-in filter implementation is just responsible for calling the authorization system.

You shouldn't throw exceptions within authorization filters, since nothing will handle the exception (exception filters won't handle them). Consider issuing a challenge when an exception occurs.

Learn more about [Authorization](../../security/authorization/index.md).

## Resource filters

* Implement either the `IResourceFilter` or `IAsyncResourceFilter` interface,
* Their execution wraps most of the filter pipeline. 
* Only [Authorization filters](#authorization-filters) run before Resource filters.

Resource filters are useful to short-circuit most of the work a request is doing. For example, a caching filter can avoid the rest of the pipeline if the response is in the cache.

The [short circuiting resource filter](#short-circuiting-resource-filter) shown earlier is one example of a resource filter. Another example is [DisableFormValueModelBindingAttribute](https://github.com/aspnet/Entropy/blob/rel/1.1.1/samples/Mvc.FileUpload/Filters/DisableFormValueModelBindingAttribute.cs):

* It prevents model binding from accessing the form data. 
* It's useful for large file uploads and want to prevent the form from being read into memory.

## Action filters

*Action filters*:

* Implement either the `IActionFilter` or `IAsyncActionFilter` interface.
* Their execution surrounds the execution of action methods.

Here's a sample action filter:

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/SampleActionFilter.cs?name=snippet_ActionFilter)]

The [ActionExecutingContext](/dotnet/api/microsoft.aspnetcore.mvc.filters.actionexecutingcontext) provides the following properties:

* `ActionArguments` - lets you manipulate the inputs to the action.
* `Controller` - lets you manipulate the controller instance. 
* `Result` - setting this short-circuits execution of the action method and subsequent action filters. Throwing an exception also prevents execution of the action method and subsequent filters, but is treated as a failure instead of a successful result.

The [ActionExecutedContext](/dotnet/api/microsoft.aspnetcore.mvc.filters.actionexecutedcontext) provides `Controller` and `Result` plus the following properties:

* `Canceled` - will be true if the action execution was short-circuited by another filter.
* `Exception` - will be non-null if the action or a subsequent action filter threw an exception. Setting this property to null effectively 'handles' an exception, and `Result` will be executed as if it were returned from the action method normally.

For an `IAsyncActionFilter`, a call to the `ActionExecutionDelegate`:

* Executes any subsequent action filters and the action method.
* returns `ActionExecutedContext`. 

To short-circuit, assign `ActionExecutingContext.Result` to some result instance and don't call the `ActionExecutionDelegate`.

The framework provides an abstract `ActionFilterAttribute` that you can subclass. 

You can use an action filter to validate model state and return any errors if the state is invalid:

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/ValidateModelAttribute.cs)]

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.
* `ActionExectedContext.Result` is executed as if it were returned normally from the action method.

## Exception filters

*Exception filters* implement either the `IExceptionFilter` or `IAsyncExceptionFilter` interface. They can be used to implement common error handling policies for an app. 

The following sample exception filter uses a custom developer error view to display details about exceptions that occur when the app is in development:

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/CustomExceptionFilterAttribute.cs?name=snippet_ExceptionFilter&highlight=1,14)]

Exception filters:

* Don't have before and after events. 
* Implement `OnException` or `OnExceptionAsync`. 
* Handle unhandled exceptions that occur in controller creation, [model binding](../models/model-binding.md), action filters, or action methods. 
* Do not catch exceptions that occur in Resource filters, Result filters, or MVC Result execution.

To handle an exception, set the `ExceptionContext.ExceptionHandled` property to true or write a response. This stops propagation of the exception. An Exception filter can't turn an exception into a "success". Only an Action filter can do that.

> [!NOTE]
> In ASP.NET Core 1.1, the response isn't sent if you set `ExceptionHandled` to true **and** write a response. In that scenario, ASP.NET Core 1.0 does send the response, and ASP.NET Core 1.1.2 will return to the 1.0 behavior. For more information, see [issue #5594](aspnet/Mvc#5594) in the GitHub repository. 

Exception filters:

* Are good for trapping exceptions that occur within MVC actions.
* Are not as flexible as error handling middleware. 

Prefer middleware for exception handling. Use exception filters only where you need to do error handling *differently* based on which MVC action was chosen. For example, your app might have action methods for both API endpoints and for views/HTML. The API endpoints could return error information as JSON, while the view-based actions could return an error page as HTML.

The `ExceptionFilterAttribute` can be subclassed. 

## Result filters

* Implement either the `IResultFilter` or `IAsyncResultFilter` interface.
* Their execution surrounds the execution of action results. 

Here's an example of a Result filter that adds an HTTP header.

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/LoggingAddHeaderFilter.cs?name=snippet_ResultFilter)]

The kind of result being executed depends on the action in question. An MVC action returning a view would include all razor processing as part of the `ViewResult` being executed. An API method might perform some serialization as part of the execution of the result. Learn more about [action results](actions.md)

Result filters are only executed for successful results - when the action or action filters produce an action result. Result filters are not executed when exception filters handle an exception.

The `OnResultExecuting` method can short-circuit execution of the action result and subsequent result filters by setting `ResultExecutingContext.Cancel` to true. You should generally write to the response object when short-circuiting to avoid generating an empty response. Throwing an exception will:

* Prevent execution of the action result and subsequent filters.
* Be treated as a failure instead of a successful result.

When the `OnResultExecuted` method runs, the response has likely been sent to the client and cannot be changed further (unless an exception was thrown). `ResultExecutedContext.Canceled` will be set to true if the action result execution was short-circuited by another filter.

`ResultExecutedContext.Exception` will be set to a non-null value if the action result or a subsequent result filter threw an exception. Setting `Exception` to null effectively 'handles' an exception and prevents the exception from being rethrown by MVC later in the pipeline. When you're handling an exception in a result filter, you might not be able to write any data to the response. If the action result throws partway through its execution, and the headers have already been flushed to the client, there's no reliable mechanism to send a failure code.

For an `IAsyncResultFilter` a call to `await next` on the `ResultExecutionDelegate` executes any subsequent result filters and the action result. To short-circuit, set `ResultExecutingContext.Cancel` to true and don't call the `ResultExectionDelegate`.

The framework provides an abstract `ResultFilterAttribute` that you can subclass. The [AddHeaderAttribute](#add-header-attribute) class shown earlier is an example of a result filter attribute.

## Using middleware in the filter pipeline

Resource filters work like [middleware](xref:fundamentals/middleware/index) in that they surround the execution of everything that comes later in the pipeline. But filters differ from middleware in that they're part of MVC, which means that they have access to MVC context and constructs.

In ASP.NET Core 1.1, you can use middleware in the filter pipeline. You might want to do that if you have a middleware component that needs access to MVC route data, or one that should run only for certain controllers or actions.

To use middleware as a filter, create a type with a `Configure` method that specifies the middleware that you want to inject into the filter pipeline. Here's an example that uses the localization middleware to establish the current culture for a request:

[!code-csharp[](./filters/sample/src/FiltersSample/Filters/LocalizationPipeline.cs?name=snippet_MiddlewareFilter&highlight=3,21)]

You can then use the `MiddlewareFilterAttribute` to run the middleware for a selected controller or action or globally:

[!code-csharp[](./filters/sample/src/FiltersSample/Controllers/HomeController.cs?name=snippet_MiddlewareFilter&highlight=2)]

Middleware filters run at the same stage of the filter pipeline as Resource filters, before model binding and after the rest of the pipeline.

## Next actions

To experiment with filters, [download, test and modify the sample](https://github.com/aspnet/Docs/tree/master/aspnetcore/mvc/controllers/filters/sample).
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants