15. Custom Middleware
◆ Custom Middleware
미들웨어 커스터마이징하는 법!!
우선 미들웨어의 특성을 살짝 복습해보자
- 요청 및 응답을 처리하는 부품
- 매 요청시마다 항상 실행되어야 할 로직에 사용함
- 양방향에서 처리됨
- 미들웨어가 Response를 직접 생성하면, ShortCut 역할을 한다.
- 아래로 계속 보내는 게 아니라, 흐름을 가로채서 끊어내는 것
이런 특성들에 대해 조금 더 자세히 알아보고자 한다.
우리가 미들웨어를 직접 만들어서 사용하고 싶을 수 있다.
이때 다음 방법들을 사용해 미들웨어를 구성할 수 있다.
- Run 이용
- 항상 흐름을 종료(shortcut)시킨다. (터미널 미들웨어)
- Map 이용
- Branching 미들웨어
- 모든 미들웨어가 항상 순차적으로 실행되어야 하는 것은 아니다.
- 흐름을 가로챘다고 해서 꼭 위로 올려보내는 것도 아니다.
- Use 이용
- next를 통해 다음 미들웨어로 연결한다.
- next() 호출을 하지 않는 경우 shorcut
- next의 전/후에 특정 처리를 할 수 있다.
- next를 통해 다음 미들웨어로 연결한다.
하나하나 살펴보자.
Run
우선 Run을 이용해서 초간단 미들웨어를 만드려면 이렇게 하면 된다.
다음은 Program.cs에서 app을 만든 후 바로 Run을 날려버리는 코드이다.
var app = builder.Build();
app.Run(async (context) =>
{
context.Response.ContentType = "test/plain";
await context.Response.WriteAsync("Hello Middleware");
});
- 밑에 어떤 코드가 더 있든간에, 실행되지 않고 여기서 흐름이 끊긴다.
- 기존처럼 Index 페이지에 연결되지 않고, 응답 설정한대로 웬 "Hello Middleware" 적힌 텍스트 파일만 다운로드되고 끝난다. (Home/Index로 요청해도 거기까지 못가고 파일만 다운받고 끝난다.)
Map
Map을 이용하면 Branch를 설정할 수 있다.
특정 경우에만 해당 미들웨어 파이프라인이 실행되도록 할 수 있다는 것이다.
예제를 보자.
var app = builder.Build();
app.Map("/secret", branch =>
{
//세팅들을 추가할 수 있다.
//...
branch.Run(async (context) =>
{
context.Response.ContentType = "test/plain";
await context.Response.WriteAsync("Hello Middleware");
});
});
- /secret 경로로 요청한 경우에만 세팅들을 적용하고 Run을 실행한다.
이 경우 Index 요청 등 다른 요청은 원래대로 동작한다.
다만 /secret으로 요청한 경우 아까처럼 "Hello Middleware"가 적힌 텍스트 파일을 다운로드한다.
Use
Use를 이용하는 방법이다.
Use는 특이하게 next 인자를 사용하는데, next()를 통해 다음 미들웨어로 연결할 수 있다.
또 next() 전/후에 특정 처리를 하도록 할 수 있다.
var app = builder.Build();
app.Use(async (context, next) =>
{
// Request 후에 처리할 내용
await next(); //다음 미들웨어 호출
//Response 전에 처리할 내용
});
Custom Middleware Component
그런데 이런식으로 Program.cs에다 Use, Map, Run...이렇게 전부 하나하나 넣으면,
작은 프로젝트에서는 괜찮지만 프로젝트가 커질수록 보기 어려울 것이다.
그럼 어떻게 만드는 게 좋을까?
Custom Middleware Component를 만드는 방법을 알아보자.
두가지 규칙이 존재한다.
- 생성자에서 RequestDelegate를 인자로 받아야 한다.
- next를 호출해주기 위함
- public Task Invoke(HttpContext context) 함수를 구현해야 한다.
실제로 하나 만들어보자.
1. 미들웨어 클래스를 하나 만들어준다.
public class TestMiddleware
{
RequestDelegate _next;
ILogger<TestMiddleware> _logger;
public TestMiddleware(RequestDelegate next, ILogger<TestMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
_logger.LogInformation("TestMiddleware");
await _next(context);
}
}
- 위와 같이, 미들웨어에서도 DI가 가능하다.
2. Program.cs에서 해당 미들웨어를 사용할 것이라고 선언한다.
var app = builder.Build();
app.UseMiddleware<TestMiddleware>();
끝~
이런식으로 미들웨어를 커스터마이징하면 된다.