A result filter is an ASP.NET Core MVC filter that runs around action-result execution. It can inspect or replace the result before response generation, then observe the completed response afterward. Result filters occupy the final stage after authorization, resource, action, or page filters. section 30.4.5 section 30.8
Choose the interface according to the behavior required:
- Use an always-run interface when the filter must execute after another filter short-circuits the pipeline or an exception occurs. section 30.4.5
Conditional diagnostics
A ResultDiagnosticsAttribute checks for a diag query parameter, gathers the result type, and replaces the endpoint output with diagnostic information. Apply it to HomeController, then request an endpoint with ?diag to observe the altered response.
Result filters can be applied globally, to controllers or page models, or to individual actions. By default, global filters run before controller-scoped filters, which run before action-scoped filters. Implement IOrderedFilter when explicit ordering is needed; lower Order values run first. section 30.7
Listing 30.28 The contents of the ResultDiagnosticsAttribute.cs file in the Filters folder
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
namespace WebApp.Filters {
public class ResultDiagnosticsAttribute :
Attribute, IAsyncResultFilter {
public async Task OnResultExecutionAsync(
ResultExecutingContext context,
ResultExecutionDelegate next) {
if (context.HttpContext.Request.Query.ContainsKey("diag")) {
Dictionary<string, string?> diagData =
new Dictionary<string, string?> {
{"Result type", context.Result.GetType().Name }
};
if (context.Result is ViewResult vr) {
diagData["View Name"] = vr.ViewName;
diagData["Model Type"]
= vr.ViewData?.Model?.GetType().Name;
diagData["Model Data"]
= vr.ViewData?.Model?.ToString();
} else if (context.Result is PageResult pr) {
diagData["Model Type"] = pr.Model.GetType().Name;
diagData["Model Data"]
= pr.ViewData?.Model?.ToString();
}
context.Result = new ViewResult() {
ViewName = "/Views/Shared/Message.cshtml",
ViewData = new ViewDataDictionary(
new EmptyModelMetadataProvider(),
new ModelStateDictionary()) {
Model = diagData
}
};
}
await next();
}
}
}
Inspect the asynchronous diagnostic-filter implementation, including query inspection, result typing, and response replacement. section 30.4.5

