Filtry v ASP.NET Core

Od Uce Polakina, Ricka Andersona, Toma Dykstraa Steva Smithe

Filtry ASP.NET Core umožňují spuštění kódu před nebo po konkrétních fázích kanálu zpracování požadavků.

Integrované filtry zvládí například tyto úlohy:

  • Autorizace bránící přístupu k prostředkům, ke které uživatel nemá oprávnění.
  • Ukládání odpovědí do mezipaměti, zkrácení kanálu požadavků k vrácení odpovědi uložené v mezipaměti.

Vlastní filtry je možné vytvořit tak, aby zvládly křížové obavy. Mezi příklady zkřížených obav patří zpracování chyb, ukládání do mezipaměti, konfigurace, autorizace a protokolování. Filtry zabraňují duplikování kódu. Filtr výjimek zpracování chyb může například konsolidovat zpracování chyb.

Tento dokument se týká Razor stránek, kontrolerů rozhraní API a kontrolerů se zobrazeními. Filtry nefungují přímo s Razor komponentami. Filtr může nepřímo ovlivnit komponentu pouze v případě, že:

  • Komponenta je vložená na stránku nebo zobrazení.
  • Stránka nebo kontroler a zobrazení používají filtr.

Zobrazit nebo stáhnout ukázku (stažení).

Jak filtry fungují

Filtry běží v rámci ASP.NET Core kanálu vyvolání akce , který se někdy označuje jako kanál filtru. Kanál filtru se spustí ASP.NET Core vybere akci, která se má provést.

Požadavek se zpracovává prostřednictvím jiného middlewaru, middlewaru směrování, výběru akce a kanálu vyvolání akce. Zpracování požadavku pokračuje zpět prostřednictvím výběru akce, middlewaru směrování a různých dalších middlewarů, než se stane odpovědí odeslaná klientovi.

Typy filtrů

Každý typ filtru se spustí v jiné fázi kanálu filtru:

  • Filtry autorizace se spustí jako první a slouží k určení, jestli je uživatel autorizovaný pro požadavek. Autorizace vyfiltruje kanál krátce, pokud požadavek není autorizovaný.

  • Filtry prostředků:

    • Spusťte po autorizaci.
    • OnResourceExecuting spustí kód před zbytkem kanálu filtru. Například spustí OnResourceExecuting kód před vytvořením vazby modelu.
    • OnResourceExecuted spustí kód po dokončení zbytku kanálu.
  • Filtry akcí:

    • Spusťte kód bezprostředně před voláním metody akce a po tom, co je volána metoda akce.
    • Může změnit argumenty předané do akce.
    • Může změnit výsledek vrácený z akce.
    • Nejsou podporované na Razor stránkách.
  • Filtry výjimek aplikují globální zásady na neošetřené výjimky, ke kterým dochází před zápisem textu odpovědi.

  • Filtry výsledků spouštěné kód těsně před a po provedení výsledků akce. Spustí se pouze v případě, že se metoda akce úspěšně spouštěna. Jsou užitečné pro logiku, která musí obklopovat provádění zobrazení nebo formátování.

Následující diagram znázorňuje interakci typů filtrů v kanálu filtru.

Požadavek se zpracovává prostřednictvím autorizačních filtrů, filtrů prostředků, vazby modelu, filtrů akcí, provedení akce a převodu výsledku akce, filtrů výjimek, filtrů výsledků a provádění výsledků. Na cestě ven se požadavek zpracuje pouze filtry výsledků a filtry prostředků před tím, než se stane odpovědí odeslaná klientovi.

Implementace

Filtry podporují synchronní i asynchronní implementace prostřednictvím různých definic rozhraní.

Synchronní filtry spouštějí kód před a po fázi kanálu. Volá se OnActionExecuting například před voláním metody akce. OnActionExecuted se volá po vrácení metody akce.

public class MySampleActionFilter : IActionFilter 
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
    }
}

V předchozím kódu je MyDebug funkcí nástroje v ukázce ke stažení.

Asynchronní filtry definují On-Stage-ExecutionAsync metodu . Například OnActionExecutionAsync :

public class SampleAsyncActionFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next)
    {
        // Do something before the action executes.

        // next() calls the action method.
        var resultContext = await next();
        // resultContext.Result is set.
        // Do something after the action executes.
    }
}

V předchozím kódu má SampleAsyncActionFilter objekt ( ), který spustí ActionExecutionDelegate next metodu akce.

Několik fází filtru

Rozhraní pro více fází filtru lze implementovat v jedné třídě. Například třída ActionFilterAttribute implementuje:

Implementujte synchronní nebo asynchronní verzi rozhraní filtru, nikoli obojí. Modul runtime nejprve zkontroluje, jestli filtr implementuje asynchronní rozhraní, a pokud ano, volá to. Pokud ne, volá metody synchronního rozhraní. Pokud jsou asynchronní i synchronní rozhraní implementována v jedné třídě, je volána pouze asynchronní metoda. Při použití abstraktních tříd, jako je , přepište pouze ActionFilterAttribute synchronní metody nebo asynchronní metody pro každý typ filtru.

Předdefinované atributy filtru

ASP.NET Core obsahuje předdefinované filtry založené na atributech, které je možné podtřídy a přizpůsobit. Například následující filtr výsledků přidá do odpovědi hlavičku:

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 });
        base.OnResultExecuting(context);
    }
}

Atributy umožňují filtrům přijímat argumenty, jak je znázorněno v předchozím příkladu. Použijte na AddHeaderAttribute kontroler nebo metodu akce a zadejte název a hodnotu hlavičky HTTP:

[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }

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 Anderson .

Následující kód implementuje objekt ActionFilterAttribute , který:

  • Přečte název a název z konfiguračního systému. Na rozdíl od předchozí ukázky následující kód nevyžaduje přidání parametrů filtru do kódu.
  • Přidá název a název do hlavičky odpovědi.
public class MyActionFilterAttribute : ActionFilterAttribute
{
    private readonly PositionOptions _settings;

    public MyActionFilterAttribute(IOptions<PositionOptions> options)
    {
        _settings = options.Value;
        Order = 1;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_settings.Title, 
                                                 new string[] { _settings.Name });
        base.OnResultExecuting(context);
    }
}

Možnosti konfigurace poskytuje konfigurační systém pomocí vzoru možností. Například ze appsettings.json souboru :

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

V souboru StartUp.ConfigureServices :

  • Třída PositionOptions se přidá do kontejneru služby s oblastí "Position" konfigurace.
  • Se MyActionFilterAttribute přidá do kontejneru služby.
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(
             Configuration.GetSection("Position"));
    services.AddScoped<MyActionFilterAttribute>();

    services.AddControllersWithViews();
}

Následující kód ukazuje PositionOptions třídu :

public class PositionOptions
{
    public string Title { get; set; }
    public string Name { get; set; }
}

Následující kód použije na MyActionFilterAttribute Index2 metodu :

[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }

    [ServiceFilter(typeof(MyActionFilterAttribute))]
    public IActionResult Index2()
    {
        return Content("Header values by configuration.");
    }

V části Hlavičky odpovědi, a se zobrazí při volání author: Rick Anderson Editor: Joe Smith Sample/Index2 koncového bodu.

Následující kód použije a MyActionFilterAttribute na AddHeaderAttribute stránku Razor :

[AddHeader("Author", "Rick Anderson")]
[ServiceFilter(typeof(MyActionFilterAttribute))]
public class IndexModel : PageModel
{
    public void OnGet()
    {
    }
}

Filtry nelze použít u metod Razor obslužné rutiny stránky. Můžete je použít buď na Razor model stránky, nebo globálně.

Několik rozhraní filtru má odpovídající atributy, které lze použít jako základní třídy pro vlastní implementace.

Atributy filtru:

Filtrování oborů a pořadí provádění

Do kanálu je možné přidat filtr v jednom ze tří rozsahů:

  • Použití atributu u akce kontroleru Atributy filtru nelze použít u metod Razor obslužné rutiny Pages.
  • Použití atributu na kontroleru nebo Razor stránce
  • Globálně pro všechny kontrolery, akce a Razor stránky, jak je znázorněno v následujícím kódu:
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
   {
        options.Filters.Add(typeof(MySampleActionFilter));
    });
}

Výchozí pořadí provádění

Pokud pro konkrétní fázi kanálu existuje více filtrů, obor určuje výchozí pořadí provádění filtru. Globální filtry obklopují filtry tříd, které pak obklopují filtry metod.

V důsledku vnořování filtru se po spuštění kódu filtrů v obráceném pořadí před kódem. Posloupnost filtru:

  • Kód před globálními filtry.
    • Kód kontroleru a filtru stránky Razor před.
      • Filtry metody akcí před kódem akce
      • Následující kód metody akce filtruje.
    • Kód za kontroleru a Razor filtry stránky.
  • Kód za globálními filtry.

