ASP.NET Core에서 필터링Filters in ASP.NET Core

작성자: Rick Anderson, Tom DykstraSteve SmithBy Rick Anderson, Tom Dykstra, and Steve Smith

ASP.NET Core MVC에서 필터를 사용하면 요청 처리 파이프라인의 특정 단계 전후에 코드를 실행할 수 있습니다.Filters in ASP.NET Core MVC allow you to run code before or after specific stages in the request processing pipeline.

중요

이 항목은 Razor 페이지에 적용되지 않습니다.This topic does not apply to Razor Pages. ASP.NET Core 2.1 이상에서는 Razor 페이지에 대해 IPageFilterIAsyncPageFilter를 지원합니다.ASP.NET Core 2.1 and later supports IPageFilter and IAsyncPageFilter for Razor Pages. 자세한 내용은 Razor 페이지에 대한 필터 메서드를 참조하세요.For more information, see Filter methods for Razor Pages.

기본 제공 필터는 다음과 같은 작업을 처리합니다.Built-in filters handle tasks such as:

  • 권한 부여(사용자가 권한이 없는 리소스에 액세스 방지).Authorization (preventing access to resources a user isn't authorized for).
  • 모든 요청이 HTTPS를 사용하는지 확인합니다.Ensuring that all requests use HTTPS.
  • 응답 캐싱(요청 파이프라인을 단락하면 캐시된 응답을 반환합니다).Response caching (short-circuiting the request pipeline to return a cached response).

사용자 지정 필터를 만들어 교차 편집 문제를 처리할 수 있습니다.Custom filters can be created to handle cross-cutting concerns. 필터는 작업 간 코드 중복을 방지할 수 있습니다.Filters can avoid duplicating code across actions. 예를 들어 오류 처리 예외 필터는 오류 처리를 통합할 수 있습니다.For example, an error handling exception filter could consolidate error handling.

GitHub에서 샘플 보기 또는 다운로드View or download sample from GitHub.

필터 작동 방법How do filters work?

필터는 필터 파이프라인이라고도 하는 MVC 동작 호출 파이프라인내에서 실행됩니다.Filters run within the MVC action invocation pipeline, sometimes referred to as the filter pipeline. 필터 파이프라인은 MVC가 실행할 작업을 선택한 후에 실행됩니다.The filter pipeline runs after MVC selects the action to execute.

다른 미들웨어, 라우팅 미들웨어, 작업 선택 영역 및 MVC 작업 호출 파이프라인을 통해 요청이 처리됩니다.

필터 형식Filter types

각 필터 형식은 필터 파이프라인의 다른 단계에서 실행됩니다.Each filter type is executed at a different stage in the filter pipeline.

  • 권한 부여 필터는 먼저 실행되고 현재 사용자가 현재 요청에 대한 권한이 있는지 여부를 결정하는 데 사용됩니다.Authorization filters run first and are used to determine whether the current user is authorized for the current request. 요청이 인증되지 않는 경우 파이프라인을 단락(short-circuit) 처리할 수 있습니다.They can short-circuit the pipeline if a request is unauthorized.

  • 리소스 필터는 권한 부여 이후 먼저 요청을 처리합니다.Resource filters are the first to handle a request after authorization. 필터 파이프라인의 나머지 이전 및 파이프라인의 나머지가 완료된 후에 코드를 실행할 수 있습니다.They can run code before the rest of the filter pipeline, and after the rest of the pipeline has completed. 캐싱을 구현하거나 그렇지 않은 경우 성능상의 이유로 필터 파이프라인을 단락(short-circuit) 처리하는 경우에 유용합니다.They're useful to implement caching or otherwise short-circuit the filter pipeline for performance reasons. 모델 바인딩 전에 실행하므로 모델 바인딩에 영향을 줄 수 있습니다.They run before model binding, so they can influence model binding.

  • 작업 필터는 개별 작업 메서드가 호출된 전후에 즉시 코드를 실행할 수 있습니다.Action filters can run code immediately before and after an individual action method is called. 작업에 전달된 인수 및 작업에서 반환된 결과를 조작하는 데 사용할 수 있습니다.They can be used to manipulate the arguments passed into an action and the result returned from the action.

  • 예외 필터는 응답 본문에 무언가 쓰여지기 전에 발생한 처리되지 않은 예외에 전역 정책을 적용하는 데 사용됩니다.Exception filters are used to apply global policies to unhandled exceptions that occur before anything has been written to the response body.

  • 결과 필터는 개별 작업이 실행된 전후에 즉시 코드를 실행할 수 있습니다.Result filters can run code immediately before and after the execution of individual action results. 작업 메서드가 성공적으로 실행되는 경우에만 실행됩니다.They run only when the action method has executed successfully. 보기 또는 포맷터 실행을 둘러싸야 하는 논리에 유용합니다.They are useful for logic that must surround view or formatter execution.

다음 다이어그램에서는 이러한 필터 형식이 필터 파이프라인에서 상호 작용하는 방법을 보여줍니다.The following diagram shows how these filter types interact in the filter pipeline.

요청은 권한 부여 필터, 리소스 필터, 모델 바인딩, 작업 필터, 작업 실행 및 작업 결과 변환, 예외 필터, 결과 필터 및 결과 실행을 통해 처리됩니다.

구현Implementation

필터는 다른 인터페이스 정의를 통해 동기 및 비동기 구현을 모두 지원합니다.Filters support both synchronous and asynchronous implementations through different interface definitions.

동기 필터는 해당 파이프라인 단계가 OnStageExecuting 및 OnStageExecuted를 정의하는 전후에 코드를 실행할 수 있습니다.Synchronous filters that can run code both before and after their pipeline stage define OnStageExecuting and OnStageExecuted methods. 예를 들어 OnActionExecuting은 작업 메서드를 호출하기 전에 호출되고 OnActionExecuted는 작업 메서드가 반환한 후에 호출됩니다.For example, OnActionExecuting is called before the action method is called, and OnActionExecuted is called after the action method returns.

using FiltersSample.Helper;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // do something before the action executes
        }

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

