Métodos de filtrado de Razor Pages de ASP.NET Core
Por Rick Anderson
Los filtros de Razor Page IPageFilter e IAsyncPageFilter permiten queRazor Pages ejecute código antes y después de que se haya ejecutado el controlador de una página de Razor. Los filtros de las páginas de Razor son similares a los filtros de acciones de ASP.NET Core MVC, salvo por el hecho de que no se pueden aplicar a métodos de control de páginas individuales.
Los filtros de páginas de Razor:
- 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.
- Ejecutan código antes de que se ejecute el método de controlador, después de que el enlace de modelos se haya completado.
- Ejecutan código después de que se haya ejecutado el método de controlador.
- Se pueden implementar en una página o globalmente.
- No se pueden usar con métodos de controlador de páginas específicas.
- Pueden tener dependencias de constructor rellenadas mediante la Inserción de dependencias (DI). Para obtener más información, vea ServiceFilterAttribute y TypeFilterAttribute.
Mientras que los constructores de páginas y el middleware permiten la ejecución de código personalizado antes de que se ejecute un método de control, solo los filtros de páginas de Razor permiten el acceso a HttpContext y a la página. El middleware tiene acceso a HttpContext
, pero no al "contexto de la página". Los filtros tienen un parámetro derivado FilterContext que proporciona acceso a HttpContext
. A continuación, se muestra un ejemplo de un filtro de página: Implemente un atributo de filtro que agregue un encabezado a la respuesta, lo cual que no es posible con constructores o con middleware. El acceso al contexto de la página, que incluye el acceso a las instancias de la página y a su modelo, solo está disponible cuando se ejecutan filtros, controladores o el cuerpo de una página de Razor.
Vea o descargue el código de ejemplo (cómo descargarlo)
Los filtros de páginas de Razor proporcionan los siguientes métodos, que se pueden aplicar globalmente o bien en el nivel de página:
Métodos sincrónicos:
- OnPageHandlerSelected: se llama a este método después de que se haya seleccionado un método de controlador, pero antes de que se produzca el enlace de modelos.
- OnPageHandlerExecuting: se llama a este método antes de que se ejecute el método de controlador, pero después de que el enlace de modelos se haya completado.
- OnPageHandlerExecuted: se llama a este método después de que se ejecute el método de controlador, pero antes de obtener el resultado de la acción.
Métodos asincrónicos:
- OnPageHandlerSelectionAsync: se llama a este método de forma asincrónica después de que se haya seleccionado un método de controlador, pero antes de que se produzca el enlace de modelos.
- OnPageHandlerExecutionAsync: se llama a este método de forma asincrónica antes de que se invoque el método de controlador, pero después de que el enlace de modelos se haya completado.
Implemente la versión sincrónica o la versión asincrónica de una interfaz de filtro, pero no ambas. El marco comprueba primero si el filtro implementa la interfaz asincrónica y, si es así, es a la interfaz que llama. De lo contrario, llamará a métodos de interfaz sincrónicos. Si se implementan ambas interfaces, solo se llamará a los métodos asincrónicos. 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.
Implementación de filtros de páginas de Razor globalmente
El siguiente código implementa IAsyncPageFilter
:
public class SampleAsyncPageFilter : IAsyncPageFilter
{
private readonly IConfiguration _config;
public SampleAsyncPageFilter(IConfiguration config)
{
_config = config;
}
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
var key = _config["UserAgentID"];
context.HttpContext.Request.Headers.TryGetValue("user-agent",
out StringValues value);
ProcessUserAgent.Write(context.ActionDescriptor.DisplayName,
"SampleAsyncPageFilter.OnPageHandlerSelectionAsync",
value, key.ToString());
return Task.CompletedTask;
}
public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context,
PageHandlerExecutionDelegate next)
{
// Do post work.
await next.Invoke();
}
}
En el código anterior, ProcessUserAgent.Write
es código proporcionado por el usuario que funciona con la cadena del agente de usuario.
El siguiente código habilita SampleAsyncPageFilter
en la clase Startup
:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.Filters.Add(new SampleAsyncPageFilter(Configuration));
});
}
El código siguiente llama a AddFolderApplicationModelConvention para aplicar SampleAsyncPageFilter
solo a las páginas en /Movies:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.Conventions.AddFolderApplicationModelConvention(
"/Movies",
model => model.Filters.Add(new SampleAsyncPageFilter(Configuration)));
});
}
El siguiente código implementa el método sincrónico IPageFilter
:
public class SamplePageFilter : IPageFilter
{
private readonly IConfiguration _config;
public SamplePageFilter(IConfiguration config)
{
_config = config;
}
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
{
var key = _config["UserAgentID"];
context.HttpContext.Request.Headers.TryGetValue("user-agent", out StringValues value);
ProcessUserAgent.Write(context.ActionDescriptor.DisplayName,
"SamplePageFilter.OnPageHandlerSelected",
value, key.ToString());
}
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
Debug.WriteLine("Global sync OnPageHandlerExecuting called.");
}
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
Debug.WriteLine("Global sync OnPageHandlerExecuted called.");
}
}
El siguiente código habilita SamplePageFilter
:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.Filters.Add(new SamplePageFilter(Configuration));
});
}
Implementación de filtros de páginas de Razor mediante la invalidación de métodos de filtro
El código siguiente invalida los filtros de páginas de Razor asincrónicos:
public class IndexModel : PageModel
{
private readonly IConfiguration _config;
public IndexModel(IConfiguration config)
{
_config = config;
}
public override Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
Debug.WriteLine("/IndexModel OnPageHandlerSelectionAsync");
return Task.CompletedTask;
}
public async override Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context,
PageHandlerExecutionDelegate next)
{
var key = _config["UserAgentID"];
context.HttpContext.Request.Headers.TryGetValue("user-agent", out StringValues value);
ProcessUserAgent.Write(context.ActionDescriptor.DisplayName,
"/IndexModel-OnPageHandlerExecutionAsync",
value, key.ToString());
await next.Invoke();
}
}
Implementar un atributo de filtro
Se pueden crear subclases del filtro OnResultExecutionAsync basado en atributos integrados. El siguiente filtro agrega un encabezado a la respuesta:
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
:
using Microsoft.AspNetCore.Mvc.RazorPages;
using PageFilter.Filters;
namespace PageFilter.Movies
{
[AddHeader("Author", "Rick")]
public class TestModel : PageModel
{
public void OnGet()
{
}
}
}
Para examinar los encabezados, use una herramienta como, por ejemplo, las herramientas de desarrollo del explorador. En Encabezados de respuesta, se muestra author: Rick
.
Vea Invalidación del orden predeterminado para obtener instrucciones sobre cómo invalidar el orden.
Vea Cancelación y cortocircuito para obtener instrucciones sobre cómo cortocircuitar la canalización de filtro de un filtro.
Atributo de filtro Authorize
El atributo Authorize se puede aplicar a un 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();
}
}
Por Rick Anderson
Los filtros de Razor Page IPageFilter e IAsyncPageFilter permiten queRazor Pages ejecute código antes y después de que se haya ejecutado el controlador de una página de Razor. Los filtros de las páginas de Razor son similares a los filtros de acciones de ASP.NET Core MVC, salvo por el hecho de que no se pueden aplicar a métodos de control de páginas individuales.
Los filtros de páginas de Razor:
- 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.
- Ejecutan código antes de que se ejecute el método de controlador, después de que el enlace de modelos se haya completado.
- Ejecutan código después de que se haya ejecutado el método de controlador.
- Se pueden implementar en una página o globalmente.
- No se pueden usar con métodos de controlador de páginas específicas.
Se puede ejecutar código antes de que un método de control se ejecute por medio del constructor de página o el middleware, pero solo los filtros de páginas de Razor tienen acceso a HttpContext. Los filtros tienen un parámetro derivado FilterContext que proporciona acceso a 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.
Vea o descargue el código de ejemplo (cómo descargarlo)
Los filtros de páginas de Razor proporcionan los siguientes métodos, que se pueden aplicar globalmente o bien en el nivel de página:
Métodos sincrónicos:
- OnPageHandlerSelected: se llama a este método después de que se haya seleccionado un método de controlador, pero antes de que se produzca el enlace de modelos.
- OnPageHandlerExecuting: se llama a este método antes de que se ejecute el método de controlador, pero después de que el enlace de modelos se haya completado.
- OnPageHandlerExecuted: se llama a este método después de que se ejecute el método de controlador, pero antes de obtener el resultado de la acción.
Métodos asincrónicos:
- OnPageHandlerSelectionAsync: se llama a este método de forma asincrónica después de que se haya seleccionado un método de controlador, pero antes de que se produzca el enlace de modelos.
- OnPageHandlerExecutionAsync: se llama a este método de forma asincrónica antes de que se invoque el método de controlador, después de que el enlace de modelos se haya completado.
Nota
Implemente la versión sincrónica o la versión asincrónica de una interfaz de filtro, pero no ambas. El marco comprueba primero si el filtro implementa la interfaz asincrónica y, si es así, es a la interfaz que llama. De lo contrario, llamará a métodos de interfaz sincrónicos. Si se implementan ambas interfaces, solo se llamará a los métodos asincrónicos. 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.
Implementación de filtros de páginas de Razor globalmente
El siguiente código implementa 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; se usa para proporcionar información de seguimiento relativa a la aplicación.
El siguiente código habilita SampleAsyncPageFilter
en la clase Startup
:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new SampleAsyncPageFilter(_logger));
});
}
El siguiente código muestra la clase Startup
completa:
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:
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
:
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
:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new SamplePageFilter(_logger));
});
}
Implementación de filtros de páginas de Razor mediante la invalidación de métodos de filtro
El código siguiente invalida los filtros de páginas de Razor sincrónicos:
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 filtro
Se pueden crear subclases del filtro OnResultExecutionAsync basado en atributos integrados. El siguiente filtro agrega un encabezado a la respuesta:
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
:
[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.
Vea Cancelación y cortocircuito para obtener instrucciones sobre cómo cortocircuitar la canalización de filtro de un filtro.
Atributo de filtro Authorize
El atributo Authorize se puede aplicar a un 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();
}
}
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de