Následující příklad znázorňuje pořadí, ve kterém jsou volány metody filtrování pro synchronní filtry akcí.

Sequence Obor filtru Metoda Filter
1 Globální OnActionExecuting
2 Kontroler nebo Razor stránka OnActionExecuting
3 Metoda OnActionExecuting
4 Metoda OnActionExecuted
5 Kontroler nebo Razor stránka OnActionExecuted
6 Globální OnActionExecuted

Filtry na úrovni kontroleru

Každý kontroler, který dědí ze Controller základní třídy, zahrnuje Controller.OnActionExecuting metody , a Controller.OnActionExecutionAsync Controller.OnActionExecuted OnActionExecuted . Tyto metody:

  • Zabalte filtry, které se pro danou akci spustí.
  • OnActionExecuting se volá před libovolným filtrem akce.
  • OnActionExecuted se volá po všech filtrech akcí.
  • OnActionExecutionAsync se volá před libovolným filtrem akce. Kód ve filtru po next spuštění po metodě akce.

Například v ukázce stahování se MySampleActionFilter globálně použije při spuštění.

Soubor TestController :

  • Použije na akci ( SampleActionFilterAttribute [SampleActionFilter] FilterTest2 ).
  • Přepíše OnActionExecuting a OnActionExecuted .
public class TestController : Controller
{
    [SampleActionFilter(Order = int.MinValue)]
    public IActionResult FilterTest2()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
        base.OnActionExecuting(context);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
        base.OnActionExecuted(context);
    }
}

MyDisplayRouteInfo poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazuje informace o trasách.

Když přejdete na https://localhost:5001/Test/FilterTest2 , spustí se následující kód:

  • TestController.OnActionExecuting
    • MySampleActionFilter.OnActionExecuting
      • SampleActionFilterAttribute.OnActionExecuting
        • TestController.FilterTest2
      • SampleActionFilterAttribute.OnActionExecuted
    • MySampleActionFilter.OnActionExecuted
  • TestController.OnActionExecuted

Filtry na úrovni kontroleru nastaví vlastnost Order na int.MinValue . Filtry na úrovni kontroleru není možné nastavit tak, aby se spouštěl po použití filtrů na metody. Order (Objednávka) je vysvětlená v další části.

Informace Razor o stránkách najdete v tématu Implementace filtrů stránek Razor přepsáním metod filtrování.

Přepsání výchozího pořadí

Výchozí sekvenci provádění lze přepsat implementací IOrderedFilter . IOrderedFilter zpřístupňuje Order vlastnost, která má přednost před oborem pro určení pořadí provádění. Filtr s nižší Order hodnotou:

  • Spustí kód před kódem filtru s vyšší hodnotou Order .
  • Spustí následující kód za kódem filtru s vyšší Order hodnotou.

Vlastnost Order je nastavená s parametrem konstruktoru:

[SampleActionFilter(Order = int.MinValue)]

Vezměte v úvahu dva filtry akcí v následujícím kontroleru:

[MyAction2Filter]
public class Test2Controller : Controller
{
    public IActionResult FilterTest2()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
        base.OnActionExecuting(context);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
        base.OnActionExecuted(context);
    }
}

Do souboru se přidá globální StartUp.ConfigureServices filtr:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
   {
        options.Filters.Add(typeof(MySampleActionFilter));
    });
}

Tři filtry se spustí v následujícím pořadí:

  • Test2Controller.OnActionExecuting
    • MySampleActionFilter.OnActionExecuting
      • MyAction2FilterAttribute.OnActionExecuting
        • Test2Controller.FilterTest2
      • MyAction2FilterAttribute.OnResultExecuting
    • MySampleActionFilter.OnActionExecuted
  • Test2Controller.OnActionExecuted

Vlastnost Order přepisuje obor při určování pořadí, ve kterém se filtry spouštěly. Filtry se seřadí nejprve podle pořadí a pak se k přerušení vazeb použije obor. Všechny integrované filtry implementují a IOrderedFilter nastaví výchozí hodnotu na Order 0. Jak už bylo zmíněno dříve, filtry na úrovni kontroleru nastaví vlastnost Order (Objednávka) na hodnotu For built-in filters (Pro předdefinové filtry), obor určuje pořadí, pokud není nastavená int.MinValue Order nenulová hodnota.

V předchozím kódu má globální obor, takže se spouští MySampleActionFilter před , který má obor MyAction2FilterAttribute kontroleru. Pokud chcete MyAction2FilterAttribute spustit jako první, nastavte pořadí na int.MinValue :

[MyAction2Filter(int.MinValue)]
public class Test2Controller : Controller
{
    public IActionResult FilterTest2()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
        base.OnActionExecuting(context);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
        base.OnActionExecuted(context);
    }
}

Pokud chcete, aby se globální MySampleActionFilter filtr spouštěl jako první, Order nastavte na int.MinValue :

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
   {
        options.Filters.Add(typeof(MySampleActionFilter),
                            int.MinValue);
    });
}

Zrušení a zkrácení okruhu

Kanál filtru je možné zkráceně nastavit vlastnost Result na ResourceExecutingContext parametru poskytnutém metodě filtru. Následující filtr prostředků například brání spuštění zbytku kanálu:

public class ShortCircuitingResourceFilterAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        context.Result = new ContentResult()
        {
            Content = "Resource unavailable - header not set."
        };
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

V následujícím kódu cílí objekt ShortCircuitingResourceFilter i AddHeader filtr na SomeResource metodu akce. Soubor ShortCircuitingResourceFilter :

  • Spustí se jako první, protože se jedná o filtr prostředků a AddHeader filtr akcí.
  • Zbytek kanálu se zkrátí.

Proto AddHeader se filtr pro akci nikdy SomeResource nes spustí. Toto chování by bylo stejné, kdyby se oba filtry použily na úrovni metody akce za předpokladu, že se ShortCircuitingResourceFilter nejprve spustili. Spustí ShortCircuitingResourceFilter se jako první kvůli svému typu filtru nebo explicitním použitím vlastnosti Order .

[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }

    [ServiceFilter(typeof(MyActionFilterAttribute))]
    public IActionResult Index2()
    {
        return Content("Header values by configuration.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header is set.");
    }

    [AddHeaderWithFactory]
    public IActionResult HeaderWithFactory()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }
}

Injektáž závislostí

Filtry je možné přidat podle typu nebo instance. Při přidání instance se tato instance použije pro každý požadavek. Pokud se přidá typ, aktivuje se typ. Typ aktivovaný filtr znamená:

  • Pro každý požadavek se vytvoří instance.
  • Všechny závislosti konstruktoru jsou naplněny injektáží závislostí (DI).

Filtry, které jsou implementovány jako atributy a přidány přímo do tříd kontroleru nebo metod akcí, nemohou mít závislosti konstruktoru poskytované injektáží závislostí (DI). Závislosti konstruktoru nelze skytovat pomocí induiéru, protože:

  • Atributy musí mít zadané parametry konstruktoru, kde jsou použity.
  • Jedná se o omezení toho, jak atributy fungují.

Následující filtry podporují závislosti konstruktoru poskytované z IN:

Předchozí filtry je možné použít u kontroleru nebo metody akce:

Protokolovací nástroje jsou k dispozici od DI. Vyhněte se ale vytváření a používání filtrů čistě pro účely protokolování. Integrované protokolování architektury obvykle poskytuje to, co je potřeba k protokolování. Protokolování přidané do filtrů:

  • Měli byste se zaměřit na otázky obchodní domény nebo chování specifické pro filtr.
  • Neměly by protokolovat akce nebo jiné události architektury. Integrovaná funkce filtruje akce protokolu a události architektury.

Atribut ServiceFilterAttribute

Typy implementace filtru služby jsou zaregistrované v ConfigureServices . Objekt ServiceFilterAttribute načte instanci filtru z diody.

Následující kód ukazuje AddHeaderResultServiceFilter :

public class AddHeaderResultServiceFilter : IResultFilter
{
    private ILogger _logger;
    public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var headerName = "OnResultExecuting";
        context.HttpContext.Response.Headers.Add(
            headerName, new string[] { "ResultExecutingSuccessfully" });
        _logger.LogInformation("Header added: {HeaderName}", headerName);
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // Can't add to headers here because response has started.
        _logger.LogInformation("AddHeaderResultServiceFilter.OnResultExecuted");
    }
}

Do kontejneru IN AddHeaderResultServiceFilter se přidá následující kód:

public void ConfigureServices(IServiceCollection services)
{
    // Add service filters.
    services.AddScoped<AddHeaderResultServiceFilter>();
    services.AddScoped<SampleActionFilterAttribute>();

    services.AddControllersWithViews(options =>
   {
       options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader",
           "Result filter added to MvcOptions.Filters"));         // An instance
        options.Filters.Add(typeof(MySampleActionFilter));         // By type
        options.Filters.Add(new SampleGlobalActionFilter());       // An instance
    });
}

V následujícím kódu atribut ServiceFilter načte instanci filtru z AddHeaderResultServiceFilter IN:

[ServiceFilter(typeof(AddHeaderResultServiceFilter))]
public IActionResult Index()
{
    return View();
}

Při použití ServiceFilterAttribute nastavení ServiceFilterAttribute.IsReusable :

  • Poskytuje nápovědu, že instanci filtru je možné znovu použít mimo rozsah požadavku, ve které byla vytvořena. Modul runtime ASP.NET Core nezaručuje:

    • Vytvoří se jedna instance filtru.
    • O tento filtr se později nebude z kontejneru ovládacího prvku pro ovládacího prvku znovu žádá.
  • Neměly by se používat s filtrem, který závisí na službách s jinou životností než singleton.

ServiceFilterAttribute implementuje IFilterFactory . IFilterFactory zpřístupňuje CreateInstance metodu pro vytvoření IFilterMetadata instance. CreateInstance načte zadaný typ z DI.

TypeFilterAttribute

TypeFilterAttribute je podobný ServiceFilterAttribute , ale jeho typ není vyřešen přímo z kontejneru di. Vytvoří instanci typu pomocí Microsoft.Extensions.DependencyInjection.ObjectFactory .

Protože TypeFilterAttribute typy nejsou vyřešeny přímo z kontejneru di:

  • Typy, na které se odkazuje pomocí, TypeFilterAttribute není nutné registrovat v kontejneru di. Mají své závislosti splněné kontejnerem DI.
  • TypeFilterAttribute může volitelně přijmout argumenty konstruktoru pro typ.

Při použití nástroje TypeFilterAttribute nastavte TypeFilterAttribute.IsReusable :

  • Poskytuje nápovědu, že se instance filtru znovu použít mimo rozsah požadavku, který byl vytvořen v rámci. modul runtime ASP.NET Core neposkytuje žádné záruky, že se vytvoří jediná instance filtru.

  • Neměl by se používat s filtrem, který závisí na službách s jinou životností než singleton.

Následující příklad ukazuje, jak předat argumenty typu pomocí TypeFilterAttribute :

[TypeFilter(typeof(LogConstantFilter),
    Arguments = new object[] { "Method 'Hi' called" })]
public IActionResult Hi(string name)
{
    return Content($"Hi {name}");
}

Filtry autorizace

Filtry autorizace:

  • Jsou první filtry spouštěny v kanálu filtru.
  • Řízení přístupu k metodám akcí.
  • Před metodou, ale ne po metodě.

Vlastní autorizační filtry vyžadují vlastní autorizační rozhraní. Preferovat konfiguraci autorizačních zásad nebo psaní vlastních zásad autorizace při psaní vlastního filtru. Vestavěný autorizační filtr:

  • Volá autorizační systém.
  • Neautorizuje požadavky.

Negenerovat výjimky v rámci autorizačních filtrů:

  • Výjimka nebude zpracována.
  • Filtry výjimek nebudou zpracovávat výjimku.

Zvažte vydání výzvy, pokud dojde k výjimce ve autorizačním filtru.

Přečtěte si další informace o autorizaci.

Filtry prostředků

Filtry prostředků:

Filtry prostředků jsou užitečné pro krátkodobé okruhy v kanálu. Například filtr ukládání do mezipaměti může zabránit zbývajícímu kanálu v případě přístupů do mezipaměti.

Příklady filtru prostředků:

Filtry akcí

Filtry akcí se nevztahují na Razor stránky. Razor Stránky podporují IPageFilter a IAsyncPageFilter . Další informace najdete v tématu metody filtrování pro Razor stránky.

Filtry akcí:

Následující kód ukazuje filtr vzorové akce:

public class MySampleActionFilter : IActionFilter 
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
    }
}

ActionExecutingContextPoskytuje následující vlastnosti:

  • ActionArguments – povolí čtení vstupů do metody Action.
  • Controller – povolí manipulaci s instancí kontroleru.
  • Result – nastavení Result krátkodobého provádění metody akce a následných filtrů akcí.

Vyvolání výjimky v metodě akce:

  • Zabraňuje spuštění dalších filtrů.
  • Na rozdíl od nastavení Result se místo úspěšného výsledku považuje za selhání.

ActionExecutedContextPoskytuje Controller a Result plus následující vlastnosti:

  • Canceled -True, pokud bylo provedení akce zkráceno jiným filtrem.

  • Exception -Hodnota není null, pokud akce nebo dříve vyvolala filtr akcí. Nastavení této vlastnosti na hodnotu null:

    • Efektivně zpracovává výjimku.
    • Result je spuštěn, jako kdyby byl vrácen z metody Action.

V případě IAsyncActionFilter volání ActionExecutionDelegate :

  • Provede všechny následné filtry akcí a metodu Action.
  • Vrací objekt ActionExecutedContext.

Do krátkodobého okruhu, přiřaďte Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.Result k instanci výsledku a Nevolejte next (a ActionExecutionDelegate ).

Rozhraní poskytuje abstrakci ActionFilterAttribute , která může být podtříd.

OnActionExecutingFiltr akcí lze použít k těmto akcím:

  • Ověří stav modelu.
  • Pokud je stav neplatný, vrátí se chyba.
public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext 
                                           context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(
                                                context.ModelState);
        }
    }

Poznámka

Řadiče s poznámkou s [ApiController] atributem automaticky ověří stav modelu a vrátí odpověď 400. Další informace najdete v tématu Automatické odpovědi HTTP 400.

OnActionExecutedMetoda se spustí za metodou akce:

  • A mohou zobrazit výsledky akce a manipulovat s nimi prostřednictvím Result Vlastnosti.

  • Canceled je nastaven na hodnotu true, pokud bylo provedení akce zkráceno jiným filtrem.

  • Exception je nastavena na hodnotu jinou než null, pokud akce nebo filtr následné akce vyvolaly výjimku. Nastavení Exception na hodnotu null:

    • Efektivně zpracovává výjimku.
    • ActionExecutedContext.Result je spuštěn, jako kdyby byl vrácen normálně z metody Action.
public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext 
                                           context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(
                                                context.ModelState);
        }
    }


    public override void OnActionExecuted(ActionExecutedContext 
                                          context)
    {
        var result = context.Result;
        // Do something with Result.
        if (context.Canceled == true)
        {
            // Action execution was short-circuited by another filter.
        }

        if(context.Exception != null)
        {
            // Exception thrown by action or action filter.
            // Set to null to handle the exception.
            context.Exception = null;
        }
        base.OnActionExecuted(context);
    }
}

Filtry výjimek

Filtry výjimek:

Následující ukázkový filtr výjimek používá vlastní zobrazení chyb pro zobrazení podrobností o výjimkách, ke kterým dochází při vývoji aplikace:

public class CustomExceptionFilter : IExceptionFilter
{
    private readonly IWebHostEnvironment _hostingEnvironment;
    private readonly IModelMetadataProvider _modelMetadataProvider;

    public CustomExceptionFilter(
        IWebHostEnvironment hostingEnvironment,
        IModelMetadataProvider modelMetadataProvider)
    {
        _hostingEnvironment = hostingEnvironment;
        _modelMetadataProvider = modelMetadataProvider;
    }

    public void OnException(ExceptionContext context)
    {
        if (!_hostingEnvironment.IsDevelopment())
        {
            return;
        }
        var result = new ViewResult {ViewName = "CustomError"};
        result.ViewData = new ViewDataDictionary(_modelMetadataProvider,
                                                    context.ModelState);
        result.ViewData.Add("Exception", context.Exception);
        // TODO: Pass additional detailed data via ViewData
        context.Result = result;
    }
}

Následující kód testuje filtr výjimky:

[TypeFilter(typeof(CustomExceptionFilter))]
public class FailingController : Controller
{
    [AddHeader("Failing Controller", 
               "Won't appear when exception is handled")]
    public IActionResult Index()
    {
        throw new Exception("Testing custom exception filter.");
    }
}

Filtry výjimek:

  • Nemusíte mít události před a po.
  • Implementujte OnException nebo OnExceptionAsync .
  • Zpracování neošetřených výjimek, ke kterým dochází při Razor vytváření stránky nebo kontroleru, vázání modelů, filtrů akcí nebo metod akcí.
  • Nezachycujte výjimky, ke kterým dochází v filtrech prostředků, výsledných filtrech nebo v důsledku provádění výsledků MVC.