비동기 필터는 단일 OnStageExecutionAsync 메서드를 정의합니다.Asynchronous filters define a single OnStageExecutionAsync method. 이 메서드는 필터의 파이프라인 단계를 실행하는 FilterTypeExecutionDelegate 대리자를 사용합니다.This method takes a FilterTypeExecutionDelegate delegate which executes the filter's pipeline stage. 예를 들어 ActionExecutionDelegate는 작업 메서드 또는 다음 작업 필터를 호출하고 호출 전후에 코드를 실행할 수 있습니다.For example, ActionExecutionDelegate calls the action method or next action filter, and you can execute code before and after you call it.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleAsyncActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(
            ActionExecutingContext context,
            ActionExecutionDelegate next)
        {
            // do something before the action executes
            var resultContext = await next();
            // do something after the action executes; resultContext.Result will be set
        }
    }
}

단일 클래스에서 여러 필터 단계에 대한 인터페이스를 구현할 수 있습니다.You can implement interfaces for multiple filter stages in a single class. 예를 들어 ActionFilterAttribute 클래스는 IActionFilter, IResultFilter 및 해당 비동기 값을 구현합니다.For example, the ActionFilterAttribute class implements IActionFilter, IResultFilter, and their async equivalents.

참고

필터 인터페이스의 동기 또는 비동기 버전 중 하나를 구현합니다.Implement either the synchronous or the async version of a filter interface, not both. 프레임워크는 먼저 필터가 비동기 인터페이스를 구현하는지를 확인하고 그렇다면 이를 호출합니다.The framework checks first to see if the filter implements the async interface, and if so, it calls that. 그렇지 않으면 동기 인터페이스의 메서드를 호출합니다.If not, it calls the synchronous interface's method(s). 하나의 클래스에 두 인터페이스를 모두 구현하는 경우 비동기 메서드만이 호출됩니다.If you were to implement both interfaces on one class, only the async method would be called. ActionFilterAttribute와 같은 추상 클래스를 사용하는 경우 각 필터 형식에 대한 동기 메서드 또는 비동기 메서드만을 재정의합니다.When using abstract classes like ActionFilterAttribute you would override only the synchronous methods or the async method for each filter type.

IFilterFactoryIFilterFactory

IFilterFactoryIFilterMetadata를 구현합니다.IFilterFactory implements IFilterMetadata. 따라서 IFilterFactory 인스턴스를 필터 파이프라인에서 IFilterMetadata 인스턴스로 사용할 수 있습니다.Therefore, an IFilterFactory instance can be used as an IFilterMetadata instance anywhere in the filter pipeline. 프레임워크가 필터를 호출하려고 준비하는 경우 IFilterFactory으로 캐스팅을 시도합니다.When the framework prepares to invoke the filter, it attempts to cast it to an IFilterFactory. 해당 캐스트에 성공하면 CreateInstance 메서드를 호출하여 호출되는 IFilterMetadata 인스턴스를 만듭니다.If that cast succeeds, the CreateInstance method is called to create the IFilterMetadata instance that will be invoked. 앱이 시작될 때 정확한 필터 파이프라인을 명시적으로 설정할 필요가 없으므로 유연한 디자인을 제공합니다.This provides a flexible design, since the precise filter pipeline doesn't need to be set explicitly when the app starts.

필터를 만드는 다른 방법으로 고유한 특성 구현에서 IFilterFactory를 구현할 수 있습니다.You can implement IFilterFactory on your own attribute implementations as another approach to creating filters:

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[] { "Header Added" });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

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

기본 제공 필터 특성Built-in filter attributes

프레임워크에는 하위 클래스를 지정하고 사용자 지정할 수 있는 기본 제공 특성 기반 필터가 포함됩니다.The framework includes built-in attribute-based filters that you can subclass and customize. 예를 들어 다음 결과 필터는 응답에 헤더를 추가합니다.For example, the following Result filter adds a header to the response.

using Microsoft.AspNetCore.Mvc.Filters;

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

특성을 사용하면 위의 예제와 같이 필터에서 인수를 허용할 수 있습니다.Attributes allow filters to accept arguments, as shown in the example above. 컨트롤러나 작업 메서드에 이 특성을 추가하고 HTTP 헤더의 이름 및 값을 지정합니다.You would add this attribute to a controller or action method and specify the name and value of the HTTP header:

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

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

Index 작업의 결과는 다음과 같습니다. 응답 헤더는 오른쪽 아래에 표시됩니다.The result of the Index action is shown below - the response headers are displayed on the bottom right.

작성자 Steve Smith  비롯한 응답 헤더를 보여주는 Microsoft Edge의 개발자 도구

여러 필터 인터페이스에는 사용자 지정 구현에 대한 기본 클래스로 사용할 수 있는 해당 특성이 있습니다.Several of the filter interfaces have corresponding attributes that can be used as base classes for custom implementations.

필터 특성:Filter attributes:

  • ActionFilterAttribute
  • ExceptionFilterAttribute
  • ResultFilterAttribute
  • FormatFilterAttribute
  • ServiceFilterAttribute
  • TypeFilterAttribute

