Search code examples
c#asp.netasp.net-coreasp.net-identity

Scaffold Identity UI in ASP.NET Core 2.1 and add Global Filter


I have a ASP.NET Core 2.1 application in which I am using Identity scaffolding as explained over here

Now I have a Global Filter for OnActionExecuting

public class SmartActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        ...
    }
}

And in startup.cs I configured filter as below

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc(options =>
        {
            options.Filters.Add(new AddHeaderAttribute("Author", "HaBo")); // an instance
            options.Filters.Add(typeof(SmartActionFilter)); // by type
            // options.Filters.Add(new SampleGlobalActionFilter()); // an instance
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddJsonOptions(options =>
        {
            options.SerializerSettings.ContractResolver = new DefaultContractResolver();
            options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        });
}

This Filter get used across all action methods but not for the one's in Identity Area. How can I have global filter work for all pages in Identity Area?


Solution

  • Within the opening paragraph of Filters in ASP.NET Core, you'll see the following note:

    Important

    This topic does not apply to Razor Pages. ASP.NET Core 2.1 and later supports IPageFilter and IAsyncPageFilter for Razor Pages. For more information, see Filter methods for Razor Pages.

    This explains why your SmartActionFilter implementation is only executing for actions and not for page handlers. Instead, you should implement IPageFilter or IAsyncPageFilter as suggested in the note:

    public class SmartActionFilter : IPageFilter
    {
        public void OnPageHandlerSelected(PageHandlerSelectedContext ctx) { }
    
        public void OnPageHandlerExecuting(PageHandlerExecutingContext ctx)
        {
            // Your logic here.
        }
    
        public void OnPageHandlerExecuted(PageHandlerExecutedContext ctx)
        {
            // Example requested in comments on answer.
            if (ctx.Result is PageResult pageResult)
            {
                pageResult.ViewData["Property"] = "Value";
            }
    
            // Another example requested in comments.
            // This can also be done in OnPageHandlerExecuting to short-circuit the response.
            ctx.Result = new RedirectResult("/url/to/redirect/to");
        }
    }
    

    Registering SmartActionFilter is still done in the same way as shown in your question (using MvcOptions.Filters).

    If you want to run this for both actions and page handlers, it looks like you might need to implement both IActionFilter and IPageFilter.