Chcete-li zpracovat výjimku, nastavte ExceptionHandled vlastnost na true nebo zapište odpověď. Tím se zastaví šíření výjimky. Filtr výjimek nemůže vypnout výjimku na "úspěch". To může provést pouze filtr akcí.

Filtry výjimek:

  • Jsou vhodné pro vytváření přesahů výjimek, ke kterým dochází v rámci akcí.
  • Nejsou tak flexibilní jako middleware při zpracování chyb.

Preferovat middleware pro zpracování výjimek. Filtry výjimek použijte pouze v případě, že se zpracování chyb liší v závislosti na tom, která metoda Action je volána. Aplikace může například mít metody akcí pro koncové body rozhraní API i pro zobrazení/HTML. Koncové body rozhraní API mohou vracet informace o chybě jako JSON, zatímco akce na základě zobrazení by mohly vracet chybovou stránku jako HTML.

Filtry výsledků

Filtry výsledků:

IResultFilter a IAsyncResultFilter

Následující kód ukazuje filtr výsledků, který přidá hlavičku PROTOKOLU HTTP:

public class AddHeaderResultServiceFilter : IResultFilter
{
    private ILogger _logger;
    public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var headerName = "OnResultExecuting";
        context.HttpContext.Response.Headers.Add(
            headerName, new string[] { "ResultExecutingSuccessfully" });
        _logger.LogInformation("Header added: {HeaderName}", headerName);
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // Can't add to headers here because response has started.
        _logger.LogInformation("AddHeaderResultServiceFilter.OnResultExecuted");
    }
}

Typ prováděného výsledku závisí na akci. Akce vracející zobrazení zahrnuje veškeré zpracování razor v rámci ViewResult spuštění. Metoda rozhraní API může provádět některé serializace v rámci provádění výsledku. Přečtěte si další informace o výsledcích akcí.

Filtry výsledků se spustí pouze v případě, že filtr akce nebo akce vytvoří výsledek akce. Filtry výsledků se nespouštěny, když:

  • Autorizační filtr nebo filtr prostředků kanál zkrátí.
  • Filtr výjimek zpracovává výjimku vytvořením výsledku akce.

Metoda může zkráceně provést výsledek akce a následné filtry výsledků Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuting nastavením Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext.Cancel na true . Při zkrácení okruhu zapište do objektu odpovědi , abyste se vyhnuli generování prázdné odpovědi. Vyvolání výjimky v IResultFilter.OnResultExecuting :

  • Zabraňuje spuštění výsledku akce a dalších filtrů.
  • Je považován za selhání místo úspěšného výsledku.

Při spuštění Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuted metody už se odpověď pravděpodobně odeslala klientovi. Pokud už byla odpověď odeslána klientovi, nelze ji změnit.

ResultExecutedContext.Canceled je nastavená true na , pokud spuštění výsledku akce bylo zkráceno jiným filtrem.

ResultExecutedContext.Exception je nastavená na hodnotu, která není null, pokud výsledek akce nebo následný filtr výsledků vyvolal výjimku. Nastavení na hodnotu null efektivně zpracuje výjimku a zabrání tomu, aby se výjimka vyvolala Exception později v kanálu. Neexistuje žádný spolehlivý způsob, jak zapisovat data do odpovědi při zpracování výjimky ve filtru výsledků. Pokud byly hlavičky vyprázdněny do klienta, když výsledek akce vyvolá výjimku, neexistuje žádný spolehlivý mechanismus pro odeslání kódu selhání.

V případě funkce se při volání metody na spustí všechny následné filtry výsledků a IAsyncResultFilter výsledek await next ResultExecutionDelegate akce. Pokud chcete krátký okruh, nastavte na a ResultExecutingContext.Cancel true nevolejte ResultExecutionDelegate :

public class MyAsyncResponseFilter : IAsyncResultFilter
{
    public async Task OnResultExecutionAsync(ResultExecutingContext context,
                                             ResultExecutionDelegate next)
    {
        if (!(context.Result is EmptyResult))
        {
            await next();
        }
        else
        {
            context.Cancel = true;
        }

    }
}

Rozhraní poskytuje abstrakt, ResultFilterAttribute který může být podtřídou. Třída AddHeaderAttribute zobrazená výše je příkladem atributu filtru výsledků.

IAlwaysRunResultFilter a IAsyncAlwaysRunResultFilter

Rozhraní IAlwaysRunResultFilter IAsyncAlwaysRunResultFilter a deklarují IResultFilter implementaci, která se spouští pro všechny výsledky akce. To zahrnuje výsledky akcí, které vytvořily:

  • Filtry autorizace a filtry prostředků, které jsou zkrácené.
  • Filtry výjimek.

Například následující filtr se vždy spustí a nastaví výsledek akce ( ) s kódem stavu nezpracované entity ObjectResult 422, když selže vyjednávání obsahu:

public class UnprocessableResultFilter : Attribute, IAlwaysRunResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is StatusCodeResult statusCodeResult &&
            statusCodeResult.StatusCode == (int) HttpStatusCode.UnsupportedMediaType)
        {
            context.Result = new ObjectResult("Can't process this!")
            {
                StatusCode = (int) HttpStatusCode.UnsupportedMediaType,
            };
        }
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
    }
}

IFilterFactory

IFilterFactory implementuje IFilterMetadata . Proto je IFilterFactory možné instanci použít jako instanci kdekoli v IFilterMetadata kanálu filtru. Když se modul runtime připraví na vyvolání filtru, pokusí se ho přetypovat na IFilterFactory . Pokud je toto přetypování úspěšné, je volána metoda pro CreateInstance vytvoření IFilterMetadata instance, která je vyvolána. To poskytuje flexibilní návrh, protože přesný kanál filtru není nutné explicitně nastavovat při spuštění aplikace.

IFilterFactory.IsReusable:

  • Je nápověda továrny, že instance filtru vytvořená továrnou se může znovu použít mimo rozsah požadavku, ve které byla vytvořena.
  • Neměly by se používat s filtrem, který závisí na službách s jinou životností než singleton.

Modul runtime ASP.NET Core nezaručuje:

  • Vytvoří se jedna instance filtru.
  • O tento filtr se později nebude z kontejneru ovládacího prvku pro ovládacího prvku znovu žádá.

Upozornění

Možnost vrácení proveďte pouze v případě, že je zdroj filtrů jednoznačný, filtry jsou bez stavové a filtry lze bezpečně použít napříč více požadavky IFilterFactory.IsReusable true HTTP. Nevrací například filtry z DI, které jsou zaregistrované jako vymezené nebo přechodné, pokud IFilterFactory.IsReusable vrátí true .

IFilterFactory je možné implementovat pomocí implementací vlastních atributů jako dalšího přístupu k vytváření filtrů:

public class AddHeaderWithFactoryAttribute : Attribute, IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new InternalAddHeaderFilter();
    }

    private class InternalAddHeaderFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "Internal", new string[] { "My header" });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Filtr se použije v následujícím kódu:

[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }

    [ServiceFilter(typeof(MyActionFilterAttribute))]
    public IActionResult Index2()
    {
        return Content("Header values by configuration.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header is set.");
    }

    [AddHeaderWithFactory]
    public IActionResult HeaderWithFactory()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }
}

Otestujte předchozí kód spuštěním ukázky stahování:

  • Vyvolání vývojářských nástrojů F12
  • Přejděte na adresu https://localhost:5001/Sample/HeaderWithFactory.

Vývojářské nástroje F12 zobrazují následující hlavičky odpovědi přidané ukázkovým kódem:

  • author (autor):Rick Anderson
  • globaladdheader:Result filter added to MvcOptions.Filters
  • interní:My header

Předchozí kód vytvoří hlavičku internal: My header response.

Implementace IFilterFactory u atributu

Implementují se IFilterFactory filtry, které jsou užitečné pro filtry, které:

  • Nevyžaduje předávání parametrů.
  • Musí mít závislosti konstruktoru, které musí být vyplněné induiérou.

TypeFilterAttribute implementuje IFilterFactory . IFilterFactory zpřístupňuje CreateInstance metodu pro vytvoření IFilterMetadata instance. CreateInstance načte zadaný typ z kontejneru services (DI).

public class SampleActionFilterAttribute : TypeFilterAttribute
{
    public SampleActionFilterAttribute()
                         :base(typeof(SampleActionFilterImpl))
    { 
    }

    private class SampleActionFilterImpl : IActionFilter
    {
        private readonly ILogger _logger;
        public SampleActionFilterImpl(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
           _logger.LogInformation("SampleActionFilterAttribute.OnActionExecuting");
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            _logger.LogInformation("SampleActionFilterAttribute.OnActionExecuted");
        }
    }
}

Následující kód ukazuje tři přístupy k použití [SampleActionFilter] :