TypeFilterAttributeServiceFilterAttribute이 문서의 뒷부분에 설명되어 있습니다.TypeFilterAttribute and ServiceFilterAttribute are explained later in this article.

필터 범위 및 실행 순서Filter scopes and order of execution

세 개의 범위 중 하나에서 파이프라인에 필터를 추가할 수 있습니다.A filter can be added to the pipeline at one of three scopes. 특성을 사용하여 특정 작업 메서드 또는 컨트롤러 클래스에 필터를 추가할 수 있습니다.You can add a filter to a particular action method or to a controller class by using an attribute. 또는 모든 컨트롤러와 동작에 대해 전역적으로 필터를 등록할 수 있습니다.Or you can register a filter globally for all controllers and actions. ConfigureServicesMvcOptions.Filters 컬렉션에 추가하여 전역적으로 필터를 추가합니다.Filters are added globally by adding it to the MvcOptions.Filters collection in ConfigureServices:

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(SampleActionFilter)); // by type
        options.Filters.Add(new SampleGlobalActionFilter()); // an instance
    });

    services.AddScoped<AddHeaderFilterWithDi>();
}

기본 실행 순서Default order of execution

파이프라인의 특정 단계에 여러 개의 필터가 있는 경우 범위는 기본 필터 실행 순서를 결정합니다.When there are multiple filters for a particular stage of the pipeline, scope determines the default order of filter execution. 전역 필터는 메서드 필터를 둘러싼 클래스 필터를 둘러쌉니다.Global filters surround class filters, which in turn surround method filters. 범위가 증가할 때마다 중첩되는 인형처럼 이전 범위를 둘러싸게 되므로 이를 "러시아 인형"이라고도 합니다.This is sometimes referred to as "Russian doll" nesting, as each increase in scope is wrapped around the previous scope, like a nesting doll. 일반적으로 명시적으로 순서를 결정할 필요 없이 원하는 재정의 동작을 가져옵니다.You generally get the desired overriding behavior without having to explicitly determine ordering.

이 중첩의 결과로 필터의 after 코드는 before 코드의 역순으로 실행됩니다.As a result of this nesting, the after code of filters runs in the reverse order of the before code. 시퀀스는 다음과 같습니다.The sequence looks like this:

  • 전역적으로 적용된 필터의 before 코드The before code of filters applied globally
    • 컨트롤러에 적용된 필터의 before 코드The before code of filters applied to controllers
      • 작업 메서드에 적용된 필터의 before 코드The before code of filters applied to action methods
      • 작업 메서드에 적용된 필터의 after 코드The after code of filters applied to action methods
    • 컨트롤러에 적용된 필터의 after 코드The after code of filters applied to controllers
  • 전역적으로 적용된 필터의 after 코드The after code of filters applied globally

필터 메서드가 동기 작업 필터에 대해 호출되는 순서를 보여주는 예제는 다음과 같습니다.Here's an example that illustrates the order in which filter methods are called for synchronous Action filters.

SequenceSequence 필터 범위Filter scope 필터 메서드Filter method
11 GlobalGlobal OnActionExecuting
22 컨트롤러Controller OnActionExecuting
33 메서드Method OnActionExecuting
44 메서드Method OnActionExecuted
55 컨트롤러Controller OnActionExecuted
66 GlobalGlobal OnActionExecuted

이 시퀀스는 다음을 보여 줍니다.This sequence shows:

  • 메서드 필터는 컨트롤러 필터 내에서 중첩됩니다.The method filter is nested within the controller filter.
  • 컨트롤러 필터는 전역 필터 내에서 중첩됩니다.The controller filter is nested within the global filter.

즉, 비동기 필터의 OnStageExecutionAsync 메서드 내에 있는 경우 코드가 스택에 있는 반면 좁은 범위를 가진 모든 필터가 실행됩니다.To put it another way, if you're inside an async filter's OnStageExecutionAsync method, all of the filters with a tighter scope run while your code is on the stack.

참고

Controller 기본 클래스에서 상속되는 모든 컨트롤러에는 OnActionExecutingOnActionExecuted 메서드가 포함됩니다.Every controller that inherits from the Controller base class includes OnActionExecuting and OnActionExecuted methods. 이러한 메서드는 지정된 작업에 대해 실행되는 필터를 래핑합니다. OnActionExecuting은 필터 이전에 호출되고 OnActionExecuted는 모든 필터 이후에 호출됩니다.These methods wrap the filters that run for a given action: OnActionExecuting is called before any of the filters, and OnActionExecuted is called after all of the filters.

기본 순서 재정의Overriding the default order

IOrderedFilter를 구현하여 실행의 기본 시퀀스를 재정의할 수 있습니다.You can override the default sequence of execution by implementing IOrderedFilter. 이 인터페이스는 실행 순서를 결정하는 범위에 대해 우선 순위를 갖는 Order 속성을 노출합니다.This interface exposes an Order property that takes precedence over scope to determine the order of execution. 낮은 Order 값을 가진 필터는 Order라는 큰 값을 가진 필터 이전에 해당 before 코드를 실행합니다.A filter with a lower Order value will have its before code executed before that of a filter with a higher value of Order. 낮은 Order 값을 가진 필터는 Order라는 큰 값을 가진 필터 이후에 해당 after 코드를 실행합니다.A filter with a lower Order value will have its after code executed after that of a filter with a higher Order value. 생성자 매개 변수를 사용하여 Order 속성을 설정할 수 있습니다.You can set the Order property by using a constructor parameter:

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

