ASP.NET Core рдорд╛рдирдХ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдирдХ рдкреНрд░рд╕реНрддрд╛рд╡реЛрдВ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рджрд╛рд╡реЗ рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рддрдХ рдкрд╣реБрдВрдЪ рдХреЛ рдкреНрд░рддрд┐рдмрдВрдзрд┐рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ, рдЖрдк рдиреАрддрд┐рдпреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЛ рдмрд╛рдВрдз рд╕рдХрддреЗ рд╣реИрдВ, рд╡рд┐рднрд┐рдиреНрди рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдЗрд╕ рдкреНрд░рдгрд╛рд▓реА рдореЗрдВ рдиреНрдпреВрдирддрдо, рдЗрд╕ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП, рд╕рдмрд╕реЗ рдмрдбрд╝рд╛ рд╣реИ:
[Authorize(Roles = "Administrator")] public class AdministrationController : Controller { }
рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдХреЛ рдХреНрдпрд╛ рдЕрдзрд┐рдХрд╛рд░ рд╣реИрдВ, рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣рдореЗрдВ рдХреЛрдИ рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рдорд┐рд▓рддреА рд╣реИред
рдореЗрд░рд╛ рдХрд╛рдо рдЗрд╕ рдорд╣реАрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдкреНрд░рддрд┐рдмрдВрдзрд┐рдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рд╣реИ (рди рдХреЗрд╡рд▓ рдбреЗрдЯрд╛рдмреЗрд╕ рдкрд░ рдЬрд╛рдПрдВ рдФрд░ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░реЗрдВ, рдХреБрдЫ рдЧрд┐рдирддреА рдХреЗ рдирд┐рдпрдо рд╣реИрдВ рдЬреЛ рдХрд╣реАрдВ рдЭреВрда рдмреЛрд▓рддреЗ рд╣реИрдВ), рдореИрдВ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ CTRL + N рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ BannedUserHandler рдпрд╛ IHasInAbounBannedUser рдпрд╛ GetBannedUsersForAdmin рдХреЛ рджреЗрдЦрддрд╛ рд╣реВрдВ ред
рдореБрдЭреЗ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рдирд┐рдпрдВрддреНрд░рдХ рдорд┐рд▓рддреЗ рд╣реИрдВ [рдЕрдзрд┐рдХреГрдд (рднреВрдорд┐рдХрд╛ = "рдкреНрд░рд╢рд╛рд╕рдХ")] , рджреЛ рдкрд░рд┐рджреГрд╢реНрдп рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:
рд╣рдо рд╕рдм рдХреБрдЫ рдХрдВрдЯреНрд░реЛрд▓рд░ рдореЗрдВ рдХрд░рддреЗ рд╣реИрдВ
[Route("api/[controller]/[action]")] public class AdminInfoController1 : ControllerBase { private readonly IGetUserInfoService _getInfoAboutActiveUsers; private readonly ICanBanUserService _banUserService; private readonly ICanRemoveBanUserService _removeBanUserService;
рд╣рдо рд╣реИрдВрдбрд▓рд░ рдкрд░ рд╡рд┐рддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ
[Route("api/[controller]/[action]")] public class AdminInfoController2 : ControllerBase { [HttpPatch("{id}")] public async Task<ActionResult<BanUserResult>> BanUser( [FromServices] IAsyncHandler<UserId, BanUserResult> handler, UserId userId) => await handler.Handle(userId, HttpContext.RequestAborted); [HttpPatch("{id}")] public async Task<ActionResult<RemoveBanUserResult>> RemoveBanUser( [FromServices] IAsyncHandler<UserId, RemoveBanUserResult> handler, UserId userId) => await handler.Handle(userId, HttpContext.RequestAborted); }
рдкрд╣рд▓рд╛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдЗрд╕ рдмрд╛рдд рдореЗрдВ рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдХреЗ рдкрд╛рд╕ рдХрд┐рди рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреА рдкрд╣реБрдБрдЪ рд╣реИ, рдпрд╣ рдХрд┐рди рдирд┐рд░реНрднрд░рддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдореИрдВ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдЫреЛрдЯреЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ рдХрд░реВрдБрдЧрд╛, рдмрд┐рдирд╛ рдХрд┐рд╕реА рдЬрдЯрд┐рд▓ рд╡рд┐рд╖рдп рдХреЗ
рджреВрд╕рд░рд╛ рдХреЛрдИ рдЗрддрдиреА рдмрд╛рдд рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИ, рд╕рднреА рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рд╣рд▓ рд╣реЛ рдЧрдИ рд╣реИрдВ, рдореИрдВ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рдирд╣реАрдВ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реВрдВ рдФрд░ рд╕рдордЭ рд╕рдХрддрд╛ рд╣реВрдВ рдХрд┐ рдореБрдЭреЗ рдХрд┐рд╕ рддрд░рд╣ рдХреА рдирд┐рд░реНрднрд░рддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдЦреБрдж рдХреЛ рдФрдЪрд┐рддреНрдп рджреЗрддрд╛ рд╣реИ рдЬрдм рдЖрд╡реЗрджрди рдЬрдЯрд┐рд▓ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдирд┐рдпрдВрддреНрд░рдХ рдкреНрд░рдлреБрд▓реНрд▓рд┐рдд рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рдЙрдирдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдХреНрд▓рд╛рд╕рд┐рдХ рд╕рдорд╛рдзрд╛рди рдлрд╝реЛрд▓реНрдбрд░реНрд╕ / рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рд╕рдорд╛рдзрд╛рди рдХрд╛ рд╡рд┐рднрд╛рдЬрди рд╣реИ, рдЖрд╡рд╢реНрдпрдХ рд╕реЗрд╡рд╛рдУрдВ рдХреЛ рдкреНрд░рддреНрдпреЗрдХ рдореЗрдВ рдбрд╛рд▓рд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╡реЗ рдЦреЛрдЬрдиреЗ рдФрд░ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рдЖрд╕рд╛рди рд╣реЛрддреЗ рд╣реИрдВ
рдпрд╣ рд╕рдм рдПрдХ рдмрдбрд╝реА рдЦрд╛рдореА рд╣реИ, рдХреЛрдб рдбреЗрд╡рд▓рдкрд░ рдХреЛ рдпрд╣ рдирд╣реАрдВ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИ, рдЗрд╕рд╕реЗ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ => рд╕рдордп рдХреА рдмрд░реНрдмрд╛рджреА => рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рддреНрд░реБрдЯрд┐рдпрд╛рдВ
рдФрд░ рдЬрд┐рддрдирд╛ рдЖрдкрдХреЛ рд╕реЛрдЪрдирд╛ рд╣реИ, рдЙрддрдиреА рд╣реА рдЧрд▓рддрд┐рдпрд╛рдБ рд╣реЛрддреА рд╣реИрдВред
рд╕реБрд╡реЗ рд░реВрдЯрд┐рдВрдЧ рдХрд╛ рдкрд░рд┐рдЪрдп
рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдЕрдЧрд░ рд░реВрдЯрд┐рдВрдЧ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ :
let webPart = choose [ path "/" >=> (OK "Home") path "/about" >=> (OK "About") path "/articles" >=> (OK "List of articles") path "/articles/browse" >=> (OK "Browse articles") path "/articles/details" >=> (OK "Content of an article") ]
''> => '' - рдХреНрдпрд╛ рд╣реИ? рдЗрд╕ рдЪреАрдЬрд╝ рдХрд╛ рдПрдХ рдирд╛рдо рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХрд╛ рдЬреНрдЮрд╛рди рдкрд╛рдардХ рдХреЛ рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЧреНрд░рд╛рдо рдХреЗ рдХрд░реАрдм рдирд╣реАрдВ рд▓рд╛рдПрдЧрд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рд▓рд╛рдиреЗ рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ, рдпрд╣ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ рдХрд┐ рд╕рдм рдХреБрдЫ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ
рд╕реБрд╡реЗ рд╕реЗ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдКрдкрд░ рд▓рд┐рдЦреА рдЧрдИ рд╣реИ, рдЬрд┐рд░рд╛рдлрд╝ рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдПрдХ рдЕрд▓рдЧ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХреЗ рд╕рд╛рде), рдПрдХ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рд╣реИ:
type WebPart = HttpContext -> Async<HttpContext option>
рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ Async рдПрдХ рд╡рд┐рд╢реЗрд╖ рднреВрдорд┐рдХрд╛ рдирд╣реАрдВ рдирд┐рднрд╛рддрд╛ рд╣реИ (рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ), рдЗрд╕реЗ рдЫреЛрдбрд╝ рджреЗрдВ
HttpContext -> HttpContext option
рдЗрд╕ рддрд░рд╣ рдХреЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХреЗ рд╕рд╛рде рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдПрдХ HttpContext рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдВ (рд╢рд░реАрд░ рдХреЛ deserializes, рдХреБрдХреАрдЬрд╝ рдХреЛ рджреЗрдЦрддрд╛ рд╣реИ, рд╣реЗрдбрд░ рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реИ), рдПрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдмрдирд╛рддрд╛ рд╣реИ, рдФрд░ рдЕрдЧрд░ рд╕рдм рдХреБрдЫ рдареАрдХ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЗрд╕реЗ рдХреБрдЫ рдореЗрдВ рд▓рдкреЗрдЯрддрд╛ рд╣реИ, рдЕрдЧрд░ рдХреБрдЫ рдЧрд▓рдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдХреЛрдИ рднреА рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП ( рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдлрд╝рдВрдХреНрд╢рди ):
// async let OK s : WebPart = fun ctx -> { ctx with response = { ctx.response with status = HTTP_200.status; content = Bytes s }} |> Some |> async.Return
рдпрд╣ рдлрд╝рдВрдХреНрд╢рди "рдЕрдиреБрд░реЛрдз рдирд┐рд╖реНрдкрд╛рджрди рдкреНрд░рд╡рд╛рд╣ рдХреЛ рд▓рдкреЗрдЯ рдирд╣реАрдВ рд╕рдХрддрд╛", рдпрд╣ рд╣рдореЗрд╢рд╛ рд╢рд░реАрд░ рдФрд░ рд╕реНрдерд┐рддрд┐ 200 рдХреЗ рд╕рд╛рде рдЖрдЧреЗ рдПрдХ рдирдИ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдлреЗрдВрдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдХрд░ рд╕рдХрддрд╛ рд╣реИ:
let path (str:string) ctx = let path = ctx.request.rawPath if path.StartsWith str then ctx |> Some |> async.Return else async.Return None
рдЕрдВрддрд┐рдо рдлрд╝рдВрдХреНрд╢рди рдЬрд┐рд╕реЗ рдЖрдкрдХреЛ рдЪреБрдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рдпрд╣ рд╡рд┐рднрд┐рдиреНрди рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрд╕ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдХреБрдЫ рдкрд╣рд▓реЗ рджреЗрддрд╛ рд╣реИ:
let rec choose (webparts:(HttpContext) -> Async<HttpContext option>) list) context= async{ match webparts with | [head] -> return! head context | head::tail -> let! result = head context match result with | Some _-> return result | None -> return! choose tail context | [] -> return None }
рдЦреИрд░, рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд╛рдзреНрдпрдХрд╛рд░реА рдХрд╛рд░реНрдп (Async рдЫреЛрдбрд╝рд╛ рдЧрдпрд╛):
type WebPartWithoutAsync = HttpContext -> HttpContext option let (>=>) (h1:WebPartWithoutAsync ) (h2:WebPartWithoutAsync) ctx : HttpContext option = let result = h1 ctx match result with | Some ctx' -> h2 ctx' | None -> None
Async рд╕рдВрд╕реНрдХрд░рдг type WebPart = HttpContext -> Async<HttpContext option> let (>=>) (h1:WebPart ) (h2:WebPart ) ctx : Async<HttpContext option>= async{ let! result = h1 ctx match result with | Some ctx' -> return! h2 ctx' | None -> return None }
"> =>" рдмрд╛рдПрдБ рдФрд░ рджрд╛рдПрдБ рдкрдХреНрд╖ рдФрд░ httpContext рдкрд░ рджреЛ рд╣реИрдВрдбрд▓рд░ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рдЬрдм рдЕрдиреБрд░реЛрдз рдЖрддрд╛ рд╣реИ, рддреЛ рд╕рд░реНрд╡рд░ рдПрдХ HttpContext рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИ, "> =>" рдкрд╣рд▓реЗ (рдмрд╛рдПрдВ) рд╣реИрдВрдбрд▓рд░ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ рдпрджрд┐ рдпрд╣ рдХреБрдЫ ctx рджреЗрддрд╛ рд╣реИ, рддреЛ ctx рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИ рджреВрд╕рд░реЗ рд╣реИрдВрдбрд▓рд░ рдХреЗ рдЗрдирдкреБрдЯ рдХреЗ рд▓рд┐рдПред
рдФрд░ рд╣рдо рдЗрд╕ рддрд░рд╣ рдХреНрдпреЛрдВ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ (рдХрдИ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ)?
GET >=> path "/api" >=> OK
рдХреНрдпреЛрдВрдХрд┐ "> =>" рджреЛ WebPart рдлрд╝рдВрдХреНрд╢рди рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рджреЗрддрд╛ рд╣реИ рдЬреЛ HttpContext рд▓реЗрддрд╛ рд╣реИ рдФрд░ Async <HttpContext рд╡рд┐рдХрд▓реНрдк> рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдФрд░ рдХреМрди рд╕рд╛ рдлрд╝рдВрдХреНрд╢рди рд╕рдВрджрд░реНрдн рд▓реЗрддрд╛ рд╣реИ рдФрд░ Async <HttpContext рд╡рд┐рдХрд▓реНрдк> рд▓реМрдЯрд╛рддрд╛ рд╣реИ?
рд╡реЗрдмрдкрд╛рд░реНрдЯ ред
рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ "> =>" рд╡реЗрдмрдкрд╛рд░реНрдЯ рдХреЛ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд▓рд┐рдП рд▓реЗрддрд╛ рд╣реИ рдФрд░ рд╡реЗрдмрдкрд╛рд░реНрдЯ рдХреЛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдХрдИ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдХреЗрд╡рд▓ рджреЛ рдирд╣реАрдВред
рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдХреЗ рдХрд╛рдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд┐рд╡рд░рдг рдпрд╣рд╛рдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рднреВрдорд┐рдХрд╛ рдФрд░ рдкрд╣реБрдВрдЪ рдкреНрд░рддрд┐рдмрдВрдз рдХрд╛ рдЗрд╕рд╕реЗ рдХреНрдпрд╛ рд▓реЗрдирд╛-рджреЗрдирд╛ рд╣реИ?
рдЖрдЗрдП рд╣рдо рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рд▓реМрдЯрддреЗ рд╣реИрдВ, рд╣рдо рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдХреИрд╕реЗ рдЗрдВрдЧрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рднреВрдорд┐рдХрд╛ рдХреЗ рд▓рд┐рдП рдХреМрди рд╕реЗ рд╕рдВрд╕рд╛рдзрди рдПрдХреНрд╕реЗрд╕ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ? рдЖрдкрдХреЛ рдЗрд╕ рдбреЗрдЯрд╛ рдХреЛ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рджрд░реНрдЬ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рддрд╛рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЙрдкрдпреБрдХреНрдд рд╕рдВрд╕рд╛рдзрдиреЛрдВ рддрдХ рдкрд╣реБрдВрдЪ рд╕рдХреЗрдВ, рдореИрдВрдиреЗ рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдХрд┐рдпрд╛ рд╣реИ:

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рднрд╛рдЧреЛрдВ / рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдПрдбрдорд┐рдирдкрд╛рд░реНрдЯ рдФрд░ рдЕрдХрд╛рдЙрдВрдЯрдкрд╛рд░реНрдЯ рдлрд╝рдВрдХреНрд╢рди рд╡рд┐рднрд┐рдиреНрди рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рдЗрди рдореЙрдбреНрдпреВрд▓ рддрдХ рдкрд╣реБрдВрдЪ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ, рд╕рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдкрд╛рд╕ рдЕрдХрд╛рдЙрдВрдЯрдкрд╛рд░реНрдЯ рддрдХ рдкрд╣реБрдВрдЪ рд╣реЛрддреА рд╣реИ , рдХреЗрд╡рд▓ рдПрдбрдорд┐рди рдПрдбрдорд┐рдирдкрд╛рд░реНрдЯ рддрдХ рдкрд╣реБрдВрдЪрддрд╛ рд╣реИ, рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рд╕реЗрд▓реЗрдХреНрдЯ рдлрд╝рдВрдХреНрд╢рди рдкрд░ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реИ, рдореБрдЭреЗ рдЕрдзрд┐рдХ рдлрд╝рдВрдХреНрд╢рди рдЬреЛрдбрд╝рдиреЗ рд╣реЛрдВрдЧреЗ, рдХреНрдпреЛрдВрдХрд┐ рдорд╛рдирдХ рд╕реБрд╡реЗ рдкреНрд░рдХрд╛рд░реЛрдВ рд╕реЗ рдЬреБрдбрд╝реЗ рд╣реЛрддреЗ рд╣реИрдВ, рдФрд░ рдПрдбрдорд┐рдирдкрд╛рд░реНрдЯ рдФрд░ рдЕрдХрд╛рдЙрдВрдЯрдкрд╛рд░реНрдЯ рдХреЗ рдЕрдВрджрд░ рдХреЗ рд╣реИрдВрдбрд▓рд░ рдХреЗ рдЕрдм рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рд╣реИрдВ:
// AdminPart AdminInfo * HttpContext -> Async<(AdminInfo * HttpContext) option> // AccountPart AccountInfo* HttpContext -> Async<(AccountInfo * HttpContext) option>
рдЕрдВрджрд░, рдирдИ рд╕реБрд╡рд┐рдзрд╛рдПрдБ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдореВрд▓ рдХреЗ рд╕рдорд╛рди рд╣реИрдВред
рдЕрдм рд╣реИрдВрдбрд▓рд░ рдХреЗ рдкрд╛рд╕ рддреБрд░рдВрдд рдкреНрд░рддреНрдпреЗрдХ рднреВрдорд┐рдХрд╛ рдХреЗ рд▓рд┐рдП рд╕рдВрд╕рд╛рдзрдиреЛрдВ рддрдХ рдкрд╣реБрдВрдЪ рд╣реИ, рдХреЗрд╡рд▓ рдореБрдЦреНрдп рдЪреАрдЬ рдХреЛ рд╡рд╣рд╛рдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рддрд╛рдХрд┐ рдЖрдк рдЖрд╕рд╛рдиреА рд╕реЗ рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд░ рд╕рдХреЗрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЕрдХрд╛рдЙрдВрдЯрдкрд╛рд░реНрдЯ рдореЗрдВ рдЖрдк рдПрдХ рдЙрдкрдирд╛рдо, рдИрдореЗрд▓, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рднреВрдорд┐рдХрд╛, рдорд┐рддреНрд░ рд╕реВрдЪреА рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рдпрд╣ рдПрдХ рд╕рд╛рдорд╛рдЬрд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ: рдПрдХ рднрд╛рд░реА рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХрд╛рдВрд╢ рд╣реИрдВрдбрд▓рд░ рдореБрдЭреЗ рдПрдХ рдорд┐рддреНрд░ рд╕реВрдЪреА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдмрд╛рдХреА рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдЗрд╕рдХреА рдмрд┐рд▓реНрдХреБрд▓ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдореБрдЭреЗ рдХреНрдпрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП? рдпрд╛ рддреЛ рдЗрди рд╣реИрдВрдбрд▓рд░ рдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдореЙрдбреНрдпреВрд▓ (рдЕрдзрд┐рдорд╛рдирддрдГ) рдореЗрдВ рд╡рд┐рддрд░рд┐рдд рдХрд░реЗрдВ, рдпрд╛ рдПрдХреНрд╕реЗрд╕ рдЖрд▓рд╕реА рдмрдирд╛рдПрдВ ( рдпреВрдирд┐рдЯ рдореЗрдВ рд▓рдкреЗрдЯреЗрдВ -> рджреЛрд╕реНрддреЛрдВ рдХреА рд╕реВрдЪреА ), рдореБрдЦреНрдп рдмрд╛рдд рдпрд╣ рдирд╣реАрдВ рд╣реИ рдХрд┐ IQueryable <Friend> рдХреЛ рд╡рд╣рд╛рдВ рд░рдЦрд╛ рдЬрд╛рдП , рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдПрдХ рд╕реЗрд╡рд╛ рдирд╣реАрдВ рд╣реИ - рдпрд╣ рдПрдХ рдбреЗрдЯрд╛ рд╕реЗрдЯ рд╣реИ рдЬреЛ рднреВрдорд┐рдХрд╛ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред
рдореИрдВрдиреЗ рдЕрдкрдиреЗ "рдЖрд╡реЗрджрди" рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ, рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рджреНрд╡рд╛рд░рд╛ рд╡рд░реНрддрдорд╛рди рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рджреНрд╡рд╛рд░рд╛ рд╕реНрд╡реАрдХреГрдд рдФрд░ рдкреНрд░рддрд┐рдмрдВрдзрд┐рдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдбрд╛рд▓ рджреА, рдпрд╣ рдкреНрд░рд╢рд╛рд╕рдХ рдХреА рднреВрдорд┐рдХрд╛ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ:
type AdminInfo = { ActiveUsersEmails: string list BanUsersEmails : string list } type UserInfo = { Name:string Surname:string }
рдХреНрд▓реЗрдо рд╕реЗ рдХреНрдпрд╛ рдЕрдВрддрд░ рд╣реИ? рдХреНрдпрд╛ рдпрд╣ рд╕рдВрднрд╡ рд╣реИ рдХрд┐ User.Claims рдХреЛ рдХрдВрдЯреНрд░реЛрд▓рд░ рдореЗрдВ рдмрдирд╛рдпрд╛ рдЬрд╛рдП рдФрд░ рдЙрд╕реА рдЪреАрдЬ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛рдП?
рдЯрд╛рдЗрдкрд┐рдВрдЧ рдФрд░ рдмрд╛рддрдЪреАрдд рдореЗрдВ: рдореЙрдбреНрдпреВрд▓, рдбреЗрд╡рд▓рдкрд░ рдХреЛ рдПрдХ рд╣реА рд╕рдВрджрд░реНрдн рдореЗрдВ рд╣реИрдВрдбрд▓рд░ рдкрд░ рдХреЛрдб рдЙрджрд╛рд╣рд░рдг рджреЗрдЦрдиреЗ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИ, рд╡рд╣ рдПрдХ рд╣реИрдВрдбрд▓рд░ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд░реВрдЯрд┐рдВрдЧ рдореЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕рднреА рд╕рдВрдХрд▓рди рдХрд░рддрд╛ рд╣реИ
let AccountPart handler = let getUserInfo ctx = async.Return {Name="Al";Surname="Pacino"} permissionHandler [User;Admin] getUserInfo handler
getUserInfo рдЦрд╛рддрд╛ рдореЙрдбреНрдпреВрд▓ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рд╡реНрдпрдХреНрддрд┐рдЧрдд рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрджрд░реНрдн рддрдХ рдкрд╣реБрдВрдЪрддрд╛ рд╣реИ (рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ user'a, admina рд╣реИ)
рдЕрдиреБрдорддрд┐рдХрд░реНрддрд╛ jwt рдЯреЛрдХрди рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕реЗ рдбрд┐рдХреНрд░рд┐рдкреНрдЯ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдПрдХреНрд╕реЗрд╕ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ, рд╕реБрд╡реЗ рдХреЗ рд╕рд╛рде рд╕рдВрдЧрддрддрд╛ рдмрдирд╛рдП рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдореВрд▓ рд╡реЗрдмрдкрд╛рд░реНрдЯ рд▓реМрдЯрд╛рддрд╛ рд╣реИ
рдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХреЛрдб github рдкрд░ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!