[SampleActionFilter]
public IActionResult FilterTest()
{
    return Content("From FilterTest");
}

[TypeFilter(typeof(SampleActionFilterAttribute))]
public IActionResult TypeFilterTest()
{
    return Content("From TypeFilterTest");
}

// ServiceFilter must be registered in ConfigureServices or
// System.InvalidOperationException: No service for type '<filter>'
// has been registered. Is thrown.
[ServiceFilter(typeof(SampleActionFilterAttribute))]
public IActionResult ServiceFilterTest()
{
    return Content("From ServiceFilterTest");
}

V předchozím kódu je upřednostňovaným přístupem k použití metody [SampleActionFilter] SampleActionFilter .

Použití middlewaru v kanálu filtru

Filtry prostředků fungují jako middleware v tom, že obklopují provádění všeho, co přijde později v kanálu. Filtry se ale liší od middlewaru v tom, že jsou součástí modulu runtime, což znamená, že mají přístup ke kontextu a konstruktorům.

Pokud chcete middleware použít jako filtr, vytvořte typ s metodou, která určuje middleware, který se Configure má vložit do kanálu filtru. Následující příklad používá middleware lokalizace k vytvoření aktuální jazykové verze pro požadavek:

public class LocalizationPipeline
{
    public void Configure(IApplicationBuilder applicationBuilder)
    {
        var supportedCultures = new[]
        {
            new CultureInfo("en-US"),
            new CultureInfo("fr")
        };

        var options = new RequestLocalizationOptions
        {
            DefaultRequestCulture = new RequestCulture(
                                       culture: "en-US", 
                                       uiCulture: "en-US"),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        };
        options.RequestCultureProviders = new[] 
            { new RouteDataRequestCultureProvider() {
                Options = options } };

        applicationBuilder.UseRequestLocalization(options);
    }
}

Ke MiddlewareFilterAttribute spuštění middlewaru použijte :

[Route("{culture}/[controller]/[action]")]
[MiddlewareFilter(typeof(LocalizationPipeline))]
public IActionResult CultureFromRouteData()
{
    return Content(
          $"CurrentCulture:{CultureInfo.CurrentCulture.Name},"
        + $"CurrentUICulture:{CultureInfo.CurrentUICulture.Name}");
}

Middlewarové filtry běží ve stejné fázi kanálu filtru jako filtry prostředků před vytvořením vazby modelu a po zbytku kanálu.

Bezpečnost vlákna

Při předávání instance filtru do , místo jeho , je filtr jednosloupce a není Add Type bezpečný pro vlákno.

Další akce

Od SteveA Polakina, Ricka Andersona, Toma Dykstraa SteveHo Smithe

Filtry ASP.NET Core umožňují spuštění kódu před nebo po konkrétních fázích kanálu zpracování požadavků.

Integrované filtry zvládí například tyto úlohy:

  • Autorizace (zabránění přístupu k prostředkům, ke které uživatel nemá oprávnění)
  • Ukládání odpovědí do mezipaměti (zkrácení kanálu požadavků pro vrácení odpovědi uložené v mezipaměti)

Vlastní filtry je možné vytvořit tak, aby zvládly křížové obavy. Mezi příklady zkřížených obav patří zpracování chyb, ukládání do mezipaměti, konfigurace, autorizace a protokolování. Filtry zabraňují duplikování kódu. Filtr výjimek zpracování chyb může například konsolidovat zpracování chyb.

Tento dokument se týká Razor stránek, kontrolerů rozhraní API a kontrolerů se zobrazeními.

Zobrazit nebo stáhnout ukázku (stažení).

Jak filtry fungují

Filtry běží v rámci ASP.NET Core kanálu vyvolání akce , který se někdy označuje jako kanál filtru. Kanál filtru se spustí ASP.NET Core vybere akci, která se má provést.

Požadavek se zpracuje prostřednictvím jiného middlewaru, middlewaru směrování, výběru akce a ASP.NET Core kanálu volání akce směrování. Zpracování požadavku pokračuje zpět prostřednictvím výběru akce, middlewaru směrování a různých dalších middlewarů, než se stane odpovědí odeslaná klientovi.

Typy filtrů

Každý typ filtru se spustí v jiné fázi kanálu filtru:

  • Filtry autorizace se spustí jako první a slouží k určení, jestli je uživatel autorizovaný pro požadavek. Filtry autorizace pro krátkodobé vynechání kanálu, pokud je požadavek neautorizovaný

  • Filtry prostředků:

    • Spusťte po autorizaci.
    • OnResourceExecuting může spustit kód před zbytek kanálu filtru. Například OnResourceExecuting může spustit kód před vytvořením vazby modelu.
    • OnResourceExecuted může spustit kód po dokončení zbývající části kanálu.
  • Filtry akcí mohou spustit kód bezprostředně před a po volání jednotlivé metody akce. Lze je použít k manipulaci s argumenty předaných do akce a výsledek vráceného z akce. Na stránkách se nepodporují filtry akcí Razor .

  • Filtry výjimek slouží k aplikování globálních zásad na neošetřené výjimky, ke kterým dojde před zapsáním cokoli do těla odpovědi.

  • Filtry výsledků můžou spustit kód hned před a po provedení jednotlivých výsledků akce. Spustí se pouze v případě, že metoda akce byla úspěšně provedena. Jsou užitečné pro logiku, která musí obklopit zobrazení nebo formátovací modul.

Následující diagram znázorňuje způsob interakce typů filtrů v kanálu filtru.

Požadavek se zpracovává pomocí autorizačních filtrů, filtrů prostředků, vazeb modelů, filtrů akcí, provádění akcí a konverze výsledků akcí, filtrů výjimek, výsledných filtrů a provádění výsledků. Na cestě je požadavek zpracován pouze pomocí filtrů výsledků a filtrů prostředků před tím, než se stane odpověď odeslanou klientovi.

Implementace

Filtry podporují synchronní i asynchronní implementace prostřednictvím různých definic rozhraní.

Synchronní filtry mohou spustit kód před ( On-Stage-Executing ) a po ( On-Stage-Executed ) jejich fáze zřetězení. Například OnActionExecuting je volána před voláním metody Action. OnActionExecuted je volána po návratu metody Action.

public class MySampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
    }
}

Asynchronní filtry definují On-Stage-ExecutionAsync metodu:

public class SampleAsyncActionFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next)
    {
        // Do something before the action executes.

        // next() calls the action method.
        var resultContext = await next();
        // resultContext.Result is set.
        // Do something after the action executes.
    }
}

V předchozím kódu SampleAsyncActionFilter obsahuje znak ActionExecutionDelegate ( next ), který provádí metodu Action. Každá z těchto On-Stage-ExecutionAsync metod vezme FilterType-ExecutionDelegate fázi zřetězení filtru.

Několik fází filtru

Rozhraní pro více fází filtru lze implementovat v rámci jedné třídy. Například ActionFilterAttribute Třída implementuje IActionFilter , IResultFilter a jejich asynchronní ekvivalenty.

Implementujte buď synchronní, nebo asynchronní verzi rozhraní filtru, nikoli obojí. Modul runtime nejprve kontroluje, zda filtr implementuje asynchronní rozhraní a v takovém případě jej zavolá. V takovém případě volá metody synchronního rozhraní. Pokud jsou asynchronní i synchronní rozhraní implementovány v jedné třídě, je volána pouze asynchronní metoda. Při použití abstraktních tříd, jako ActionFilterAttribute je například přepsání pouze synchronních metod nebo asynchronní metody pro každý typ filtru.

Předdefinované atributy filtru

ASP.NET Core obsahuje integrované filtry založené na atributech, které mohou být roztříděné a přizpůsobené. Například následující filtr výsledků přidá hlavičku do odpovědi:

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 });
        base.OnResultExecuting(context);
    }
}

Atributy umožňují filtrům přijímat argumenty, jak je znázorněno v předchozím příkladu. Použijte AddHeaderAttribute pro metodu Controller nebo Action a zadejte název a hodnotu HLAVIČKY http:

[AddHeader("Author", "Joe Smith")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header is set.");
    }

Některé z rozhraní filtru mají odpovídající atributy, které lze použít jako základní třídy pro vlastní implementace.

Atributy filtru:

Filtrovat obory a pořadí provádění

Filtr lze přidat do kanálu v jednom ze tří oborů:

  • Použití atributu pro akci.
  • Použití atributu na řadiči.
  • Globálně pro všechny řadiče a akce, jak je znázorněno v následujícím kódu:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader",
            "Result filter added to MvcOptions.Filters"));         // An instance
        options.Filters.Add(typeof(MySampleActionFilter));         // By type
        options.Filters.Add(new SampleGlobalActionFilter());       // An instance
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Předchozí kód přičítá tři filtry globálně pomocí kolekce MvcOptions. filters .