위의 예제에 표시된 3개의 동일한 작업 필터가 있지만 컨트롤러 및 글로벌 필터의 Order 속성을 각각 1 및 2로 설정한 경우 실행 순서는 반대입니다.If you have the same 3 Action filters shown in the preceding example but set the Order property of the controller and global filters to 1 and 2 respectively, the order of execution would be reversed.

SequenceSequence 필터 범위Filter scope Order 속성Order property 필터 메서드Filter method
11 메서드Method 00 OnActionExecuting
22 컨트롤러Controller 11 OnActionExecuting
33 GlobalGlobal 22 OnActionExecuting
44 GlobalGlobal 22 OnActionExecuted
55 컨트롤러Controller 11 OnActionExecuted
66 메서드Method 00 OnActionExecuted

Order 속성은 필터가 실행되는 순서를 결정할 때 범위를 결정합니다.The Order property trumps scope when determining the order in which filters will run. 필터가 순서에 따라 먼저 정렬된 다음, 범위는 연결을 끊는 데 사용됩니다.Filters are sorted first by order, then scope is used to break ties. 모든 기본 제공 필터는 IOrderedFilter을 구현하고 기본 Order 값을 0으로 설정합니다.All of the built-in filters implement IOrderedFilter and set the default Order value to 0. 기본 제공 필터의 경우 Order를 0이 아닌 값으로 설정하지 않는 한 범위가 순서를 결정합니다.For built-in filters, scope determines order unless you set Order to a non-zero value.

취소 및 단락(short-circuit)Cancellation and short circuiting

제공된 context 매개 변수의 Result 속성을 필터 메서드로 설정하여 언제든지 필터 파이프라인을 단락(short-circuit) 처리할 수 있습니다.You can short-circuit the filter pipeline at any point by setting the Result property on the context parameter provided to the filter method. 예를 들어 다음과 같은 리소스 필터는 파이프라인의 나머지 부분이 실행되지 않도록 방지합니다.For instance, the following Resource filter prevents the rest of the pipeline from executing.

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

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

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }
}

다음 코드에서 ShortCircuitingResourceFilterAddHeader 필터는 SomeResource 작업 메서드를 대상으로 지정합니다.In the following code, both the ShortCircuitingResourceFilter and the AddHeader filter target the SomeResource action method. ShortCircuitingResourceFilter:The ShortCircuitingResourceFilter:

  • 리소스 필터이고 AddHeader이 작업 필터이기 때문에 먼저 실행합니다.Runs first, because it's a Resource Filter and AddHeader is an Action Filter.
  • 나머지 파이프라인을 단락(Short-circuit) 처리합니다.Short-circuits the rest of the pipeline.

따라서 AddHeader 필터는 SomeResource 작업에 대해 절대 실행되지 않습니다.Therefore the AddHeader filter never runs for the SomeResource action. 이 동작은 작업 메서드 수준에서 두 필터를 적용한 경우에도 동일하며 먼저 실행되는 ShortCircuitingResourceFilter를 제공합니다.This behavior would be the same if both filters were applied at the action method level, provided the ShortCircuitingResourceFilter ran first. 해당 필터 형식 또는 Order 속성의 명시적 사용으로 인해 ShortCircuitingResourceFilter이 실행됩니다.The ShortCircuitingResourceFilter runs first because of its filter type, or by explicit use of Order property.

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

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

종속성 주입Dependency injection

형식 또는 인스턴스별로 필터를 추가할 수 있습니다.Filters can be added by type or by instance. 인스턴스를 추가하는 경우 해당 인스턴스가 모든 요청에 사용됩니다.If you add an instance, that instance will be used for every request. 형식을 추가하면 활성화됩니다. 즉, DI(종속성 주입)에서 각 요청에 대한 인스턴스를 만들고 모든 생성자 종속성을 채웁니다.If you add a type, it will be type-activated, meaning an instance will be created for each request and any constructor dependencies will be populated by dependency injection (DI). 형식별 필터를 추가하는 작업은 filters.Add(new TypeFilterAttribute(typeof(MyFilter)))에 해당합니다.Adding a filter by type is equivalent to filters.Add(new TypeFilterAttribute(typeof(MyFilter))).

특성으로 구현되고 컨트롤러 클래스 또는 작업 메서드에 직접 추가되는 필터에는 DI(종속성 주입)에서 제공하는 생성자 종속성이 없을 것입니다.Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by dependency injection (DI). 특성이 적용될 때 해당 생성자 매개 변수가 제공되어야 하기 때문입니다.This is because attributes must have their constructor parameters supplied where they're applied. 특성이 작동하는 방법의 제한 사항입니다.This is a limitation of how attributes work.

필터에 DI에서 액세스해야 하는 종속성이 있는 경우 지원되는 여러 가지 방법이 있습니다.If your filters have dependencies that you need to access from DI, there are several supported approaches. 다음 중 하나를 사용하여 클래스 또는 작업 메서드에 필터를 적용할 수 있습니다.You can apply your filter to a class or action method using one of the following:

  • ServiceFilterAttribute
  • TypeFilterAttribute
  • 특성에서 구현된 IFilterFactoryIFilterFactory implemented on your attribute

참고

DI에서 가져오려는 하나의 종속성은 로거입니다.One dependency you might want to get from DI is a logger. 그러나 기본 제공 프레임워크 로깅 기능이 필요한 기능을 이미 제공할 수 있으므로 로깅 용도로 필터를 만들고 사용하지 않습니다.However, avoid creating and using filters purely for logging purposes, since the built-in framework logging features may already provide what you need. 필터에 로깅을 추가하려는 경우 MVC 작업 또는 다른 프레임워크 이벤트보다 비즈니스 도메인 문제 또는 필터에 특정된 동작에 집중해야 합니다.If you're going to add logging to your filters, it should focus on business domain concerns or behavior specific to your filter, rather than MVC actions or other framework events.

