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

Autor: Rick Anderson

RazorFiltry stránek a IAsyncPageFilter umožňují stránkám IPageFilter spouštět kód před a po spuštění obslužné rutiny RazorRazor stránky. Razor Filtry stránek se podobají ASP.NET základním filtrům akcí MVC, ale nedají se použít u jednotlivých metod obslužné rutiny stránky.

Razor Filtry stránek:

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

Zatímco konstruktory stránek a middleware umožňují spouštění vlastního kódu před spuštěním metody obslužné rutiny, pouze Razor filtry stránky umožňují přístup k HttpContext a stránce. Middleware má přístup k objektu HttpContext, ale ne k kontextu stránky. Filtry mají odvozený FilterContext parametr, který poskytuje přístup k HttpContext. Tady je ukázka filtru stránky: Implementujte atribut filtru, který přidá hlavičku do odpovědi, něco, co nelze provést s konstruktory nebo middlewarem. Přístup k kontextu stránky, který zahrnuje přístup k instancím stránky a jeho modelu, jsou 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 (postup stažení)

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

  • Synchronní metody:

  • Asynchronní metody:

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

Globální implementace Razor 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 zadaný kód, ProcessUserAgent.Write který funguje s řetězcem uživatelského agenta.

Následující kód umožňuje SampleAsyncPageFilter ve Startup třídě:

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

Následující volání AddFolderApplicationModelConvention kódu, která se použijí SampleAsyncPageFilter pouze na stránky / 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ánky přepsáním metod filtru

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

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 filtru OnResultExecutionAsync založený na atributech může být podtříděn. Následující filtr přidá hlavičku do odpovědi:

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, například vývojářské nástroje prohlížeče. V části Hlavičkyauthor: Rick odpovědi se zobrazí.

Pokyny k přepsání objednávky najdete v části Přepsání výchozího pořadí .

Pokyny ke zkratování kanálu filtru z filtru najdete v tématu Zrušení a zkratování .

Autorizace atributu filtru

Atribut Authorize lze 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

RazorFiltry stránek a IAsyncPageFilter umožňují stránkám IPageFilter spouštět kód před a po spuštění obslužné rutiny RazorRazor stránky. Razor Filtry stránek se podobají ASP.NET základním filtrům akcí MVC, ale nedají se použít u jednotlivých metod obslužné rutiny stránky.

Razor Filtry stránek:

  • Spusťte kód po výběru metody obslužné rutiny, ale před vytvořením vazby modelu.
  • Po dokončení vazby modelu spusťte kód před spuštěním metody obslužné rutiny.
  • Spusťte kód po spuštění metody obslužné rutiny.
  • Dá se implementovat na stránce nebo globálně.
  • Nelze použít pro konkrétní metody obslužné rutiny stránky.

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

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

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

  • Synchronní metody:

  • Asynchronní metody:

Poznámka

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

Globální implementace Razor 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 ILogger se nevyžaduje. Používá se v ukázce k poskytnutí informací o trasování aplikace.

Následující kód umožňuje SampleAsyncPageFilter ve Startup třídě:

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í AddFolderApplicationModelConvention kódu, která použijí SampleAsyncPageFilter pouze stránky v /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ánky přepsáním metod filtru

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

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 filtru OnResultExecutionAsync založený na atributech může být podtříděn. Následující filtr přidá hlavičku do odpovědi:

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í objednávky najdete v části Přepsání výchozího pořadí .

Pokyny ke zkratování kanálu filtru z filtru najdete v tématu Zrušení a zkratování .

Autorizace atributu filtru

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