Metody filtrování pro Razor stránky v ASP.NET Core

Autor: Rick Anderson

Razor Filtry stránek IPageFilter a IAsyncPageFilter umožňují Pages spouštět kód před a po spuštění Razor obslužné rutiny Razor Page. RazorFiltry stránek se podobají ASP.NET Core akcí MVCs tím rozdílem, že je nelze použít u jednotlivých metod obslužné rutiny stránky.

Razor Filtry stránek:

  • Po výběru metody obslužné rutiny spusťte kód, ale před vytvořením vazby modelu.
  • Po dokončení vazby modelu spusťte kód před provedením metody obslužné rutiny.
  • Po provedení metody obslužné rutiny spusťte kód.
  • Je možné implementovat na stránce nebo globálně.
  • Nelze použít u konkrétních metod obslužné rutiny stránky.
  • Může mít závislosti konstruktoru naplněné injektáží závislostí (DI). Další informace najdete v tématu ServiceFilterAttribute a TypeFilterAttribute.

Zatímco konstruktory stránek a middleware umožňují spouštění vlastního kódu před provedením metody obslužné rutiny, přístup k a stránce povoluje pouze filtry Razor HttpContext stránky. Middleware má přístup k HttpContext , ale ne ke kontextu stránky. Filtry mají FilterContext odvozený parametr, který poskytuje přístup k HttpContext . Tady je ukázka filtru stránky: Implementujte atribut filtru, který do odpovědi přidá hlavičku , něco, co nelze provést pomocí konstruktorů nebo middlewaru. Přístup k kontextu stránky, který zahrnuje přístup k instancím stránky a jeho modelu, je k dispozici pouze při provádění filtrů, obslužných rutin nebo textu Razor stránky.

Zobrazení nebo stažení ukázkového kódu (stažení)

Razor Filtry stránek poskytují následující metody, které je možné použít globálně nebo na úrovni stránky:

Implementujte synchronní nebo asynchronní verzi rozhraní filtru, nikoli obojí. Rozhraní nejprve zkontroluje, jestli filtr implementuje asynchronní rozhraní, a pokud ano, volá to. Pokud ne, volá metody synchronního rozhraní. Pokud jsou implementována obě rozhraní, jsou volány pouze asynchronní metody. Stejné pravidlo platí pro přepsání na stránkách, implementuje synchronní nebo asynchronní verzi přepsání, nikoli obojí.

Globální Razor implementace filtrů stránek

Následující kód implementuje 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();
    }
}

V předchozím kódu je uživatelem zadaný ProcessUserAgent.Write kód, který funguje s řetězcem uživatelského agenta.

Následující kód povolí ve SampleAsyncPageFilter třídě Startup :

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.Filters.Add(new SampleAsyncPageFilter(Configuration));
        });
}

Následující volání kódu AddFolderApplicationModelConvention pro použití na pouze stránky v SampleAsyncPageFilter /Movies:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages(options =>
    {
        options.Conventions.AddFolderApplicationModelConvention(
            "/Movies",
            model => model.Filters.Add(new SampleAsyncPageFilter(Configuration)));
    });
}

Následující kód implementuje synchronní 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.");
    }
}

Následující kód povolí SamplePageFilter :

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.Filters.Add(new SamplePageFilter(Configuration));
        });
}

Implementace Razor filtrů stránek přepsáním metod filtrování

Následující kód přepíše asynchronní Razor filtry stránky:

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();
    }
}

Implementace atributu filtru

Předdefinovaný filtr založený na OnResultExecutionAsync atributech může být podtřídou. Následující filtr přidá do odpovědi hlavičku:

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 });
        }
    }
}

Následující kód použije AddHeader atribut :

using Microsoft.AspNetCore.Mvc.RazorPages;
using PageFilter.Filters;

namespace PageFilter.Movies
{
    [AddHeader("Author", "Rick")]
    public class TestModel : PageModel
    {
        public void OnGet()
        {

        }
    }
}

K prozkoumání hlaviček použijte nástroj, jako jsou vývojářské nástroje prohlížeče. V části Hlavičky odpovědi se zobrazí author: Rick .

Pokyny k přepsání pořadí najdete v tématu Přepsání výchozího pořadí.

Pokyny ke zkrácení kanálu filtru z filtru najdete v tématu Zrušení a krátký okruh.

Autorizovat atribut filtru

Atribut Authorize je možné použít na 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();
    }
}

Autor: Rick Anderson

Razor Filtry stránek IPageFilter a IAsyncPageFilter umožňují Pages spouštět kód před a po spuštění Razor obslužné rutiny Razor Page. RazorFiltry stránek se podobají ASP.NET Core akcí MVCs tím rozdílem, že je nelze použít u jednotlivých metod obslužné rutiny stránky.

Razor Filtry stránek:

  • Po výběru metody obslužné rutiny spusťte kód, ale před vytvořením vazby modelu.
  • Po dokončení vazby modelu spusťte kód před provedením metody obslužné rutiny.
  • Po provedení metody obslužné rutiny spusťte kód.
  • Je možné implementovat na stránce nebo globálně.
  • Nelze použít u konkrétních metod obslužné rutiny stránky.

Kód lze spustit před provedením metody obslužné rutiny pomocí konstruktoru stránky nebo middlewaru, ale k objektu HttpContext mají přístup pouze filtry Razor stránky. Filtry mají odvozený parametr FilterContext, který poskytuje přístup k HttpContext . Například ukázka Implementace atributu filtru přidá do odpovědi hlavičku , něco, co nelze provést pomocí konstruktorů nebo middlewaru.

Zobrazení nebo stažení ukázkového kódu (stažení)

Razor Filtry stránek poskytují následující metody, které je možné použít globálně nebo na úrovni stránky:

Poznámka

Implementujte synchronní nebo asynchronní verzi rozhraní filtru, nikoli obojí. Rozhraní nejprve zkontroluje, jestli filtr implementuje asynchronní rozhraní, a pokud ano, volá to. Pokud ne, volá metody synchronního rozhraní. Pokud jsou implementována obě rozhraní, jsou volány pouze asynchronní metody. Stejné pravidlo platí pro přepsání na stránkách, implementuje synchronní nebo asynchronní verzi přepsání, nikoli obojí.

Globální Razor implementace filtrů stránek

Následující kód implementuje 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();
        }
    }
}

V předchozím kódu není protokolovací nástroj ILogger vyžadován. Používá se v ukázce k poskytnutí informací o trasování pro aplikaci.

Následující kód povolí ve SampleAsyncPageFilter třídě Startup :

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

Následující kód ukazuje úplnou Startup třídu:

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();
        }
    }
}

Následující volání kódu AddFolderApplicationModelConvention pro použití na pouze stránky v SampleAsyncPageFilter /subFolder:

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

Následující kód implementuje synchronní 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.");
        }
    }
}

Následující kód povolí SamplePageFilter :

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

Implementace Razor filtrů stránek přepsáním metod filtrování

Následující kód přepíše synchronní Razor filtry stránky:

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");
        }
    }
}

Implementace atributu filtru

Předdefinovaný filtr založený na atributech OnResultExecutionAsync může být podtřídou. Následující filtr přidá do odpovědi hlavičku:

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 });
        }
    }
}

Následující kód použije AddHeader atribut :

[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;
    }
}

Pokyny k přepsání pořadí najdete v tématu Přepsání výchozího pořadí.

Pokyny ke zkrácení kanálu filtru z filtru najdete v tématu Zrušení a krátký okruh.

Autorizovat atribut filtru

Atribut Authorize je možné použít na 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();
    }
}