Výchozí pořadí provádění

Pokud existuje více filtrů stejného typu, určuje obor výchozí pořadí provádění filtru. Globální filtry filtr tříd Surround. Filtry tříd obklopují filtry metod Surround.

V důsledku vnořování filtru je po kódu spuštěn v obráceném pořadí před kódem. Pořadí filtru:

  • Před kódem globálních filtrů.
    • Před kódem filtru kontroleru.
      • Kód před filtry metody Action.
      • Po kódu filtry metody Action.
    • Po kódu filtry kontroleru.
  • Po kódu globálních filtrů.

Následující příklad ilustruje pořadí, ve kterém jsou metody filtru volány pro filtry synchronních akcí.

Sequence Rozsah filtru Filter – metoda
1 Globální OnActionExecuting
2 Controller OnActionExecuting
3 Metoda OnActionExecuting
4 Metoda OnActionExecuted
5 Controller OnActionExecuted
6 Globální OnActionExecuted

Tato posloupnost zobrazuje:

  • Filtr metod je vnořený do filtru kontroleru.
  • Filtr kontroleru je vnořený do globálního filtru.

Filtry na Razor úrovni řadiče a stránky

Každý kontroler, který dědí ze Controller základní třídy Controller.OnActionExecuting , zahrnuje Controller.OnActionExecutionAsync metody, a Controller.OnActionExecuted OnActionExecuted . Tyto metody:

  • Zabalte filtry, které se spouštějí pro danou akci.
  • OnActionExecuting je volána před jakýmkoli filtrem akce.
  • OnActionExecuted se volá po všech filtrech akcí.
  • OnActionExecutionAsync je volána před jakýmkoli filtrem akce. Kód v filtru po next spuštění po metodě Action.

Například v ukázce ke stažení MySampleActionFilter se použije globálně při spuštění.

TestController:

  • Aplikuje SampleActionFilterAttribute ( [SampleActionFilter] ) na FilterTest2 akci.
  • Přepisuje OnActionExecuting a OnActionExecuted .
public class TestController : Controller
{
    [SampleActionFilter]
    public IActionResult FilterTest2()
    {
        return Content($"From FilterTest2");
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        base.OnActionExecuting(context);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        base.OnActionExecuted(context);
    }
}

Navigace pro https://localhost:5001/Test/FilterTest2 spustí následující kód:

  • TestController.OnActionExecuting
    • MySampleActionFilter.OnActionExecuting
      • SampleActionFilterAttribute.OnActionExecuting
        • TestController.FilterTest2
      • SampleActionFilterAttribute.OnActionExecuted
    • MySampleActionFilter.OnActionExecuted
  • TestController.OnActionExecuted

RazorInformace o stránkách naleznete v tématu implementace Razor filtrů stránek pomocí přepsání metod filtru.

Přepsání výchozího pořadí

Výchozí sekvenci spuštění lze přepsat implementací IOrderedFilter . IOrderedFilter zpřístupňuje Order vlastnost, která má přednost před rozsahem, aby určila pořadí provádění. Filtr s nižší Order hodnotou:

  • Spustí před kódem filtr s vyšší hodnotou Order .
  • Spustí za kódem za filtr s vyšší Order hodnotou.

OrderVlastnost lze nastavit s parametrem konstruktoru:

[MyFilter(Name = "Controller Level Attribute", Order=1)]

Vezměte v úvahu stejné 3 filtry akcí, které jsou uvedené v předchozím příkladu. Pokud Order je vlastnost Controller a globální filtry nastavená na 1 a 2 v uvedeném pořadí, pořadí spouštění se vrátí zpět.

Sequence Rozsah filtru Order majetek Filter – metoda
1 Metoda 0 OnActionExecuting
2 Controller 1 OnActionExecuting
3 Globální 2 OnActionExecuting
4 Globální 2 OnActionExecuted
5 Controller 1 OnActionExecuted
6 Metoda 0 OnActionExecuted

OrderVlastnost Přepisuje obor při určování pořadí, ve kterém jsou filtry spouštěny. Filtry jsou seřazené podle pořadí, pak se k přerušení vztahů používá obor. Všechny předdefinované filtry implementují IOrderedFilter a nastaví výchozí Order hodnotu na 0. Pro předdefinované filtry rozsah určuje pořadí, pokud Order není nastaven na nenulovou hodnotu.

Zrušení a zkrácení okruhů

Kanál filtru může být v krátkém okruhu nastavením Result vlastnosti pro ResourceExecutingContext parametr poskytnutý metodě Filter. Například následující filtr prostředků zabrání ve spuštění zbývajícího kanálu:

public class ShortCircuitingResourceFilterAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        context.Result = new ContentResult()
        {
            Content = "Resource unavailable - header not set."
        };
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

V následujícím kódu, ShortCircuitingResourceFilter a jako AddHeader cíl filtru i cílovou SomeResource metodu Action. ShortCircuitingResourceFilter:

  • Nejprve se spustí, protože se jedná o filtr prostředků a AddHeader je filtr akcí.
  • Krátké okruhy zbývajícího kanálu.

Proto AddHeader Filtr pro akci nikdy neběží SomeResource . Toto chování by bylo stejné, pokud byly oba filtry aplikovány na úrovni metody akce, a to za předpokladu, že byla ShortCircuitingResourceFilter spuštěna jako první. ShortCircuitingResourceFilterNejprve se spustí z důvodu jeho typu filtru nebo explicitního použití Order Vlastnosti.

[AddHeader("Author", "Joe Smith")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using the F12 developer tools.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header is set.");
    }

Injektáž závislostí

Filtry lze přidat podle typu nebo podle instance. Pokud je přidána instance, bude tato instance použita pro každý požadavek. Pokud je přidán typ, je aktivován typ. Filtr aktivovaný typu znamená:

  • Instance se vytvoří pro každý požadavek.
  • Jakékoli závislosti konstruktoru jsou vyplněny pomocí Injektáže závislosti (di).

Filtry, které jsou implementovány jako atributy a přidány přímo do tříd kontroleru nebo metody akcí, nemohou mít závislosti konstruktoru poskytované vkládáním závislostí (di). Pomocí DI nelze poskytnout závislosti konstruktoru:

  • V atributech musí být zadány parametry konstruktoru, kde jsou aplikovány.
  • Toto je omezení způsobu fungování atributů.

Následující filtry podporují závislosti konstruktoru poskytované od DI:

Předchozí filtry lze použít pro metodu kontroleru nebo akce:

Protokolovací nástroje jsou k dispozici z DI. Ale nevytvářejte a používejte filtry čistě pro účely protokolování. Integrované protokolování rozhraní obvykle zajišťuje, co je potřeba pro protokolování. Protokolování přidáno do filtrů:

  • Měl by se soustředit na obavy a chování obchodních domén, které jsou specifické pro filtr.
  • Neměli byste protokolovat akce nebo jiné události rozhraní. Vestavěné filtry protokolují akce a události rozhraní.

ServiceFilterAttribute

Typy implementace filtru služby jsou zaregistrované v ConfigureServices . ServiceFilterAttributeNačte instanci filtru z di.

Následující kód ukazuje AddHeaderResultServiceFilter :

public class AddHeaderResultServiceFilter : IResultFilter
{
    private ILogger _logger;
    public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var headerName = "OnResultExecuting";
        context.HttpContext.Response.Headers.Add(
            headerName, new string[] { "ResultExecutingSuccessfully" });
        _logger.LogInformation("Header added: {HeaderName}", headerName);
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // Can't add to headers here because response has started.
    }
}

V následujícím kódu AddHeaderResultServiceFilter je přidán do kontejneru di:

public void ConfigureServices(IServiceCollection services)
{
    // Add service filters.
    services.AddScoped<AddHeaderResultServiceFilter>();
    services.AddScoped<SampleActionFilterAttribute>();

    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader",
            "Result filter added to MvcOptions.Filters"));         // An instance
        options.Filters.Add(typeof(MySampleActionFilter));         // By type
        options.Filters.Add(new SampleGlobalActionFilter());       // An instance
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

V následujícím kódu ServiceFilter atribut načte instanci AddHeaderResultServiceFilter filtru z di:

[ServiceFilter(typeof(AddHeaderResultServiceFilter))]
public IActionResult Index()
{
    return View();
}

Při použití nástroje ServiceFilterAttribute nastavte ServiceFilterAttribute.IsReusable :

  • Poskytuje nápovědu, že se instance filtru znovu použít mimo rozsah požadavku, který byl vytvořen v rámci. modul runtime ASP.NET Core nezaručuje:

    • Vytvoří se jedna instance filtru.
    • Filtr nebude znovu vyžádán z kontejneru DI v pozdějším bodě.
  • Neměl by se používat s filtrem, který závisí na službách s jinou životností než singleton.

