Asp.Net Core 에서 ModelConvention 를 사용 하여 전역 필터 격 리

어디서부터 말 할 까
이것 은 내 가 프로젝트 를 Asp.Net Core 로 옮 기 는 과정 에서 문제 에 부 딪 혔 기 때문이다.웹 프로그램 에 MVC 와 WebAPI 가 동시에 포함 되 어 있 습 니 다.이 제 는 WebAPI 부분 에 인터페이스 검증 필터IActionFilter를 따로 추가 해 야 합 니 다.일반적인 방법 은 필 터 를 작성 한 후에 필요 한 컨트롤 러 에 이 탭 을 걸 어 주 는 것 입 니 다.고급 방법 은 전체 필 터 를 등록 하 는 것 입 니 다.이렇게 하면 매번 수 동 으로 추가 되 는 것 을 피 할 수 있 고 코드 도 잘 관리 할 수 있 습 니 다.전역 필 터 를 등록 하 는 방법 은 다음 과 같 습 니 다.

services.AddMvc(options =>
 {
  options.Filters.Add(typeof(AccessControlFilter));
 });
그러나 이렇게 하면 문 제 를 가 져 올 수 있다.바로 MVC 부분 컨트롤 러 도 영향 을 받는다 는 것 이다.필터 에서 어떤 것 이 MVC 컨트롤 러 이 고 어떤 것 이 API 컨트롤 러 인지 판단 할 수 있 지만 괜 히 MVC 에 이런 쓸모없는 Filter 를 추가 하 는 것 은 어차피 참 을 수 없 기 때문에 이 기능 을 실현 할 수 있 는 더 좋 은 방법 이 있 는 지 찾 아 보 자.
그 러 자 모델 컨 벤 션 이 깜짝 등장 했다.
애플 리 케 이 션 모델 부터 알 아 보 겠 습 니 다.
공식 문서 에서 응용 프로그램 모델(ApplicationModel)을 어떻게 설명 하 는 지 보 세 요.
ASP.NET Core MVC defines an application model representing the components of an MVC app. You can read and manipulate this model to modify how MVC elements behave. By default, MVC follows certain conventions to determine which classes are considered to be controllers, which methods on those classes are actions, and how parameters and routing behave. You can customize this behavior to suit your app's needs by creating your own conventions and applying them globally or as attributes.
간단하게 말하자면 응용 프로그램 모델 은 MVC 응용 프로그램의 각종 대상 과 행 위 를 묘사 했다.이런 내용 은 응용 프로그램,컨트롤 러,Action,Parameter,Router,Page,Property,Filter 등 을 포함 하고 Asp.Net Core 프레임 워 크 자체 에 규칙(Convention)을 내장 하여 이 모델 들 을 처리한다.또한 인 터 페 이 스 를 제공 하여 우리 에 게 더욱 필요 한 응용 을 실현 하기 위해 모델 을 확장 하기 로 약속 했다.
응용 프로그램 모델 과 관련 된 클래스 는 네 임 스페이스Microsoft.AspNetCore.Mvc.ApplicationModels에 정의 되 어 있 으 며,이 모델 들 은IApplicationModelProvider을 통 해 구축 되 었 으 며,Asp.Net Core 프레임 워 크 가 제공 하 는 기본 Provider 는DefaultApplicationModelProvider입 니 다.우 리 는 이 모델 들 을 편집 하여 표현 행 위 를 바 꿀 수 있다.이것 은 모델 컨 벤 션 을 통 해 이 루어 져 야 한다.
ModelConvention
ModelConvention 는 조작 모델 의 입 구 를 정의 하거나 계약 이 라 고 할 수 있 습 니 다.이 를 통 해 우 리 는 모델 을 수정 할 수 있 습 니 다.자주 사용 하 는 Convention 는 다음 과 같 습 니 다.
  • IApplicationModelConvention
  • IControllerModelConvention
  • IActionModelConvention
  • IParameterModelConvention
  • IPageRouteModelConvention
  • 이 인터페이스 들 은 공 통 된 방법Apply을 제공 합 니 다.방법 적 인 파 라 메 터 는 각자 의 응용 프로그램 모델 입 니 다.IControllerModelConvention을 예 로 들 어 그 정 의 를 보 세 요.
    
    namespace Microsoft.AspNetCore.Mvc.ApplicationModels
    {
     //
     //   :
     //  Allows customization of the Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerModel.
     //
     //   :
     //  To use this interface, create an System.Attribute class which implements the
     //  interface and place it on a controller class. Microsoft.AspNetCore.Mvc.ApplicationModels.IControllerModelConvention
     //  customizations run after Microsoft.AspNetCore.Mvc.ApplicationModels.IApplicationModelConvention
     //  customizations and before Microsoft.AspNetCore.Mvc.ApplicationModels.IActionModelConvention
     //  customizations.
     public interface IControllerModelConvention
     {
      //
      //   :
      //  Called to apply the convention to the Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerModel.
      //
      //   :
      // controller:
      //  The Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerModel.
      void Apply(ControllerModel controller);
     }
    }
    인터페이스 요약 을 통 해 알 수 있 듯 이 이 인 터 페 이 스 는 사용자 정의ControllerModel대상 을 허용 합 니 다.사용자 정의 내용 은Apply방법 으로 이 루어 집 니 다.이 방법 은 현재ControllerModel대상 의 인 스 턴 스 를 제공 합 니 다.우 리 는 그 에 게 서 얻 을 수 있 는 것 이 너무 많 습 니 다.그것 이 무엇 을 포함 하 는 지 보 세 요.

    이러한 것들 이 있 으 면 우 리 는 매우 유연 한 조작 을 할 수 있다.예 를 들 어 설정ControllerName필드 를 통 해 컨트롤 러 의 이름 을 강제로 변경 하여 프로그램 에 죽은 컨트롤 러 이름 을 무효 화 할 수도 있 고Filters필드 를 통 해 필터 집합 을 동적 으로 업데이트 할 수도 있 으 며RouteValues을 통 해 경로 규칙 을 변경 할 수도 있다.
    여기까지 말 하면 많은 사람들 이 이 물건 과 사용자 정의 필터 가 별로 차이 가 나 지 않 는 다 고 생각 할 것 이다.처음에 나 도 그렇게 생각 했다.그러나 실제 코드 디 버 깅 을 통 해 나 는 그것 의 생명 주기 가 필터 보다 훨씬 빠 르 거나 비교 할 수 없다 는 것 을 알 게 되 었 다.이 녀석 은 시작 할 때 한 번 만 실행 해 야 하 며 매번 요청 에 따라 실행 하지 않 아 도 된다.즉,컨트롤 러 를 활성화 하 는 것 보다 더 일찍 실행 되 었 고 그 때 는 필터 가 전혀 없 었 으 며 호출 은app.UseEndpoints()에서 발생 했다.
    최초의 수요 로 돌아가다.위의 소 개 를 바탕 으로 다음 과 같은 약속 을 사용자 정의 할 수 있 습 니 다.
    
     public class ApiControllerAuthorizeConvention : IControllerModelConvention
     {
      public void Apply(ControllerModel controller)
      {
       if (controller.Filters.Any(x => x is ApiControllerAttribute) && !controller.Filters.Any(x => x is AccessControlFilter))
       {
        controller.Filters.Add(new AccessControlAttribute());
       }
      }
     }
    위의 주요 사고방식 은 컨트롤 러 자체 의 필터 집합 에 API 컨트롤 러 가 포함 되 어 있 는 지ApiControllerAttribute를 판단 함으로써 API 컨트롤 러 가 표시 되 어 있 지 않 고AccessControlAttribute표시 되 어 있 지 않 으 면 새로운 실례 를 추가 하 는 것 이다.
    그러면 어떻게 이 약속 을 응용 프로그램 에 등록 합 니까?Microsoft.AspNetCore.Mvc.MvcOptions 에서Conventions속성 을 제공 합 니 다.
    
      //
      //   :
      //  Gets a list of Microsoft.AspNetCore.Mvc.ApplicationModels.IApplicationModelConvention
      //  instances that will be applied to the Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel
      //  when discovering actions.
      public IList<IApplicationModelConvention> Conventions { get; }
    조작 을 통 해 사용자 정의 약속 을 주입 할 수 있 습 니 다:
    
      services.AddMvc(options =>
       {
        options.Conventions.Add(new ApiControllerAuthorizeConvention());
       })
    세심 한 사람 은 Conventions 가 하나의IApplicationModelConvention유형의 집합 이라는 것 을 알 게 될 것 이다.우리 가 정의 한 Convention 는 하나의IControllerModelConvention이 므 로 정상적으로 잘못 보고 해 야 한다.왜냐하면 Asp.Net Core 의 DI 프레임 워 크 는 우리 에 게 일련의 확장 방법 을 제공 하여 Convention 의 추 가 를 간소화 하고 더 이상 전환 하지 않 아 도 되 기 때문이다.

    코드 디 버 깅 을 통 해 시작 할 때 시스템 의 모든 컨트롤 러 를 옮 겨 다 니 며 Apply 작업 을 수행 한 것 을 알 수 있 습 니 다.그러면IApplicationModelConvention을 통 해 도 이 기능 을 실현 할 수 있 습 니 다.컨트롤 러 집합 이 포함 되 어 있 기 때 문 입 니 다.
    
     public class ApiControllerAuthorizeConvention : IApplicationModelConvention
     {
      public void Apply(ApplicationModel application)
      {
       foreach (var controller in application.Controllers)
       {
        if (controller.Filters.Any(x => x is ApiControllerAttribute) && !controller.Filters.Any(x => x is AccessControlFilter))
        {
         controller.Filters.Add(new AccessControlFilter());
        }
       }
      }
     }
    좀 더 개선 하 다
    실제 개발 에서 나의 Access Control Filter 는 구조 함 수 를 통 해 업무 인 터 페 이 스 를 주입 해 야 합 니 다.이와 유사 합 니 다.
    
     public class AccessControlFilter : IActionFilter
     {
      private IUserService _userService;
    
      public AccessControlFilter(IUserService service)
      {
       _userService = service;
      }
    
      public void OnActionExecuting(ActionExecutingContext context)
      {
        //        
        //var user=_userService.GetById(996);
        //.......
      }
    
      public void OnActionExecuted(ActionExecutedContext context)
      {
      }
     }
    어떻게 하면 Convention 에서 DI 자동 주입 을 우아 하 게 사용 할 수 있 을까요?Asp.Net Core MVC 프레임 워 크 가 제공 하 는ServiceFilter이 문 제 를 해결 할 수 있 습 니 다.ServiceFilter자체 가 필터 입 니 다.그 차이 점 은 구조 함 수 를 통 해 Type 형식의 인 자 를 받 을 수 있 습 니 다.우 리 는 여기 서 진정 으로 사용 할 필 터 를 전송 할 수 있 습 니 다.그래서 위의 필터 등록 과정 은 다음 과 같 습 니 다.
    
     controller.Filters.Add(new ServiceFilterAttribute(typeof(AccessControlFilter)));
    물론 DI 에서 이 filter 인 스 턴 스 를 가 져 오 려 면 DI 용기 에 주입 해 야 합 니 다.
    
     services.AddScoped<AccessControlFilter>();
    이로써 큰 성 과 를 거 두 며 즐 거 운 CRUD 를 이 어 갔다.
    갑자기 제 가상편언급 한 확장 DI 속성 주입 기능 도 이 를 통 해 이 루어 질 수 있 을 것 같 습 니 다.eeeeee...시간 이 나 면 해 보 세 요.
    총결산
    전체적으로 볼 때 저 는 곡선 으로 나 라 를 구 하 는 방식 으로 전체 필터 격 리 를 실 현 했 습 니 다.목표 컨트롤 러 를 옮 겨 다 니 고 Filter 를 수 동 으로 추가 하 는 방식 은 한 줄 의 코드 로 실현 할 수 있 는 방식 이 우아 하지 않 지만 대체적으로 만 족 스 럽 고 현재 생각 할 수 있 는 가장 좋 은 방법 입 니 다.내 가 짐 작 컨 대options.Filters.Add(xxx)도 틀 에서 어느 때 한 명 씩 xxx 를 각자 주인 에 게 던 져 주 고 멋대로 추측 하 며 잘못 말 하면 책임 을 지지 않 는 다~hhh:seeno_evil::see_no_evil::see_no_evil:
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기