ServiceFilterAttributeServiceFilterAttribute

ServiceFilter는 DI에서 필터의 인스턴스를 검색합니다.A ServiceFilter retrieves an instance of the filter from DI. 필터를 ConfigureServices의 컨테이너에 추가하고, ServiceFilter 특성에서 참조합니다.You add the filter to the container in ConfigureServices, and reference it in a ServiceFilter attribute

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(SampleActionFilter)); // by type
        options.Filters.Add(new SampleGlobalActionFilter()); // an instance
    });

    services.AddScoped<AddHeaderFilterWithDi>();
}
[ServiceFilter(typeof(AddHeaderFilterWithDi))]
public IActionResult Index()
{
    return View();
}

필터 형식을 등록하지 않고 ServiceFilter를 사용하여 예외를 발생시킵니다.Using ServiceFilter without registering the filter type results in an exception:

System.InvalidOperationException: No service for type
'FiltersSample.Filters.AddHeaderFilterWithDI' has been registered.

ServiceFilterAttributeIFilterFactory를 구현합니다.ServiceFilterAttribute implements IFilterFactory. IFilterFactoryIFilterMetadata 인스턴스를 만들기 위해 CreateInstance 메서드를 노출합니다.IFilterFactory exposes the CreateInstance method for creating an IFilterMetadata instance. CreateInstance 메서드는 서비스 컨테이너(DI)에서 지정된 형식을 로드합니다.The CreateInstance method loads the specified type from the services container (DI).

TypeFilterAttributeTypeFilterAttribute

TypeFilterAttributeServiceFilterAttribute와 비슷하지만 해당 형식은 DI 컨테이너에서 직접 확인되지 않습니다.TypeFilterAttribute is similar to ServiceFilterAttribute, but its type isn't resolved directly from the DI container. Microsoft.Extensions.DependencyInjection.ObjectFactory를 사용하여 형식을 인스턴스화합니다.It instantiates the type by using Microsoft.Extensions.DependencyInjection.ObjectFactory.

이 차이 때문에:Because of this difference:

  • TypeFilterAttribute을 사용하여 참조되는 형식은 먼저 컨테이너를 사용하여 등록할 필요가 없습니다.Types that are referenced using the TypeFilterAttribute don't need to be registered with the container first. 컨테이너에서 충족하는 종속성을 갖고 있습니다.They do have their dependencies fulfilled by the container.
  • TypeFilterAttribute는 형식에 대한 생성자 인수를 필요에 따라 허용할 수 있습니다.TypeFilterAttribute can optionally accept constructor arguments for the type.

다음 예제에서는 TypeFilterAttribute를 사용하여 인수를 형식에 전달하는 방법을 보여줍니다.The following example demonstrates how to pass arguments to a type using TypeFilterAttribute:

[TypeFilter(typeof(AddHeaderAttribute),
    Arguments = new object[] { "Author", "Steve Smith (@ardalis)" })]
public IActionResult Hi(string name)
{
    return Content($"Hi {name}");
}

특성에서 구현된 IFilterFactoryIFilterFactory implemented on your attribute

다음과 같은 필터가 있는 경우:If you have a filter that:

  • 인수가 필요하지 않습니다.Doesn't require any arguments.
  • DI에서 채워야 할 생성자 종속성이 있습니다.Has constructor dependencies that need to be filled by DI.

[TypeFilter(typeof(FilterType))] 대신에 클래스 및 메서드에 대한 자신의 명명된 특성을 사용할 수 있습니다).You can use your own named attribute on classes and methods instead of [TypeFilter(typeof(FilterType))]). 다음 필터에서는 이를 구현하는 방법을 보여줍니다.The following filter shows how this can be implemented:

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

이 필터는 [TypeFilter] 또는 [ServiceFilter]를 사용하는 대신 [SampleActionFilter] 구문을 사용하여 클래스 또는 메서드에 적용될 수 있습니다.This filter can be applied to classes or methods using the [SampleActionFilter] syntax, instead of having to use [TypeFilter] or [ServiceFilter].

권한 부여 필터Authorization filters

*권한 부여 필터:*Authorization filters:

  • 동작 메서드에 대한 액세스를 제어합니다.Control access to action methods.
  • 필터 파이프라인 내에서 실행되어야 할 첫 번째 필터입니다.Are the first filters to be executed within the filter pipeline.
  • before 메서드는 있지만 after 메서드는 없습니다.Have a before method, but no after method.

고유한 권한 부여 프레임워크를 작성하는 경우에만 사용자 지정 권한 부여 필터를 작성해야 합니다.You should only write a custom authorization filter if you are writing your own authorization framework. 사용자 지정 필터를 작성하는 대신 권한 부여 정책을 구성하거나 사용자 지정 권한 부여 정책을 작성하는 것이 좋습니다.Prefer configuring your authorization policies or writing a custom authorization policy over writing a custom filter. 기본 제공 필터 구현은 권한 부여 시스템을 호출합니다.The built-in filter implementation is just responsible for calling the authorization system.

무엇도 예외를 처리하지 않으므로 권한 부여 필터 내에서 예외를 throw해서는 안됩니다(예외 필터는 처리하지 않음).You shouldn't throw exceptions within authorization filters, since nothing will handle the exception (exception filters won't handle them). 예외가 발생할 경우 과제 실행을 고려합니다.Consider issuing a challenge when an exception occurs.

