Métodos de filtrado de páginas de Razor en ASP.NET CoreFilter methods for Razor Pages in ASP.NET Core

Por Rick AndersonBy Rick Anderson

Los filtros de páginas de Razor IPageFilter e IAsyncPageFilter permiten que las páginas de Razor ejecuten código antes y después de que se haya ejecutado un controlador de páginas de Razor.Razor Page filters IPageFilter and IAsyncPageFilter allow Razor Pages to run code before and after a Razor Page handler is run. Estos filtros son similares a los filtros de acción de ASP.NET Core MVC, salvo por el hecho de que no se pueden usar con métodos de controlador de páginas individuales.Razor Page filters are similar to ASP.NET Core MVC action filters, except they can't be applied to individual page handler methods.

Los filtros de páginas de Razor:Razor Page filters:

  • Ejecutan código después de que se haya seleccionado un método de controlador, pero antes de que el enlace de modelos tenga lugar.Run code after a handler method has been selected, but before model binding occurs.
  • Ejecutan código antes de que se ejecute el método de controlador, después de que el enlace de modelos se haya completado.Run code before the handler method executes, after model binding is complete.
  • Ejecutan código después de que se haya ejecutado el método de controlador.Run code after the handler method executes.
  • Se pueden implementar en una página o globalmente.Can be implemented on a page or globally.
  • No se pueden usar con métodos de controlador de páginas específicas.Cannot be applied to specific page handler methods.

Se puede ejecutar código antes de que un método de controlador se ejecute por medio del constructor de página o de middleware, pero solo los filtros de páginas de Razor tienen acceso a HttpContext.Code can be run before a handler method executes using the page constructor or middleware, but only Razor Page filters have access to HttpContext. Los filtros tienen un parámetro derivado FilterContext que concede acceso a HttpContext.Filters have a FilterContext derived parameter, which provides access to HttpContext. Por ejemplo, en el ejemplo Implementar un atributo de filtro se agrega un encabezado a la respuesta, cosa que no es posible con constructores o con middleware.For example, the Implement a filter attribute sample adds a header to the response, something that can't be done with constructors or middleware.

Vea o descargue el código de ejemplo (cómo descargarlo)View or download sample code (how to download)

Los filtros de páginas de Razor proporcionan los siguientes métodos, que se pueden usar globalmente o bien en el nivel de página:Razor Page filters provide the following methods, which can be applied globally or at the page level:

  • Métodos sincrónicos:Synchronous methods:

    • OnPageHandlerSelected : Se llama después de que se ha seleccionado un método de controlador, pero antes de modelo se produce el enlace.OnPageHandlerSelected : Called after a handler method has been selected, but before model binding occurs.
    • OnPageHandlerExecuting : Se llama antes de que se ejecuta el método de controlador, una vez completado el enlace de modelos.OnPageHandlerExecuting : Called before the handler method executes, after model binding is complete.
    • OnPageHandlerExecuted : Llamado cuando se ejecuta el método de controlador, antes de resultado de la acción.OnPageHandlerExecuted : Called after the handler method executes, before the action result.
  • Métodos asincrónicos:Asynchronous methods:

    • OnPageHandlerSelectionAsync : Llamar de forma asincrónica una vez que se ha seleccionado el método de controlador, pero antes de que se produce el enlace de modelos.OnPageHandlerSelectionAsync : Called asynchronously after the handler method has been selected, but before model binding occurs.
    • OnPageHandlerExecutionAsync : Se llama asincrónicamente antes de invoca el método de controlador, una vez completado el enlace de modelos.OnPageHandlerExecutionAsync : Called asynchronously before the handler method is invoked, after model binding is complete.

Nota

Implemente la versión sincrónica o la versión asincrónica de una interfaz de filtro, pero no ambas.Implement either the synchronous or the async version of a filter interface, not both. El marco comprueba primero si el filtro implementa la interfaz asincrónica y, si es así, es a la interfaz que llama.The framework checks first to see if the filter implements the async interface, and if so, it calls that. De lo contrario, llamará a métodos de interfaz sincrónicos.If not, it calls the synchronous interface's method(s). Si se implementan ambas interfaces, solo se llamará a los métodos asincrónicos.If both interfaces are implemented, only the async methods are be called. La misma regla se cumple con las invalidaciones en páginas: implemente la versión sincrónica o asincrónica de la invalidación, pero no ambas.The same rule applies to overrides in pages, implement the synchronous or the async version of the override, not both.

Implementar filtros de páginas de Razor globalmenteImplement Razor Page filters globally

El siguiente código implementa IAsyncPageFilter:The following code implements IAsyncPageFilter:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace PageFilter.Filters
{
    public class SampleAsyncPageFilter : IAsyncPageFilter
    {
        private readonly ILogger _logger;

        public SampleAsyncPageFilter(ILogger logger)
        {
            _logger = logger;
        }

        public async Task OnPageHandlerSelectionAsync(
                                            PageHandlerSelectedContext context)
        {
            _logger.LogDebug("Global OnPageHandlerSelectionAsync called.");
            await Task.CompletedTask;
        }

        public async Task OnPageHandlerExecutionAsync(
                                            PageHandlerExecutingContext context,
                                            PageHandlerExecutionDelegate next)
        {
            _logger.LogDebug("Global OnPageHandlerExecutionAsync called.");
            await next.Invoke();
        }
    }
}