ServiceFilterAttribute implementuje IFilterFactory . IFilterFactory zpřístupňuje CreateInstance metodu pro vytvoření IFilterMetadata instance. CreateInstance Načte zadaný typ z DI.

TypeFilterAttribute

TypeFilterAttribute je podobný ServiceFilterAttribute , ale jeho typ není vyřešen přímo z kontejneru di. Vytvoří instanci typu pomocí Microsoft.Extensions.DependencyInjection.ObjectFactory .

Protože TypeFilterAttribute typy nejsou vyřešeny přímo z kontejneru di:

  • Typy, na které se odkazuje pomocí, TypeFilterAttribute není nutné registrovat v kontejneru di. Mají své závislosti splněné kontejnerem DI.
  • TypeFilterAttribute může volitelně přijmout argumenty konstruktoru pro typ.

Při použití nástroje TypeFilterAttribute nastavte TypeFilterAttribute.IsReusable :

  • Poskytuje nápovědu, že se instance filtru znovu použít mimo rozsah požadavku, který byl vytvořen v rámci. modul runtime ASP.NET Core neposkytuje žádné záruky, že se vytvoří jediná instance filtru.

  • Neměl by se používat s filtrem, který závisí na službách s jinou životností než singleton.

Následující příklad ukazuje, jak předat argumenty typu pomocí TypeFilterAttribute :

[TypeFilter(typeof(LogConstantFilter),
    Arguments = new object[] { "Method 'Hi' called" })]
public IActionResult Hi(string name)
{
    return Content($"Hi {name}");
}
public class LogConstantFilter : IActionFilter
{
    private readonly string _value;
    private readonly ILogger<LogConstantFilter> _logger;

    public LogConstantFilter(string value, ILogger<LogConstantFilter> logger)
    {
        _logger = logger;
        _value = value;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogInformation(_value);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    { }
}

Filtry autorizace

Filtry autorizace:

  • Jsou první filtry spouštěny v kanálu filtru.
  • Řízení přístupu k metodám akcí.
  • Před metodou, ale ne po metodě.

Vlastní autorizační filtry vyžadují vlastní autorizační rozhraní. Preferovat konfiguraci autorizačních zásad nebo psaní vlastních zásad autorizace při psaní vlastního filtru. Vestavěný autorizační filtr:

  • Volá autorizační systém.
  • Neautorizuje požadavky.

Negenerovat výjimky v rámci autorizačních filtrů:

  • Výjimka nebude zpracována.
  • Filtry výjimek nebudou zpracovávat výjimku.

Zvažte vydání výzvy, pokud dojde k výjimce ve autorizačním filtru.

Přečtěte si další informace o autorizaci.

Filtry prostředků

Filtry prostředků:

Filtry prostředků jsou užitečné pro krátkodobé okruhy v kanálu. Například filtr ukládání do mezipaměti může zabránit zbývajícímu kanálu v případě přístupů do mezipaměti.

Příklady filtru prostředků:

Filtry akcí

Důležité

Filtry akcí se nevztahují na Razor stránky. Razor Stránky podporují IPageFilter a IAsyncPageFilter . Další informace najdete v tématu metody filtrování pro Razor stránky.

Filtry akcí:

Následující kód ukazuje filtr vzorové akce:

public class MySampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
    }
}

ActionExecutingContextPoskytuje následující vlastnosti:

  • ActionArguments – povolí čtení vstupů do metody akce.
  • Controller – povolí manipulaci s instancí kontroleru.
  • Result – nastavení Result krátkodobého provádění metody akce a následných filtrů akcí.

Vyvolání výjimky v metodě akce:

  • Zabraňuje spuštění dalších filtrů.
  • Na rozdíl od nastavení Result se místo úspěšného výsledku považuje za selhání.

ActionExecutedContextPoskytuje Controller a Result plus následující vlastnosti:

  • Canceled -True, pokud bylo provedení akce zkráceno jiným filtrem.

  • Exception -Hodnota není null, pokud akce nebo dříve vyvolala filtr akcí. Nastavení této vlastnosti na hodnotu null:

    • Efektivně zpracovává výjimku.
    • Result je spuštěn, jako kdyby byl vrácen z metody Action.

V případě IAsyncActionFilter volání ActionExecutionDelegate :

  • Provede všechny následné filtry akcí a metodu Action.
  • Vrací objekt ActionExecutedContext.

Do krátkodobého okruhu, přiřaďte Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.Result k instanci výsledku a Nevolejte next (a ActionExecutionDelegate ).

Rozhraní poskytuje abstrakci ActionFilterAttribute , která může být podtříd.

OnActionExecutingFiltr akcí lze použít k těmto akcím:

  • Ověří stav modelu.
  • Pokud je stav neplatný, vrátí se chyba.
public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
    }

OnActionExecutedMetoda se spustí za metodou akce:

  • A mohou zobrazit výsledky akce a manipulovat s nimi prostřednictvím Result Vlastnosti.

  • Canceled je nastaven na hodnotu true, pokud bylo provedení akce zkráceno jiným filtrem.

  • Exception je nastavena na hodnotu jinou než null, pokud akce nebo filtr následné akce vyvolaly výjimku. Nastavení Exception na hodnotu null:

    • Efektivně zpracovává výjimku.
    • ActionExecutedContext.Result je spuštěn, jako kdyby byl vrácen normálně z metody Action.
public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
    }


    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var result = context.Result;
        // Do something with Result.
        if (context.Canceled == true)
        {
            // Action execution was short-circuited by another filter.
        }

        if(context.Exception != null)
        {
            // Exception thrown by action or action filter.
            // Set to null to handle the exception.
            context.Exception = null;
        }
        base.OnActionExecuted(context);
    }
}

Filtry výjimek

Filtry výjimek:

Následující ukázkový filtr výjimek používá vlastní zobrazení chyb pro zobrazení podrobností o výjimkách, ke kterým dochází při vývoji aplikace:

public class CustomExceptionFilter : IExceptionFilter
{
    private readonly IHostingEnvironment _hostingEnvironment;
    private readonly IModelMetadataProvider _modelMetadataProvider;

    public CustomExceptionFilter(
        IHostingEnvironment hostingEnvironment,
        IModelMetadataProvider modelMetadataProvider)
    {
        _hostingEnvironment = hostingEnvironment;
        _modelMetadataProvider = modelMetadataProvider;
    }

    public void OnException(ExceptionContext context)
    {
        if (!_hostingEnvironment.IsDevelopment())
        {
            return;
        }
        var result = new ViewResult {ViewName = "CustomError"};
        result.ViewData = new ViewDataDictionary(_modelMetadataProvider,
                                                    context.ModelState);
        result.ViewData.Add("Exception", context.Exception);
        // TODO: Pass additional detailed data via ViewData
        context.Result = result;
    }
}

Filtry výjimek:

  • Nemusíte mít události před a po.
  • Implementujte OnException nebo OnExceptionAsync .
  • Zpracování neošetřených výjimek, ke kterým dochází při Razor vytváření stránky nebo kontroleru, vázání modelů, filtrů akcí nebo metod akcí.
  • Nezachycujte výjimky, ke kterým dochází v filtrech prostředků, výsledných filtrech nebo v důsledku provádění výsledků MVC.

Chcete-li zpracovat výjimku, nastavte ExceptionHandled vlastnost na true nebo zapište odpověď. Tím se zastaví šíření výjimky. Filtr výjimek nemůže vypnout výjimku na "úspěch". To může provést pouze filtr akcí.

Filtry výjimek:

  • Jsou vhodné pro vytváření přesahů výjimek, ke kterým dochází v rámci akcí.
  • Nejsou tak flexibilní jako middleware při zpracování chyb.

Preferovat middleware pro zpracování výjimek. Filtry výjimek použijte pouze v případě, že se zpracování chyb liší v závislosti na tom, která metoda Action je volána. Aplikace může například mít metody akcí pro koncové body rozhraní API i pro zobrazení/HTML. Koncové body rozhraní API mohou vracet informace o chybě jako JSON, zatímco akce na základě zobrazení by mohly vracet chybovou stránku jako HTML.

Filtry výsledků

Filtry výsledků:

IResultFilter a IAsyncResultFilter

Následující kód ukazuje filtr výsledků, který přidá hlavičku protokolu HTTP:

public class AddHeaderResultServiceFilter : IResultFilter
{
    private ILogger _logger;
    public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var headerName = "OnResultExecuting";
        context.HttpContext.Response.Headers.Add(
            headerName, new string[] { "ResultExecutingSuccessfully" });
        _logger.LogInformation("Header added: {HeaderName}", headerName);
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // Can't add to headers here because response has started.
    }
}