권한 부여에 대해 자세히 알아봅니다.Learn more about Authorization.

리소스 필터Resource filters

  • IResourceFilter 또는 IAsyncResourceFilter 인터페이스 중 하나를 구현합니다.Implement either the IResourceFilter or IAsyncResourceFilter interface,
  • 해당 실행은 필터 파이프라인 대부분을 래핑합니다.Their execution wraps most of the filter pipeline.
  • 권한 부여 필터만 리소스 필터 전에 실행됩니다.Only Authorization filters run before Resource filters.

리소스 필터는 요청을 수행하는 대부분의 작업을 단락(short-circuit) 처리해야 하는 경우에 유용합니다.Resource filters are useful to short-circuit most of the work a request is doing. 예를 들어 응답이 캐시에 있는 경우 캐싱 필터는 파이프라인의 나머지 부분을 방지할 수 있습니다.For example, a caching filter can avoid the rest of the pipeline if the response is in the cache.

앞에서 살펴본 단락(short-circuit) 리소스 필터는 리소스 필터의 예입니다.The short circuiting resource filter shown earlier is one example of a resource filter. 다른 예는 DisableFormValueModelBindingAttribute입니다.Another example is DisableFormValueModelBindingAttribute:

  • 모델 바인딩이 양식 데이터에 액세스하는 것을 방지합니다.It prevents model binding from accessing the form data.
  • 대형 파일 업로드에 유용하며 형식이 메모리로 읽히는 것을 방지하려 합니다.It's useful for large file uploads and want to prevent the form from being read into memory.

작업 필터Action filters

작업 필터:Action filters:

  • IActionFilter 또는 IAsyncActionFilter 인터페이스 중 하나를 구현합니다.Implement either the IActionFilter or IAsyncActionFilter interface.
  • 해당 실행은 작업 메서드의 실행을 둘러쌉니다.Their execution surrounds the execution of action methods.

샘플 작업 필터는 다음과 같습니다.Here's a sample action filter:

public class SampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // do something before the action executes
    }

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

ActionExecutingContext는 다음과 같은 속성을 제공합니다.The ActionExecutingContext provides the following properties:

  • ActionArguments - 작업에 대한 입력을 조작할 수 있습니다.ActionArguments - lets you manipulate the inputs to the action.
  • Controller - 컨트롤러 인스턴스를 조작할 수 있습니다.Controller - lets you manipulate the controller instance.
  • Result - 작업 메서드 및 후속 작업 필터의 단락(short-circuit) 실행을 설정합니다.Result - setting this short-circuits execution of the action method and subsequent action filters. 또한 예외를 throw하면 작업 메서드 및 후속 필터의 실행을 방지하지만 성공적인 결과가 아닌 실패로 처리됩니다.Throwing an exception also prevents execution of the action method and subsequent filters, but is treated as a failure instead of a successful result.

ActionExecutedContextControllerResult 및 다음과 같은 속성을 제공합니다.The ActionExecutedContext provides Controller and Result plus the following properties:

  • Canceled - 작업 실행이 다른 필터에 의해 단락(short-circuit) 처리된 경우 true입니다.Canceled - will be true if the action execution was short-circuited by another filter.
  • Exception - 작업 또는 후속 작업 필터에서 예외가 throw된 경우 null이 아닙니다.Exception - will be non-null if the action or a subsequent action filter threw an exception. 이 속성을 효과적으로 null로 설정하면 예외를 '처리'하고 Result이 정상적으로 작업 메서드에서 반환된 것처럼 실행됩니다.Setting this property to null effectively 'handles' an exception, and Result will be executed as if it were returned from the action method normally.

IAsyncActionFilter의 경우 ActionExecutionDelegate에 대한 호출:For an IAsyncActionFilter, a call to the ActionExecutionDelegate:

  • 후속 작업 필터 및 작업 메서드를 실행합니다.Executes any subsequent action filters and the action method.
  • ActionExecutedContext를 반환합니다.returns ActionExecutedContext.

단락(short-circuit) 처리하려면 ActionExecutingContext.Result을 일부 결과 인스턴스에 를 할당하고 ActionExecutionDelegate를 호출하지 않아야 합니다.To short-circuit, assign ActionExecutingContext.Result to some result instance and don't call the ActionExecutionDelegate.

프레임워크는 하위 클래스를 지정할 수 있는 추상 ActionFilterAttribute을 제공합니다.The framework provides an abstract ActionFilterAttribute that you can subclass.

작업 필터를 사용하여 모델 상태를 확인하고 상태가 잘못된 경우 오류를 반환할 수 있습니다.You can use an action filter to validate model state and return any errors if the state is invalid:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }
    }
}

OnActionExecuted 메서드는 작업 메서드 이후에 실행되고 ActionExecutedContext.Result 속성을 통해 작업의 결과를 확인하고 조작할 수 있습니다.The OnActionExecuted method runs after the action method and can see and manipulate the results of the action through the ActionExecutedContext.Result property. ActionExecutedContext.Canceled는 작업 실행이 다른 필터에 의해 단락(short-circuit) 처리된 경우 true로 설정됩니다.ActionExecutedContext.Canceled will be set to true if the action execution was short-circuited by another filter. ActionExecutedContext.Exception은 작업 또는 후속 작업 필터에서 예외가 throw된 경우 null이 아닌 값으로 설정됩니다.ActionExecutedContext.Exception will be set to a non-null value if the action or a subsequent action filter threw an exception. ActionExecutedContext.Exception을 Null로 설정:Setting ActionExecutedContext.Exception to null:

  • 예외를 효과적으로 ‘처리’합니다.Effectively 'handles' an exception.
  • ActionExectedContext.Result은 작업 메서드에서 정상적으로 반환되는 것처럼 실행됩니다.ActionExectedContext.Result is executed as if it were returned normally from the action method.

