3 заметки с тегом

asp.net core

Жизненный цикл запросов в ASP.NET Core MVC

Жизненный цикл — это цепочка событий, этапов и компонентов, которые взаимодействуют друг с другом, чтобы обработать запрос пользователя и предоставить ему ответ.

Общий вид на жизненный цикл ASP.NET Core MVC приложений:

Он содержит в себе несколько этапов:

  • Middlewares
  • Routing
  • Controller Initialization
  • Controller action execution
  • Result Execution
  • View Rendering

Middlewares

Middlewares представляют из себя базовые блоки, с помощью которых строится HTTP пайплайн. Такой пайплайн представляет из себя конвейер, который обрабатывает каждый запрос. Каждый блок получает запрос и смотрит на него, если может предоставить ответ — возвращает его, если нет, передаёт запрос следующему блоку.

В ASP.NET Core у нас есть 4 метода, с помощью которых мы можем создавать свои middlewares.

  • Use
  • Run
  • Map
  • MapWhen

Официальная документация

Routing

Маршрутизация позволяет найти для каждого URL подходящий обработчик, а также извлекает все параметры из URL и красиво их нам предоставляет. Для работы роутинга нам нужны две middleware:

  • UseRouting
  • UseEndpoints

Как все это работает?

UseRouting встраивает класс EndpointRoutingMiddleware, он смотрит на конечные точки, которые есть в приложении и выбирает подходящую. Выбор происходит на основании URL и заголовков. После того как нужный обработчик найден (Request delegate) его присваивают свойству Endpoint(IEndpointFeature) внутри текущего HttpContext. В дальнейшем мы можем получить его значения с помощью метода GetEndpoint.

UseEndpoints встраивает EndpointMiddleware. Он отвечает за выполнение установленной ранее конечной точки.

Официальная документация

Controller initialization

Для обеспечения работы контроллеров у есть два класса: ResourceInvoker, ControllerActionInvoker.

ResourceInvoker является абстрактным классом, который содержит общую логику работы с ресурсом, обработку исключений и результата.

ControllerActionInvoker наследует ResourceInvoker и добавляет в него логику работы с контроллерами и их методами.

Каждый из этих классов содержит машину состояний, где каждое состояние отвечает за свой этап жизненного цикла контроллера.

Исходники классов можно посмотреть на github (ResourceInvoker, ControllerActionInvoker).

Action workflow

Работа каждого метода контроллера состоит из своего жизненного цикла. Основой которого являются фильтры. Каждый фильтр может отрабатывать как и перед запуском действия, так и после.

Общий вид этого жизненного цикла:

  • Фильтры авторизации
  • Фильтры ресурсов
  • Привязки моделей
  • Фильтры действий
  • Выполнение метода контроллера
  • Фильтры исключений
  • Фильтры результатов
  • Выполнение результата
  • Фильтры результатов

Детальнее про фильтры можно почитать на метаните.

Result execution

Методы контроллера возвращают объекты результата, которые в дальнейшем преобразовываются в соответствующее представление. Объект результата должен наследовать абстрактный класс ActionResult. Фреймворк предоставляет нам большое множество готовых классов.

Общий вид того как происходит рендеринг представлений:

Источники

 Нет комментариев    85   27 дн   .net   asp.net core   c#

Как я делал бота для Facebook workplace

Дали мне задачу: написать бота для мессенджера workplace, с помощью которого можно получать уведомления из нашей CRM и управлять разными вещами. Расскажу о разных интересных вещах с которыми я столкнулся. Бота писал с помощью ASP.NET Core Web API.

Вебхуки

Для того чтобы бот мог обрабатывать запросы и сообщения от Facebook нам надо настроить вебхуки. Webhook — механизм оповещения системы о событиях. Для того чтобы Facebook принял наш хук, он должен обрабатывать как GET так и POST запросы.

Подробнее о Webhook в официальной документации

GET запрос служит для валидации работы нашего эндпоинта. POST принимает данные связанные с активностью пользователя, будь то нажатие на кнопки или другая активность.

Показать код метода-обработчика GET запроса

public IActionResult Receive(
[FromQuery(Name = "hub.mode")] string mode,

    [FromQuery(Name = "hub.challenge")] string challenge,

    [FromQuery(Name = "hub.verify_token")] string verifyToken)
{

   if (string.IsNullOrEmpty(verifyToken)) {

       return Unauthorized();

    }


    if (verifyToken.Equals(FacebookEnvironment.FacebookVToken)) {

        return Ok(challenge);

    }

    return Unauthorized();

}

В качестве verify_token используется токен, который мы указали при регистрации нашего хука.

Показать код метода-обработчика POST запроса

public async Task<IActionResult> Receive([FromBody]FbResponse response = null)
{
    if (response is null) {
        return BadRequest();
    }

    if (response.Object != "page") {
        return Ok();
    }

    foreach (var entry in response.Entries) {
        foreach (var message in entry.Messaging) {
            await PrepareMessageAsync(message);
        }
    }
    return Ok("EVENT_RECEIVED");
}

Авторизация запросов Facebook

Для авторизации Facebook использует специальный http заголовок (X-Hub-Signature), в нем он передает некую сигнатуру с помощью которой мы можем авторизовать запрос. Для того чтобы добавить такую функциональность в наш контроллер, добавим фильтр.

Пример кода, для проверки подписи

private const string Sha1Prefix = "sha1=";

public static bool Validate(string signature, string contentString) {
    if (!signature.StartsWith(Sha1Prefix, StringComparison.OrdinalIgnoreCase)) {
        return false;
    }
    var secret = Encoding.ASCII.GetBytes(FacebookEnvironment.AppSecret);
    var signatureWithoutPrefix = signature.Substring(Sha1Prefix.Length);
    var content = Encoding.ASCII.GetBytes(contentString);
    return GetIsHashValid(secret, signatureWithoutPrefix, content);
}

private static bool GetIsHashValid(byte[] secret, string signature, byte[] content) {
    using var hmac = new HMACSHA1(secret);
    var hash = hmac.ComputeHash(content);
    var hashString = ToHexString(hash);
    return hashString.Equals(signature);
}

private static string ToHexString(IReadOnlyCollection<byte> bytes)
{
    var builder = new StringBuilder(bytes.Count * 2);
    foreach (var b in bytes)
    {
        builder.AppendFormat("{0:x2}", b);
    }

    return builder.ToString();
}

Тестирование бота

Как установить letsencrypt сертификат для IIS. Если же вы используете связку в виде ubuntu и nginx вам подойдет эта инструкция.

Для тестирования нужно развернуть бот на сервере, который смотрит в мир. Также необходимо чтобы у сервера было доменное имя и валидный SSL сертификат. В моем случае, в качестве сервера выступала машина на винде, так как другой внутри нашей сети не было. Как мне показалось захостить приложение написанное на .NET Core намного проще под Ubuntu + nginx нежели под Windows + IIS. В качестве поставщика сертификатов выбрал letsencrypt, так как они предоставляют бесплатный сертификат на 3 месяца, с возможностью дальнейшего обновления.

Best Practices for Building Async APIs with ASP.NET Core

На днях был вебинар от JetBrains на тему: «Лучшие практики по построению асинхронных API в ASP.NET Core».
В скором времени опубликую заметку на эту тему.

 Нет комментариев    96   2019   asp.net core   webinar