Typ výsledku, který se má provést, závisí na akci. Akce vracející zobrazení zahrnuje všechny zpracování Razor jako součást prováděné ViewResult . Metoda rozhraní API může provést určitou serializaci v rámci provádění výsledku. Přečtěte si další informace o výsledcích akcí.

Filtry výsledků se spustí pouze v případě, že akce nebo filtr akcí vytvoří výsledek akce. Filtry výsledků nejsou provedeny v těchto případech:

  • Filtr autorizace nebo filtr prostředků pro krátké okruhy kanálu.
  • Filtr výjimek zpracovává výjimku tím, že vyprodukuje výsledek akce.

Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecutingMetoda může zkrátit provádění výsledků akce a následných filtrů výsledků nastavením Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext.Cancel na true . Zapište do objektu Response v případě krátkého okruhu, abyste se vyhnuli vygenerování prázdné odpovědi. Vyvolání výjimky v IResultFilter.OnResultExecuting bude:

  • Zabraňte provádění výsledků akce a dalších filtrů.
  • Být považována za selhání namísto úspěšného výsledku.

Při Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuted spuštění metody je odpověď pravděpodobně již odeslána klientovi. Pokud byla odpověď již odeslána klientovi, nelze ji dále změnit.

ResultExecutedContext.Canceled je nastaven na hodnotu, true Pokud je spuštění výsledku akce zkráceno jiným filtrem.

ResultExecutedContext.Exception je nastavena na hodnotu jinou než null, pokud výsledek akce nebo následný filtr výsledků vyvolal výjimku. nastavení Exception na hodnotu null efektivně zpracovává výjimku a brání výjimce znovu vyvolat ASP.NET Core později v kanálu. Neexistuje žádný spolehlivý způsob, jak zapisovat data do odpovědi při zpracování výjimky ve filtru výsledků. Pokud byly hlavičky vyprázdněny do klienta, pokud výsledek akce vyvolá výjimku, neexistuje žádný spolehlivý mechanismus pro odeslání kódu chyby.

V případě IAsyncResultFilter volání await next na se ResultExecutionDelegate spustí všechny následné filtry výsledků a výsledek akce. Do krátkodobého okruhu, nastavte ResultExecutingContext.Cancel na true a Nevolejte ResultExecutionDelegate :

public class MyAsyncResponseFilter : IAsyncResultFilter
{
    public async Task OnResultExecutionAsync(ResultExecutingContext context,
                                             ResultExecutionDelegate next)
    {
        if (!(context.Result is EmptyResult))
        {
            await next();
        }
        else
        {
            context.Cancel = true;
        }

    }
}

Rozhraní poskytuje abstrakci ResultFilterAttribute , která může být podtříd. Dříve uvedená třída AddHeaderAttribute je příkladem atributu filtru výsledků.

IAlwaysRunResultFilter a IAsyncAlwaysRunResultFilter

Rozhraní IAlwaysRunResultFilter IAsyncAlwaysRunResultFilter a deklarují IResultFilter implementaci, která se spouští pro všechny výsledky akce. To zahrnuje výsledky akcí, které vytvořily:

  • Filtry autorizace a filtry prostředků, které jsou zkrácené.
  • Filtry výjimek.

Například následující filtr se vždy spustí a nastaví výsledek akce ( ) s kódem stavu nezpracované entity ObjectResult 422, když selže vyjednávání obsahu:

public class UnprocessableResultFilter : Attribute, IAlwaysRunResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is StatusCodeResult statusCodeResult &&
            statusCodeResult.StatusCode == (int) HttpStatusCode.UnsupportedMediaType)
        {
            context.Result = new ObjectResult("Can't process this!")
            {
                StatusCode = (int) HttpStatusCode.UnsupportedMediaType,
            };
        }
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
    }
}

IFilterFactory

IFilterFactory implementuje IFilterMetadata . Proto je IFilterFactory možné instanci použít jako instanci kdekoli v IFilterMetadata kanálu filtru. Když se modul runtime připraví na vyvolání filtru, pokusí se ho přetypovat na IFilterFactory . Pokud je toto přetypování úspěšné, je volána metoda pro CreateInstance vytvoření IFilterMetadata instance, která je vyvolána. To poskytuje flexibilní návrh, protože přesný kanál filtru není nutné explicitně nastavovat při spuštění aplikace.

IFilterFactory je možné implementovat pomocí implementací vlastních atributů jako dalšího přístupu k vytváření filtrů:

public class AddHeaderWithFactoryAttribute : Attribute, IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new InternalAddHeaderFilter();
    }

    private class InternalAddHeaderFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "Internal", new string[] { "My header" });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Předchozí kód můžete otestovat spuštěním ukázky stahování:

  • Vyvolání vývojářských nástrojů F12
  • Přejděte na adresu https://localhost:5001/Sample/HeaderWithFactory.

Vývojářské nástroje F12 zobrazují následující hlavičky odpovědi přidané ukázkovým kódem:

  • author (autor):Joe Smith
  • globaladdheader:Result filter added to MvcOptions.Filters
  • interní:My header

Předchozí kód vytvoří hlavičku internal: My header response.

Implementace IFilterFactory u atributu

Implementují se IFilterFactory filtry, které jsou užitečné pro filtry, které:

  • Nevyžaduje předávání parametrů.
  • Musí mít závislosti konstruktoru, které musí být vyplněné induiérou.

TypeFilterAttribute implementuje IFilterFactory . IFilterFactory zpřístupňuje CreateInstance metodu pro vytvoření IFilterMetadata instance. CreateInstance načte zadaný typ z kontejneru services (DI).

public class SampleActionFilterAttribute : TypeFilterAttribute
{
    public SampleActionFilterAttribute():base(typeof(SampleActionFilterImpl))
    {
    }

    private class SampleActionFilterImpl : IActionFilter
    {
        private readonly ILogger _logger;
        public SampleActionFilterImpl(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            _logger.LogInformation("Business action starting...");
            // perform some business logic work

        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // perform some business logic work
            _logger.LogInformation("Business action completed.");
        }
    }
}

Následující kód ukazuje tři přístupy k použití [SampleActionFilter] :

[SampleActionFilter]
public IActionResult FilterTest()
{
    return Content($"From FilterTest");
}

[TypeFilter(typeof(SampleActionFilterAttribute))]
public IActionResult TypeFilterTest()
{
    return Content($"From ServiceFilterTest");
}

// ServiceFilter must be registered in ConfigureServices or
// System.InvalidOperationException: No service for type '<filter>' has been registered.
// Is thrown.
[ServiceFilter(typeof(SampleActionFilterAttribute))]
public IActionResult ServiceFilterTest()
{
    return Content($"From ServiceFilterTest");
}

V předchozím kódu je upřednostňovaným přístupem k použití metody [SampleActionFilter] SampleActionFilter .

Použití middlewaru v kanálu filtru

Filtry prostředků fungují jako middleware v tom, že obklopují provádění všeho, co přijde později v kanálu. Filtry se ale liší od middlewaru v tom, že jsou součástí modulu runtime ASP.NET Core, což znamená, že mají přístup k ASP.NET Core kontextu a konstruktorům.

Pokud chcete middleware použít jako filtr, vytvořte typ s metodou, která určuje middleware, který se Configure má vložit do kanálu filtru. Následující příklad používá middleware lokalizace k vytvoření aktuální jazykové verze pro požadavek:

public class LocalizationPipeline
{
    public void Configure(IApplicationBuilder applicationBuilder)
    {
        var supportedCultures = new[]
        {
            new CultureInfo("en-US"),
            new CultureInfo("fr")
        };

        var options = new RequestLocalizationOptions
        {

            DefaultRequestCulture = new RequestCulture(culture: "en-US", 
                                                     uiCulture: "en-US"),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        };
        options.RequestCultureProviders = new[] 
            { new RouteDataRequestCultureProvider() { Options = options } };

        applicationBuilder.UseRequestLocalization(options);
    }
}

Ke MiddlewareFilterAttribute spuštění middlewaru použijte :

[Route("{culture}/[controller]/[action]")]
[MiddlewareFilter(typeof(LocalizationPipeline))]
public IActionResult CultureFromRouteData()
{
    return Content($"CurrentCulture:{CultureInfo.CurrentCulture.Name},"
        + $"CurrentUICulture:{CultureInfo.CurrentUICulture.Name}");
}

Middlewarové filtry běží ve stejné fázi kanálu filtru jako filtry prostředků před vytvořením vazby modelu a po zbytku kanálu.

Bezpečnost vlákna

Při předávání instance filtru do , místo jeho , je filtr jednosloupce a není Add Type bezpečný pro vlákno.

Další akce