En el código anterior, ILogger no es necesario;In the preceding code, ILogger is not required. se usa para proporcionar información de seguimiento relativa a la aplicación.It's used in the sample to provide trace information for the application.

El siguiente código habilita SampleAsyncPageFilter en la clase Startup:The following code enables the SampleAsyncPageFilter in the Startup class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new SampleAsyncPageFilter(_logger));
    });
}

El siguiente código muestra la clase Startup completa:The following code shows the complete Startup class:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PageFilter.Filters;

namespace PageFilter
{
    public class Startup
    {
        ILogger _logger;
        public Startup(ILoggerFactory loggerFactory, IConfiguration configuration)
        {
            _logger = loggerFactory.CreateLogger<GlobalFiltersLogger>();
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(options =>
            {
                options.Filters.Add(new SampleAsyncPageFilter(_logger));
            });
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc();
        }
    }
}

El siguiente código llama a AddFolderApplicationModelConvention para aplicar SampleAsyncPageFilter solo a las páginas en /subFolder:The following code calls AddFolderApplicationModelConvention to apply the SampleAsyncPageFilter to only pages in /subFolder:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
       .AddRazorPagesOptions(options =>
       {
           options.Conventions.AddFolderApplicationModelConvention(
               "/subFolder",
               model => model.Filters.Add(new SampleAsyncPageFilter(_logger)));
       });
}

El siguiente código implementa el método sincrónico IPageFilter:The following code implements the synchronous IPageFilter:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;

namespace PageFilter.Filters
{
    public class SamplePageFilter : IPageFilter
    {
        private readonly ILogger _logger;

        public SamplePageFilter(ILogger logger)
        {
            _logger = logger;
        }

        public void OnPageHandlerSelected(PageHandlerSelectedContext context)
        {
            _logger.LogDebug("Global sync OnPageHandlerSelected called.");
        }

        public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
        {
            _logger.LogDebug("Global sync PageHandlerExecutingContext called.");
        }

        public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
        {
            _logger.LogDebug("Global sync OnPageHandlerExecuted called.");
        }
    }
}

El siguiente código habilita SamplePageFilter:The following code enables the SamplePageFilter:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new SamplePageFilter(_logger));
    });
}

Implementar filtros de páginas de Razor invalidando métodos de filtroImplement Razor Page filters by overriding filter methods

El siguiente código invalida los filtros de páginas de Razor sincrónicos:The following code overrides the synchronous Razor Page filters:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace PageFilter.Pages
{
    public class IndexModel : PageModel
    {
        private readonly ILogger _logger;

        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }
        public string Message { get; set; }

        public void OnGet()
        {
            _logger.LogDebug("IndexModel/OnGet");
        }
        
        public override void OnPageHandlerSelected(
                                    PageHandlerSelectedContext context)
        {
            _logger.LogDebug("IndexModel/OnPageHandlerSelected");          
        }

        public override void OnPageHandlerExecuting(
                                    PageHandlerExecutingContext context)
        {
            Message = "Message set in handler executing";
            _logger.LogDebug("IndexModel/OnPageHandlerExecuting");
        }


        public override void OnPageHandlerExecuted(
                                    PageHandlerExecutedContext context)
        {
            _logger.LogDebug("IndexModel/OnPageHandlerExecuted");
        }
    }
}

Implementar un atributo de filtroImplement a filter attribute

El filtro basado en atributos integrado OnResultExecutionAsync puede ser una subclase.The built-in attribute-based filter OnResultExecutionAsync filter can be subclassed. El siguiente filtro agrega un encabezado a la respuesta:The following filter adds a header to the response:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;

namespace PageFilter.Filters
{
    public class AddHeaderAttribute  : ResultFilterAttribute
    {
        private readonly string _name;
        private readonly string _value;

        public AddHeaderAttribute (string name, string value)
        {
            _name = name;
            _value = value;
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(_name, new string[] { _value });
        }
    }
}

El siguiente código se aplica al atributo AddHeader:The following code applies the AddHeader attribute:

[AddHeader("Author", "Rick")]
public class ContactModel : PageModel
{
    private readonly ILogger _logger;

    public ContactModel(ILogger<ContactModel> logger)
    {
        _logger = logger;
    }
    public string Message { get; set; }

    public async Task OnGetAsync()
    {
        Message = "Your contact page.";
        _logger.LogDebug("Contact/OnGet");
        await Task.CompletedTask;
    }
}

Vea Invalidación del orden predeterminado para obtener instrucciones sobre cómo invalidar el orden.See Overriding the default order for instructions on overriding the order.

Vea Cancelación y cortocircuito para obtener instrucciones sobre cómo cortocircuitar la canalización de filtro de un filtro.See Cancellation and short circuiting for instructions to short-circuit the filter pipeline from a filter.

Atributo de filtro AuthorizeAuthorize filter attribute

El atributo Authorize se puede aplicar a un PageModel:The Authorize attribute can be applied to a PageModel:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace PageFilter.Pages
{
    [Authorize]
    public class ModelWithAuthFilterModel : PageModel
    {
        public IActionResult OnGet() => Page();
    }
}