Для создания компонентов middleware, которые обрабатывают запрос, в прошлых темах использовались так называемые inline middleware. То есть с помощью методов app.Run/app.Use/app.Map/app.MapWhen/app.UseWhen в конвейер обработки запроса встраивались некоторые обработчики в виде лямбда-выражений или полноценных методов. Однако также ASP.NET Core позволяет определять middleware в виде отдельных классов.
Итак, добавим в проект новый класс, который назовем TokenMiddleware и который будет иметь следующий код:
Imports Microsoft.AspNetCore.Http Public Class TokenMiddleware Private ReadOnly nextMiddleware As RequestDelegate Public Sub New(nextMiddleware As RequestDelegate) Me.nextMiddleware = nextMiddleware End Sub Public Async Function InvokeAsync(context As HttpContext) As Task Dim token = context.Request.Query("token") If token <> "12345678" Then context.Response.StatusCode = 403 Await context.Response.WriteAsync("Token is invalid") Else Await nextMiddleware.Invoke(context) End If End Function End Class
Класс middleware должен иметь конструктор, который принимает параметр типа RequestDelegate. Через этот параметр можно получить ссылку на тот делегат запроса, который стоит следующим в конвейере обработки запроса.
Также в классе должен быть определен метод, который должен называться либо Invoke, либо InvokeAsync. Причем этот метод должен возвращать объект Task и принимать в качестве параметра контекст запроса - объект HttpContext. Данный метод собственно и будет обрабатывать запрос.
Суть действия класса заключается в том, что мы получаем из запроса параметр "token". Если полученный токен равен строке "12345678", то передаем запрос
дальше следующему компоненту, вызвав метод nextMiddleware.Invoke()
. Иначе возвращаем пользователю сообщение об ошибке.
Для добавления компонента middleware, который представляет класс, в конвейер обработки запроса применяется метод UseMiddleware(). Так, изменим файл Program.vb следующим образом:
Imports Microsoft.AspNetCore.Builder Imports Microsoft.AspNetCore.Http Module Program Sub Main(args As String()) Dim builder = WebApplication.CreateBuilder(args) Dim app = builder.Build() app.UseMiddleware(Of TokenMiddleware) app.Run(Async Function(context As HttpContext) As Task Await context.Response.WriteAsync("Hello METANIT.COM") End Function) app.Run() End Sub End Module
С помощью метода UseMiddleware(Of T) в конструктор объекта TokenMiddleware будет внедряться объект
для параметра RequestDelegate next
. Поэтому явным образом передавать значение для этого параметра нам не нужно.
Запустим проект. И если мы не передадим через строку запроса параметр token или передадим для него значение, отличное от "12345678", то браузер отобразит ошибку:
Если же будет передан корректный токен, то вызов app.UseMiddleware(Of TokenMiddleware)()
передаст обработку запроса
в компонент middleware из app.Run()
:
Также нередко для встраивания подобных компонентов middleware определяются специальные методы расширения. Сделаем что-то подобное и для этого изменим код программы в Program.vb следующим образом:
Imports System.Runtime.CompilerServices Imports Microsoft.AspNetCore.Builder Imports Microsoft.AspNetCore.Http Module Program Sub Main(args As String()) Dim builder = WebApplication.CreateBuilder(args) Dim app = builder.Build() app.UseToken() app.Run(Async Function(context As HttpContext) As Task Await context.Response.WriteAsync("Hello METANIT.COM") End Function) app.Run() End Sub <Extension()> Public Sub UseToken(builder As IApplicationBuilder) builder.UseMiddleware(Of TokenMiddleware)() End Sub End Module
Здесь ключевой момент заключается в создании метода расширения
<Extension()> Public Sub UseToken(builder As IApplicationBuilder) builder.UseMiddleware(Of TokenMiddleware)() End Sub
Сам метод называется UseToken. Здесь создается метод расширения для типа IApplicationBuilder, поэтому параметр именно этого типа передается в качестве первого (и единственного) параметра. И этот метод встраивает компонент TokenMiddleware в конвейер обработки запроса.
Затем мы можем написать так
app.UseToken()
И тем самым встроить TokenMiddleware в конвейер обработки запроса.
Изменим класс TokenMiddleware, чтобы он извне получал образец токена для сравнения:
Imports Microsoft.AspNetCore.Http Public Class TokenMiddleware Private ReadOnly nextMiddleware As RequestDelegate Private pattern As String Public Sub New(nextMiddleware As RequestDelegate, pattern As String) Me.nextMiddleware = nextMiddleware Me.pattern = pattern End Sub Public Async Function InvokeAsync(context As HttpContext) As Task Dim token = context.Request.Query("token") If token <> pattern Then context.Response.StatusCode = 403 Await context.Response.WriteAsync("Token is invalid") Else Await nextMiddleware.Invoke(context) End If End Function End Class
Образец токена, с которым идет сравнения, устанавливается через конструктор.
Далее изменим код в файле Program.vb, чтобы передавать в middleware нужные токены:
Imports System.Runtime.CompilerServices Imports Microsoft.AspNetCore.Builder Imports Microsoft.AspNetCore.Http Module Program Sub Main(args As String()) Dim builder = WebApplication.CreateBuilder(args) Dim app = builder.Build() app.UseToken("555555") app.Run(Async Function(context As HttpContext) As Task Await context.Response.WriteAsync("Hello METANIT.COM") End Function) app.Run() End Sub <Extension()> Public Sub UseToken(builder As IApplicationBuilder, pattern As String) builder.UseMiddleware(Of TokenMiddleware)(pattern) End Sub End Module
Чтобы передать ножное значение в конструктор TokenMiddleware, в метод builder.UseMiddleware
можно передать набор значений - они автоматически передаются в конструктор компонента middleware:
<Extension()> Public Sub UseToken(builder As IApplicationBuilder, pattern As String) builder.UseMiddleware(Of TokenMiddleware)(pattern) End Sub
И при вызове метода расширения UseToken в него можно передать конкретное значение
app.UseToken("555555")