예외 필터Exception filters

예외 필터IExceptionFilter 또는 IAsyncExceptionFilter 인터페이스 중 하나를 구현합니다.Exception filters implement either the IExceptionFilter or IAsyncExceptionFilter interface. 앱에서 일반적인 오류 처리 정책을 구현하는 데 사용할 수 있습니다.They can be used to implement common error handling policies for an app.

다음 샘플 예외 필터는 사용자 지정 개발자 오류 보기를 사용하여 앱을 개발 중인 경우에 발생하는 예외에 대한 세부 정보를 표시합니다.The following sample exception filter uses a custom developer error view to display details about exceptions that occur when the app is in development:

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    private readonly IHostingEnvironment _hostingEnvironment;
    private readonly IModelMetadataProvider _modelMetadataProvider;

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

    public override void OnException(ExceptionContext context)
    {
        if (!_hostingEnvironment.IsDevelopment())
        {
            // do nothing
            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;
    }
}

예외 필터:Exception filters:

  • before 및 after 이벤트는 없습니다.Don't have before and after events.
  • OnException 또는 OnExceptionAsync를 구현합니다.Implement OnException or OnExceptionAsync.
  • 컨트롤러 생성, 모델 바인딩, 작업 필터 또는 작업 메서드에서 발생하는 처리되지 않은 예외를 처리합니다.Handle unhandled exceptions that occur in controller creation, model binding, action filters, or action methods.
  • 리소스 필터, 결과 필터 또는 MVC 결과 실행에서 발생하는 예외를 catch하지 않습니다.Do not catch exceptions that occur in Resource filters, Result filters, or MVC Result execution.

예외를 처리하려면 ExceptionContext.ExceptionHandled 속성을 true로 설정하거나 응답을 작성합니다.To handle an exception, set the ExceptionContext.ExceptionHandled property to true or write a response. 그러면 예외가 전파되지 않습니다.This stops propagation of the exception. 예외 필터는 예외를 "성공"으로 변환할 수 없습니다.An Exception filter can't turn an exception into a "success". 작업 필터에서만 가능합니다.Only an Action filter can do that.

참고

ASP.NET Core 1.1에서 ExceptionHandled을 true로 설정하고 응답을 작성하는 경우 응답이 전송되지 않습니다.In ASP.NET Core 1.1, the response isn't sent if you set ExceptionHandled to true and write a response. 이 시나리오에서 ASP.NET Core 1.0은 응답을 전송하고 ASP.NET Core 1.1.2는 1.0 동작에 반환됩니다.In that scenario, ASP.NET Core 1.0 does send the response, and ASP.NET Core 1.1.2 will return to the 1.0 behavior. 자세한 내용은 GitHub 리포지토리에서 문제 #5594를 참조하세요.For more information, see issue #5594 in the GitHub repository.

예외 필터:Exception filters:

  • MVC 작업 내에서 발생하는 트래핑 예외에 좋습니다.Are good for trapping exceptions that occur within MVC actions.
  • 오류 처리 미들웨어만큼 유연하지 않습니다.Are not as flexible as error handling middleware.

예외 처리의 경우 미들웨어를 선호합니다.Prefer middleware for exception handling. 선택한 MVC 작업에 따라 오류 처리를 다르게 수행해야 하는 경우에만 예외 필터를 사용합니다.Use exception filters only where you need to do error handling differently based on which MVC action was chosen. 예를 들어 앱에는 API 엔드포인트 및 보기/HTML 모두에 대한 작업 메서드가 있을 수 있습니다.For example, your app might have action methods for both API endpoints and for views/HTML. API 엔드포인트는 JSON으로 오류 정보를 반환할 수 있습니다. 반면 보기 기반 작업은 HTML로 오류 페이지를 반환할 수 있습니다.The API endpoints could return error information as JSON, while the view-based actions could return an error page as HTML.

ExceptionFilterAttribute을 서브클래스할 수 있습니다.The ExceptionFilterAttribute can be subclassed.

결과 필터Result filters

  • IResultFilter 또는 IAsyncResultFilter 인터페이스 중 하나를 구현합니다.Implement either the IResultFilter or IAsyncResultFilter interface.
  • 해당 실행은 작업 결과의 실행을 둘러쌉니다.Their execution surrounds the execution of action results.

HTTP 헤더를 추가하는 결과 필터의 예는 다음과 같습니다.Here's an example of a Result filter that adds an HTTP header.

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

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

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

실행되는 결과의 종류는 문제가 되는 작업에 따라 다릅니다.The kind of result being executed depends on the action in question. 보기를 반환하는 MVC 작업에는 실행되는 ViewResult의 일부인 모든 Razor 프로세스가 포함됩니다.An MVC action returning a view would include all razor processing as part of the ViewResult being executed. API 메서드는 실행 결과의 일부로 일부 serialization을 수행할 수 있습니다.An API method might perform some serialization as part of the execution of the result. 작업 결과에 대한 자세한 정보Learn more about action results

결과 필터는 작업 또는 작업 필터가 작업 결과 생성하는 성공적인 결과에 대해서만 실행됩니다.Result filters are only executed for successful results - when the action or action filters produce an action result. 예외 필터가 예외를 처리하는 경우 결과 필터는 실행되지 않습니다.Result filters are not executed when exception filters handle an exception.

