共用方式為


ASP.NET Core 中頁面的篩選方法Razor

作者:Rick Anderson

Razor 頁面篩選器 IPageFilter 允許 IAsyncPageFilterRazor 頁面在執行頁面處理程序 Razor 的之前和之後運行程式碼。 Razor 頁面篩選條件類似於 ASP.NET Core MVC 動作篩選,但無法套用至個別頁面處理程式方法。

Razor 頁面篩選:

  • 在選取處理程式方法之後執行程序代碼,但在模型系結發生之前。
  • 在完成模型系結後,於執行處理程序方法之前執行代碼。
  • 執行處理程式方法之後執行程序代碼。
  • 可以在頁面上或全域實作。
  • 無法套用至特定的頁面處理程式方法。
  • 可透過相依性注入 (DI) 來填入建構函式的相依性。 如需詳細資訊,請參閱 ServiceFilterAttributeTypeFilterAttribute

雖然頁面構造器和中介軟體允許在處理程式方法執行之前執行自訂程式碼,但只有 Razor 頁面篩選器能夠存取 HttpContext 和頁面。 中間件可以存取HttpContext ,但無法存取「頁面上下文」。 篩選條件具有 FilterContext 衍生參數,可提供 存取 HttpContext權。 以下是頁面篩選的範例: 實作篩選屬性 ,將標頭新增至回應,這是建構函式或中間件無法完成的工作。 頁面內容的存取權,包括頁面實例及其模型的存取權,只有在執行篩選、處理程式或頁面主體 Razor 時才能使用。

檢視或下載範例程式代碼如何下載

Razor 頁面篩選提供下列方法,可全域或頁面層級套用:

  • 同步方法:

  • 非同步方法:

請實作同步非同步版本的篩選介面,但避免同時實作兩者。 架構會先檢查,以查看篩選是否實作異步介面,如果是,則會呼叫該介面。 若不行,則呼叫同步介面的方法。 如果實作這兩個介面,則只會呼叫異步方法。 相同的規則適用於頁面中的覆寫,您應選擇實作同步或異步版本的覆寫,而不是兩者兼具。

全域實作 Razor 頁面篩選

下列程式代碼會實作 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();
    }
}

在上述程式代碼中, ProcessUserAgent.Write 是使用者提供的程序代碼,可搭配使用者代理程式字串使用。

下列程式碼會在SampleAsyncPageFilter類別中啟用Startup

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

下列程式代碼會呼叫 AddFolderApplicationModelConvention ,將 套用 SampleAsyncPageFilter/Movies 中唯一的頁面:

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

下列程式碼實作了同步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.");
    }
}

下列程式代碼會啟用 SamplePageFilter

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

實作Razor頁面篩選功能,藉由覆寫篩選方法

下列程式代碼會覆寫異步 Razor 的Page篩選:

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

實作篩選屬性

內建屬性型篩選 OnResultExecutionAsync 條件可以子類別化。 下列篩選條件會將標頭新增至回應:

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

下列程式碼會套用 AddHeader 屬性:

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

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

        }
    }
}

使用瀏覽器開發人員工具之類的工具來檢查標頭。 回應標頭底下會顯示 author: Rick

如需有關覆寫順序的指示,請參閱覆寫預設順序

如需在篩選器中短路篩選管線的指示,請參閱 取消和短路

授權篩選屬性

Authorize 屬性可以套用至 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();
    }
}

作者:Rick Anderson

Razor 頁面篩選器 IPageFilter 允許 IAsyncPageFilterRazor 頁面在執行頁面處理程序 Razor 的之前和之後運行程式碼。 Razor 頁面篩選條件類似於 ASP.NET Core MVC 動作篩選,但無法套用至個別頁面處理程式方法。

Razor 頁面篩選:

  • 在選取處理程式方法之後執行程序代碼,但在模型系結發生之前。
  • 在完成模型系結後,於執行處理程序方法之前執行代碼。
  • 執行處理程式方法之後執行程序代碼。
  • 可以在頁面上或全域實作。
  • 無法套用至特定的頁面處理程式方法。

程式代碼可以在處理程式方法使用頁面建構函式或中間件執行之前執行,但只有 Razor Page篩選條件可以存取 HttpContext。 篩選條件具有 FilterContext 衍生參數,可提供 存取 HttpContext權。 例如,實作 篩選屬性 範例會將標頭新增至回應,這是建構函式或中間件無法完成的工作。

檢視或下載範例程式代碼如何下載

Razor 頁面篩選提供下列方法,可全域或頁面層級套用:

  • 同步方法:

  • 非同步方法:

Note

請僅實作篩選介面的同步版本或異步版本,切勿同時實作兩者。 架構會先檢查,以查看篩選是否實作異步介面,如果是,則會呼叫該介面。 若不行,則呼叫同步介面的方法。 如果實作這兩個介面,則只會呼叫異步方法。 相同的規則適用於頁面中的覆寫,您應選擇實作同步或異步版本的覆寫,而不是兩者兼具。

全域實作 Razor 頁面篩選

下列程式代碼會實作 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();
        }
    }
}

在上述程式代碼中, ILogger 不需要 。 在範例中,這是用來提供應用程式的追蹤資訊。

下列程式碼會在SampleAsyncPageFilter類別中啟用Startup

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

下列程式代碼顯示完整的 Startup 類別:

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

下列程式代碼會呼叫 AddFolderApplicationModelConvention ,將 套用 SampleAsyncPageFilter/subFolder 中唯一的頁面:

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

下列程式碼實作了同步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.");
        }
    }
}

下列程式代碼會啟用 SamplePageFilter

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

實作Razor頁面篩選功能,藉由覆寫篩選方法

下列程式代碼會覆寫同步 Razor 頁面篩選:

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

實作篩選屬性

內建屬性型篩選 OnResultExecutionAsync 條件可以子類別化。 下列篩選條件會將標頭新增至回應:

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

下列程式碼會套用 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;
    }
}

如需有關覆寫順序的指示,請參閱覆寫預設順序

如需在篩選器中短路篩選管線的指示,請參閱 取消和短路

授權篩選屬性

Authorize 屬性可以套用至 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();
    }
}