OnResultExecuting 메서드는 ResultExecutingContext.Cancel를 true로 설정하여 작업 결과 및 후속 결과 필터를 단락(short-circuit) 처리할 수 있습니다.The OnResultExecuting method can short-circuit execution of the action result and subsequent result filters by setting ResultExecutingContext.Cancel to true. 일반적으로 빈 응답을 생성하지 않도록 단락(short-circuit) 처리하는 경우 응답 개체에 작성해야 합니다.You should generally write to the response object when short-circuiting to avoid generating an empty response. 예외를 throw하면:Throwing an exception will:

  • 작업 결과 및 후속 필터의 실행을 방지합니다.Prevent execution of the action result and subsequent filters.
  • 성공적인 결과 대신 실패로 처리됩니다.Be treated as a failure instead of a successful result.

OnResultExecuted 메서드를 실행하는 경우 응답은 클라이언트에 전송되고 추가로 변경될 수 없습니다(예외가 throw되지 않는 경우).When the OnResultExecuted method runs, the response has likely been sent to the client and cannot be changed further (unless an exception was thrown). ResultExecutedContext.Canceled는 작업 결과 실행이 다른 필터에 의해 단락(short-circuit) 처리된 경우 true로 설정됩니다.ResultExecutedContext.Canceled will be set to true if the action result execution was short-circuited by another filter.

ResultExecutedContext.Exception은 작업 결과 또는 후속 결과 필터에서 예외가 throw된 경우 null이 아닌 값으로 설정됩니다.ResultExecutedContext.Exception will be set to a non-null value if the action result or a subsequent result filter threw an exception. Exception을 효과적으로 null로 설정하면 예외를 '처리'하고 예외가 파이프라인의 뒷부분에 나오는 MVC 에 의해 다시 throw되지 않습니다.Setting Exception to null effectively 'handles' an exception and prevents the exception from being rethrown by MVC later in the pipeline. 결과 필터에서 예외를 처리하는 경우 응답에 모든 데이터를 쓸 수 없습니다.When you're handling an exception in a result filter, you might not be able to write any data to the response. 작업 결과가 해당 실행을 통해 일부 throw되고 헤더가 이미 클라이언트에 플러시된 경우 오류 코드를 전송하는 신뢰할 수 있는 메커니즘이 없습니다.If the action result throws partway through its execution, and the headers have already been flushed to the client, there's no reliable mechanism to send a failure code.

IAsyncResultFilter의 경우 ResultExecutionDelegate에서 await next에 대한 호출은 후속 결과 필터 및 작업 결과를 실행합니다.For an IAsyncResultFilter a call to await next on the ResultExecutionDelegate executes any subsequent result filters and the action result. 단락(short-circuit) 처리하려면 ResultExecutingContext.Cancel를 true로 설정하고 ResultExectionDelegate를 호출하지 않습니다.To short-circuit, set ResultExecutingContext.Cancel to true and don't call the ResultExectionDelegate.

프레임워크는 하위 클래스를 지정할 수 있는 추상 ResultFilterAttribute을 제공합니다.The framework provides an abstract ResultFilterAttribute that you can subclass. 앞에 표시된 AddHeaderAttribute 클래스는 결과 필터 특성의 예제입니다.The AddHeaderAttribute class shown earlier is an example of a result filter attribute.

필터 파이프라인에서 미들웨어 사용Using middleware in the filter pipeline

리소스 필터는 파이프라인의 뒷부분에 제공되는 모든 실행을 둘러싼다는 점에서 미들웨어처럼 작동합니다.Resource filters work like middleware in that they surround the execution of everything that comes later in the pipeline. 하지만 필터는 MVC의 일부라는 점에서 미들웨어와 다릅니다. 즉, MVC 컨텍스트 및 구문에 액세스할 수 있습니다.But filters differ from middleware in that they're part of MVC, which means that they have access to MVC context and constructs.

ASP.NET Core 1.1에서 필터 파이프라인에 미들웨어를 사용할 수 있습니다.In ASP.NET Core 1.1, you can use middleware in the filter pipeline. MVC 경로 데이터에 액세스해야 하는 미들웨어 구성 요소 또는 특정 컨트롤러 또는 작업에서만 실행해야 하는 미들웨어 구성 요소가 있는 경우 해당 작업을 수행합니다.You might want to do that if you have a middleware component that needs access to MVC route data, or one that should run only for certain controllers or actions.

미들웨어를 필터로 사용하려면 필터 파이프라인에 삽입하려고 하는 미들웨어를 지정하는 Configure 메서드를 포함한 형식을 만듭니다.To use middleware as a filter, create a type with a Configure method that specifies the middleware that you want to inject into the filter pipeline. 요청에서 현재 문화권을 설정하는 지역화 미들웨어를 사용하는 예제는 다음과 같습니다.Here's an example that uses the localization middleware to establish the current culture for a request:

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

MiddlewareFilterAttribute을 사용하여 선택한 컨트롤러나 작업에서 또는 전역적으로 미들웨어를 실행할 수 있습니다.You can then use the MiddlewareFilterAttribute to run the middleware for a selected controller or action or globally:

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

미들웨어 필터는 모델 바인딩 이전 및 나머지 파이프라인 이후에 리소스 필터와 동일한 필터 파이프라인 단계에서 실행됩니다.Middleware filters run at the same stage of the filter pipeline as Resource filters, before model binding and after the rest of the pipeline.

다음 작업Next actions

필터를 실험하려면 샘플을 다운로드하고, 테스트하고, 수정합니다.To experiment with filters, download, test and modify the sample.