Skip to content

Instantly share code, notes, and snippets.

@sampletext32
Last active January 15, 2022 12:14
Show Gist options
  • Save sampletext32/5db5189106d5539dec373f6ecea10af2 to your computer and use it in GitHub Desktop.
Save sampletext32/5db5189106d5539dec373f6ecea10af2 to your computer and use it in GitHub Desktop.

Оглавление

  1. Обобщенная модель работы веб-сервера.
  2. HTTP запросы. Структура, заголовки.
  3. HTTP ответ. Структура, коды ответов, заголовки.
  4. Content-Type и Disposition.
  5. HTML формы в рамках протокола HTTP.
  6. URL.
  7. MIME.
  8. HTTP/2.
  9. Недостатки HTTP протокола.
  10. Cookies.
  11. HTTP Сессии.
  12. MVC. Схема паттерна, описание основных компонентов.
  13. Контроллер в MVC. Задачи и Реализация.
  14. MVC в web-приложениях.
  15. ASP.NET CORE. История и особенности.
  16. MVC и ASP.NET Core.
  17. Контроллеры и ASP.NET Core.
  18. Возвращаемое значение в контроллерах.
  19. Маршрутизация в ASP.NET Core MVC.
  20. Конфигурация статических файлов в ASP.NET Core MVC
  21. HTML-теги. Примеры.
  22. HTML формы (). Атрибуты, валидация.
  23. HTML таблицы.
  24. View Engine в ASP.NET Core MVC.
  25. Layout, _ViewStart.cshtml, _ViewImports.cshtml, Секции.
  26. HTML Helpers и Tag Helpers.
  27. Жизненный цикл запроса.
  28. Конфигурация ASP.NET Core.
  29. Среды развертывания.
  30. Обработка ошибок в ASP.NET Core.
  31. Middleware. Встроенные в ASP.NET Core.
  32. Фильтры в ASP.NET Core.
  33. Реализация фильтров-сервисов.
  34. Привязка моделей в ASP.NET Core.
  35. Валидация моделей в ASP.NET Core.
  36. JSON.
  37. XML.
  38. ASP.NET Core Web API.
  39. Возвращаемые значения в Web API.
  40. Web API – примеры методов в рамках HTTP запросов.
  41. Сервисной слой.
  42. DTO.
  43. DI контейнер, сервис и контроллер.
  44. Cross-Site Request Forgery.
  45. Аутентификация и Авторизация. Концепция и разница.
  46. ASP.NET Identity – основные компоненты для реализации собственной авторизации.

01. Обобщенная модель работы веб-сервера.

image

02. HTTP запросы. Структура, заголовки.

Пример

GET /index.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html
<CRLF>
  • Первая строка всегда состоит из

    • Типа запроса (GET, POST, PUT, DELETE)
    • URI Ресурса (./index.html)
    • Версии протокола (HTTP/1.1)
  • Все последующие строки содержат HTTP заголовки

    • User-Agent: Mozilla/5.0
  • Запрос заканчивается переводом строки <CRLF>

03. HTTP ответ. Структура, коды ответов, заголовки.

Пример

HTTP/1.1 200 OK
Server: nginx/0.6.31
Content-Language: ru
Content-Type: text/html; charset=utf-8
<CRLF>
SOME AWESOME RESULT
  • Первая строка всегда содержит
    • Версию протокола (HTTP/1.1)
    • Код состояния (200)
    • Статус (OK)
  • Все последующие строки содержат HTTP заголовки ответа
    1. Content-Language: ru
  • Затем ответ содержит символ перевода строки <CRLF>
  • После него идут сами данные ответа (SOME AWESOME RESULT)

04. Content-Type и Disposition.

Заголовок Content-Type определяет тип передаваемого ресурса

Пример

Content-Type: text/html; charset=utf8

Заголовок Content-Disposition содержит информацию, как необходимо обрабатывать передаваемый ресурс

Пример:

Content-Disposition: attachment; filename="index.html"
  • attachment - скачать
  • inline - показать данные как есть

05. HTML формы в рамках протокола HTTP.

HTTP форма - раздел HTML документа, позволяющий пользователю вводить информацию для последующей обработки системой. Пример

<form action="index.php" method="post">
    <label>
    <input>
</form>

Заголовок формы содержит

  • Атрибут action, который указывает, куда отправить данные
  • Атрибут method, который указывает, каким типом запроса отправлять данные

Форма может содержать неограниченное количество input полей

NOTE: GET запрос ограничен 4КБ, так что большое количество текста может сломать логику вашей формы

06. URL.

Uniform Resource Locator

Пример

https://mysite.com:443/demo/index.php?id=27&lang=en#lectures

URL содержит

  • Протокол для связи (http, https - чаще всего, ftp, magnet)
  • Хост или IP адрес (example.com, 192.168.1.1)
  • Порт подключения в диапазоне [0.65535] (http 80, http 443, ftp 21)
  • Путь к ресурсу (demo/index.php)
  • Строку запроса (пары ключ=значение, разделённые &)(?id=27&lang=en)
  • Фрагмен (якорь) для перехода к определённому разделу страницы (#lectures)

URL кодируется стандартом RFC 1738

  • Поддерживаются любые незарезервированные символы
  • Все зарезервированные или нестандартные символы экранируются в формате %[code]
    • например пробел %20

07. MIME.

Multipurpose Internet Mail Extensions

Спецификация для передачи по интернету медиа контента

Концепция MIME: То же самое, что в пункте 4

Заголовок Content-Type определяет тип передаваемого ресурса

Пример

Content-Type: text/html; charset=utf8

Заголовок Content-Disposition содержит информацию, как необходимо обрабатывать передаваемый ресурс

Пример

Content-Disposition: attachment; filename="index.html"
  1. attachment - скачать
  2. inline - показать данные как есть

08. HTTP/2.

HTTP/2 - вторая версия протокола HTTP, используемая в современном интернете

Главные отличия от HTTP/1

  • Протокол является бинарным, а не текстовым
  • Сервер теперь может послать незапрошенные данные, за счёт чего можно приклеивать к странице связанные файлы сразу (.css, .js)
  • Сжатие заголовов и данных для ускорения запросов
  • Мультиплексирование (склеивание) запросов (после запроса ресурса соединение не закрывается, а используется повторно)

Имеет полную обратную совместимость с HTTP/1

09. Недостатки HTTP протокола.

HTTP протокол не имеет состояния и не хранит информацию о запросах (stateless)

  • Не поддерживает состояние, каждый запрос - отдельный и не связанный с остальными
  • Сервер не знает, поступают ли 2 запроса от одного клиента или разных
  • Проблема состояния - переход между страницами требует повторной аутентификации
  • Информация теряется при переходе на другие страницы
  • Сложная персонализация контента

10. Cookies.

Небольшой текстовый файл без кода

  • Отправляется сервером при первом запросе Set-Cookie: lang=en
  • Хранится на клиенте
  • При необходимости изменений, конкретный параметр задаётся в заголовке Cookie: lang=ru

Зачем нужен:

  • Корзины
  • Логины
  • Покупки
  • История посещений
  • Персонализация
  • Отслеживание

Структура Cookie:

Набор пар ключ=значение, разделённые ;

Например: Set-Cookie: lang=en; time=22.00

Область действия Cookie определяется атрибутом Domain=page.html

При этом Path=/; указывает на URL, при котором Cookie передаётся

Жизненный цикл Cookie

  • Либо атрибут Expires=Wed 13 Jan 2021 22:00:00 GMT - дата окончания действия
  • Либо атрибут Max-Age=100, время в секундах от момента получения (0 - Cookie не используется)

11. HTTP Сессии.

Способ хранения информации о пользователе при использовании нескольких страниц

При использовании сессии пользователь может быть однозначно идентифицирован между несколькими запросами

Суть заключается в том, что клиент сохраняет ID сессии в локальном хранилище (например в Cookie) и при необходимости передаёт серверу

12. MVC. Схема паттерна, описание основных компонентов.

Model-View-Controller - архитектурный паттерн, разработанный Трюгве Реенскаугом в 70-х в языке SmallTalk

Концепция разделения компонентов кода по назначению с целью переиспользования

Был популярен в Desktop приложениях, однако сейчас в основном заменён на родственные

MVP (Model-View-Presenter) и MVVM (Model-View-ViewModel)

Компоненты

  • Model - набор классов, описывающих предметную область (часто, прямые объекты из БД)
  • View - набор классов, определяющих, как и что будет отображаться на экране
  • Controller - набор классов, отвечающих за обработку запросов пользователя и выдачую данных во View

13. Контроллер в MVC. Задачи и Реализация.

Все запросы пользователя идут в соответствующий контроллер, который

Обращается в модель за данными и передаёт их по View для формирования интерфейса

Содержит всю логику уровня приложения (всё, что не связано с моделью)

Пример:

  • Пользователь нажимает на кнопочку Узнать %DATA_NAME% (подставьте любой объект)
  • Кнопочка сообщает контроллеру, что она была нажата
  • Контроллер обрабатывает сообщение - обращается к модели и запрашивает данные
  • Контроллер может обратиться к View для запроса изменений (например заблокировать кнопочку)
  • Модель оповещает представление об изменении состояния (например переключилась песенка)
  • Представление запрашивает у модели информацию состояния

Контроллер не ограничен передачей данных!

Он интерпретирует ввод данных и выполняет соответствующие действия с моделью

14. MVC в web-приложениях.

  • Входящий запрос от браузера отправляется в контроллер
  • Контроллер обрабатывает запрос и создаёт модель представления (ViewModel) + выбирает View
  • ViewModel передаётся во View
  • View преобразует ViewModel в HTML и возвращает HTTP Response

image

15. ASP.NET CORE. История и особенности.

ASP.NET CORE - кроссплатформенный фреймворк для создания веб приложений (веб-сайты, сервисы, приложения-сервисы)

Фреймворк предлагает множество технологий: MVC, WebAPI, ViewEngine (Razor)

Может быть использован с фронтенд решениями: React, Angular, Blazor

ASP.NET CORE может быть запущен как на старом .Net Framework, так и на .Net Core

ASP.NET появился в 2002 году, работал только на Windows в среде IIS

С появлением .Net Core, появился ASP.NET Core - 2016, кроссплатформенный и улучшенный

Сейчас уже появился .Net 5, предлагающий лучшие скорости работы, унифицированные инструменты разработки и C# 9

16. MVC и ASP.NET Core.

ASP.NET Core MVC предоставляет функции для создания WebAPI и веб-приложений

Основные аспекты:

  • Использует шаблон MVC
  • Open-source
  • Легковесный
  • Разработчку нужно указать только нестандартные аспекты (соглашение важнее конфигураций)
  • Автоматическая привязка моделей к данным HTTP запросов
  • Поддержка валидаций
  • Роутинг
  • Razor
  • Filter, Middleware и т.д.

17. Контроллеры и ASP.NET Core.

  • Контроллеры располагаются в папке Controllers
  • Соглашение именования - %Name%Controller
  • Каждый контроллер наследует класс Controller, который предоставляет доступ к Request, Response, HttpContext, RouteData, ModelState, User, ViewBag
  • На основе маршрута выбирается контроллер
  • Каждый контроллер содержит Action методы, каждый запрос привязывается к конкретному методу

18. Возвращаемое значение в контроллерах.

Возвращаемое значение представляет собой различные коды HTTP статусов

Тип возвращаемого значения унаследован от ActionResult

Пример:

  • StatusCodeResult - return Ok("Success");,
  • JsonResult - return Json(new object());,
  • ContentResult - return Content(AppVersion);,
  • FileContentResult - return File(fileStream, mimeType, fileName);

ASP.NET Core сопоставляет параметры методов по шаблонам (например Users/{id})

19. Маршрутизация в ASP.NET Core MVC.

За маршрутизацию отвечает Middleware

Маршруты с помощью шаблонов описывает Mapping запроса на конкретный Action у контроллера

  • По соглашению - не требуется дополнительная конфигурация, достаточно основной
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Маршруты поддерживают RegEx:

endpoints.MapControllerRoute(name: "blog", template: "{year}/{month}/{day}", 
    defaults: new { controller="Blog", action= "ByDate" },
    constraints: new { year=@"\d{4}", month=@"\d{1,2}", day=@"\d{1,2}",
});
  • На основе аттрибутов методов контроллера (HttpPost, Action, Route)
public class ArticlesController : Controller
{
    [Route("/blog/{page}")]
    [HttpPost]
    public IActionResult List(int page)
    {
        return View(page);
    }
}

20. Конфигурация статических файлов в ASP.NET Core MVC.

Статические файлы необходимы для работы веб-приложения (фронтенд)

.html, .css, .js и другие ресурсы могут быть переданы приложению с помощью ASP.NET Core

Примеры:

  • Хостинг стандартной папки wwwroot
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseStaticFiles();
}
  • Хостинг кастомной папки
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseStaticFiles(); // для стандартной папки wwwroot
    app.UseStaticFiles(new StaticFileOptions()
    {
        FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), "OtherFiles")),
        RequestPath = new PathString("/files")
    });
}

21. HTML-теги. Примеры.

Hyper Text Markup Language

HTML - стандартизированный язык разметки, код интерпретируется браузерами

Для оформления страниц используют каскадные таблицы стилей (CSS)

Актуальная версия - HTML5

Семантическая вёрстка - подход к созданию HTML страниц с использованием HTML тегов на основе их семантики

Семантический элемент чётко описывает его значение как для браузера так и для разработчика

<p>Some random text...</p>

Теги позволяют браузеру понять, что из себя представляет страница..

Пример:

<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8" />
  <title>TITLE</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
 ...    
</body>
</html>
  • <header> - вводный контент, содержит заголовок и нередко - логотип
  • <nav> - отдельная секция документа
  • <body> - весь контент страницы, может быть только 1
  • <main> - основная часть контента внутри <body>
  • <title> - заголовок страницы, который отображается во вкладке браузера
  • <aside> - часть документа, которая не связана с основным контентом сайта (чаще боковые панели, сноски)
  • <footer> - содержит нижний колонтитул (футер, подвал) страницы
  • <section> - представляет раздел страницы
  • <article> - независимый раздел страницы, предназначенный для распространения
  • <figure> - самостоятельный контент с заголовком
  • <details> - раскрытие дополнительной информации, если в самом начале есть <summary>, то это метка виджета раскрытия
  • <time> - представление времени в 24-х часовом формате, либо точной даты
  • <address> - контактные данные для ближайшего <article> или <body>

22. HTML формы (<form>). Атрибуты, валидация.

HTML формы содержат интерактивные элементы управления, которые позволяют отправлять информацию на сервер

Пример:

<form>
    <label for="fname">First name:</label><br>
    <input type="text" id="fname" name="fname" value="John"><br>
    <input type="submit" value="Submit">
</form>
<input type="text">
<input type="number">
<input type="password">
<input type="email">
<input type="search">
<input type="checkbox">
<input type="radio">
<input type="range">
<input type="submit">
<input type="button">
<input type="file">

Атрибуты:

  • value - начальное значение у элемента, необязателен для всех, кроме radio и checkbox
  • name - имя элемента при отправке
  • placeholder - подсказка пользователю, работает только в text, search, tel, url или email
  • required - поле обязательно к заполнению перед отправкой
  • autofocus - элемент должен получить фокус при загрузке страницы
  • disabled - элемент недоступен для взаимодействия
  • min и max - минимальное и максимальное значения соответственно

Валидация:

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

23. HTML таблицы.

  • Таблица <table>
  • Каждая строка - <tr>
  • Каждая ячейка - <td> или <th>

Пример:

<table>
    <tr>
        <td>Cell 1.1</td>
    </tr>
    <tr>
        <td>Cell 2.1</td>
    </tr>
</table>

У каждой таблицы есть

  • Заголовок
  • Тело
  • Подвал

(не более 1) - Для хранения одной или нескольких строк

  • <thead> вверху таблицы
  • <tbody> в середине таблицы
  • <tfoot> внизу таблицы

24. View Engine в ASP.NET Core MVC.

  • Views в ASP.NET Core MVC используют движок Razor View Engine для встраивания кода .NET в HTML-разметку.
  • Содержат минимальную логику, только для отображения данных
  • Данные могут быть переданы через ViewData, ViewBag или ViewModel
    1. ViewBag (dynamic тип):
      1. Action: ViewBag.Message = "Hello World!";
      2. View: @ViewBag.Message
    2. ViewData (dictionary)
      1. Action: ViewData["message"] = "Hello World!";
      2. View: @ViewData["message"]
    3. Подготовленные модели (строгая типизация):
      1. Action: return View(model);
      2. View: @model ModelDataType и затем @Model.<Свойство>

Razor использует специальные языковые вставки, обычно начинающиеся с @

  • @if - условия
  • @* *@ - комментарии
  • @(...) - выражения
  • @using, @model - подключения

25. Layout, _ViewStart.cshtml, _ViewImports.cshtml, Секции.

Layout - определяет основной шаблон сайта

Находится в файле ~/Views/Shared/_Layout.cshtml

  • Как правило View ссылается на подобный шаблон и по сути является просто содержимым шаблона
  • Razor вначале рендерит саму View, а затем рендерит шаблон и вставляет в него готовый View
  • В шаблоне указывается место куда подсунется готовое View
    @RenderBody()

_ViewStart.cshtml

  • По умолчанию, View нет необходимости указывать что они привязаны к шаблону, так как шаблон по умолчанию указывается в ~/Views/_ViewStart.cshtml
  • Если нужно выбрать другой шаблон для View, укажите его во View
        @{
            Layout = "~/Views/Shared/_UncommonLayout.cshtml";
        }

_ViewImports.cshtml

  • Если директива или зависимость являются общими для многих представлений они могут быть указаны глобально в ViewImports: ~/Views/_ViewImports.cshtml
  • Данный файл не поддерживает остальные возможности Razor

Razor позволяет создавать Cекции

  • Определяются во View
        @section SideBar {
            <aside>
                Some side info
            </aside>
        }
  • Секции рендерятся в шаблоне используя RenderSection()
  • Используется как правило для «передачи» HTML кода шаблону

26. HTML Helpers и Tag Helpers.

  • Razor предоставляет удобный механизм рендеринга HTML тегов
  • Через свойство Html (Каждая RazorPage имеет данное свойство)
  • Но такой подход не рекомендуется, лучше используйте Tag Helpers!

Примеры HTML Helpers:

  • @Html.ActionLink
  • @Html.TextBox
  • @Html.BeginForm
  • @Html.TextArea
  • @Html.CheckBox
  • @Html.Password
  • @Html.Display
  • @Html.Hidden
  • @Html.Editor
  • @Html.Label
  • @Html.DropDownList
  • @Html.Action

Tag Helpers позволяют участвовать серверному коду в создании и рендеринге HTML-элементов в Razor представлениях

  • Существуют встроенные Tag Helpers для многих распространенных задач
  • Tag Helpers предоставляют
    • Близкий к HTML опыт разработки
    • Отличная поддержка IntelliSense для создания Razor разметки
    • Более производительный, надежный и поддерживаемый код
  • Можно создать свой Tag Helper
    [HtmlTargetElement("h1")]
    public class HelloTagHelper : TagHelper
    {
        private const string MessageFormat = "Hello, {0}";
        public string TargetName { get; set; }
        
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            string formattedMessage = string.Format(MessageFormat, this.TargetName);
            output.Content.SetContent(formattedMessage);
        }
    }
    @using WebApplication;
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelper
    @addTagHelper WebApplication.TagHelpersHelloTagHelper, WebApplication
    <div class="tag-helper-content">
        <h1 target-name="John"></h1>
    </div>

27. Жизненный цикл запроса.

image

28. Конфигурация ASP.NET Core.

ASP.NET Core использует метод Configure() в файле Startup.cs для:

  • Настройки конвейера HTTP-запросов
  • Определение поведения для различных сред развертывания
  • Это делается с помощью IApplicationBuilder и IHostingEnvironment
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }
    else { app.UseExceptionHandler("/Home/Error"); }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseMvcWithDefaultRoute();
}
  • Конфигурация приложения в ASP.NET Core основана на парах ключ-значение

    • Конфигурации приложения задаются в провайдерах конфигураций
    • Провайдеры конфигураций считывают данные из специальных источников конфигураций
    • Хранилище ключей Azure, аргументы командной строки
    • Пользовательские провайдеры (установленные или созданные)
    • Специальные файлы, переменные окружения и т. д.
    • Одним из источников по умолчанию является appsettings.json
  • Конфигурация приложения считывается при запуске приложения с помощью провайдеров конфигурации

    • Конфигурационные свойства мэпятся в IConfiguration
    • IConfiguration доступен в DI контейнере приложения
  • Конфигурационные параметры, по соглашению, задаются в ConfigureServices()

    • Вызывается перед методом Configure() объектом WebHost
    • Как правило все вызовы по шаблону add{Service}, а затем services.Configure(Service)
    • Добавление сервиса в контейнер сервисов:
    • Делает их доступными в приложении
    • Доступ реализуется через внедрение зависимости (Dependency Injection)
    • Делает их доступными в методе Configure()
    • Через IApplicationBuilder.ApplicationServices

Пример конфигурации сервисов:

public void ConfigureServices(IServiceCollection services)
{
    // Transient objects are always different
    // A new instance is provided to every controller and service
    services.AddTransient<DataService>();
    // Scoped objects are the same within a request
    // They are different across different requests
    services.AddScoped(typeof(DataService));
    // Singleton objects are the same for every object and request.
    services.AddSingleton<DataService>();
    ...
}

29. Среды развертывания.

  • Развертывание программного обеспечения обычно производится в нескольких средах

    • Многоэтапное развертывание является обязательным при разработке корпоративных приложений
    • ОС (реальная или виртуальная) с необходимой средой для приложения, которая запускает ваше программное обеспечение
    • Может включать в себя задачи, которые выполняются в программном приложении (например, модульные или интеграционные тесты)
  • Виды сред развертывания (часто встречаемые):

    • Dev – среда, где разрабатывается программное обеспечение
    • Test – где ПО тестируется и проверяется разработчиками
    • Stage – среда приближенная к Production, закрытая для пользователей
    • Production – когда продукт становится доступным для всех пользователей
  • ASP.NET Core настраивает поведение приложения на основе среды выполнения

    • Фреймворк поддерживает 3 среды – Development, Staging и Production
    • ASP.NET Core считывает переменную окружения – ASPNETCORE_ENVIRONMENT
    • Значение хранится в IHostingEnvironment.EnvironmentName
    • Вы можете установить любое значение. Но, среда по умолчанию - Production

30. Обработка ошибок в ASP.NET Core.

  • Есть несколько путей конфигурации обработки ошибок в ASP.NET Core:

    • Developer Exception Page – страница ошибки для разработчика
    • Exception Handler – обработчик ошибок
    • Status Code Pages – страница кода ошибки/статуса запроса
      1. Приложения ASP.NET Core не имеют по умолчанию расширенной страницы с кодом или статусом
        1. Используется Status Code Pages Middleware
        2. app.UseStatusCodePages()
        3. Данный middleware легко кастомизируются
      2. В частности поддерживают extension methods
        1. app.UseStatusCodePagesWithRedirects(…)
        2. app.UseStatusCodePagesWithReExecute(…)
    • Приложения ASP.NET Core MVC дополняются способами:
      1. Exception Filters – фильтры ошибок
      2. Model Validation (ModelState) – валидация моделей
  • Настройка кастомной страницы для ошибки используя ExceptionHandlerMiddleware

    •       public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                app.UseExceptionHandler("/Home/Error");
            }
    • Вы можете реализовать обработчик по данному адресу
    • Это может как Action контроллера, страница Razor или другой обработчик

31. Middleware. Встроенные в ASP.NET Core.

Middleware - это ни что иное, как компонент (класс), который выполняется при каждом запросе в приложении ASP.NET Core.

Каждый компонент:

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

Общая схема работы image

Request Delegates обрабатывают каждый HTTP запрос

  • Настраиваются с помощью extension methods Run(), Map() и Use()

  • Request Delegates (также называемые компонентами middleware) могут быть:

    • анонимный метод (in-line middleware)
      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
          app.Use(async (context, next) =>
          {
              // Do work that doesn't write to the Response.
              await next();
              // Do logging or other work that doesn't write to the Response.
          });
      }
    • определен как класс (для многократного повторного использования)
      public class CustomMiddleware
      {
          private readonly RequestDelegate next;
          public CustomMiddleware(RequestDelegate next)
          {
              this.next = next;
          }
          // IMyService is injected into InvokeAsync
          public async Task InvokeAsync(HttpContext httpContext, IMyService svc)
          {
              svc.MyProperty = 1000;
              await this.next(httpContext);
          }
      }
      public static class CustomMiddlewareExtensions
      {
          public static IApplicationBuilder UseCustom(this IApplicationBuilder builder)
          {
              return builder.UseMiddleware<CustomMiddleware>();
          }
      }
      public class Startup
      {
          public void Configure(IApplicationBuilder app)
          {
              app.UseCustom();
              ...
          }
      }
  • Каждый компонент middleware отвечает за:

    • Вызов (Invoking) следующего компонента в конвейере
    • short-circuiting (замыкает) the pipeline – завершает обработку запроса в конвейере
  • Метод Use() используется для объединения нескольких делегатов в одну цепочку

    • Метод может закоротить конвейер (если он не вызывает next())
  • Первый Run() делегат останавливает конвейер

    • Run() - это соглашение
    • Некоторые компоненты middleware могут предоставлять Run{Middleware} методы
    • Эти методы выполняются в конце конвейера
  • Метод Map() используется для ветвления конвейера

    • Конвейер запросов разветвляется на основе заданного URL запроса

image

  • Конвейер запросов ASP.NET Core состоит из последовательности Request Delegates, вызываемых один за другим
  • Пользовательские Request Delegates создаются с помощью IApplicationBuilder

Встроенные Middleware:

  • UseAuthentication
  • UseCookiePolicy
  • UseCors
  • Diagnostics
    • UseExceptionHandler
    • UseDevelopmentExceptionPage
    • UseStatusCodePages
  • UseHttpsRedirection
  • UseHsts
  • UseStaticFiles
  • UseResponseCaching
  • UseResponseCompression
  • UseRequestLocalization
  • UseRouter
  • UseSession
  • UseRewriter
  • UseWebSockets
  • UseWelcomePage

32. Фильтры в ASP.NET Core.

Фильтры позволяют запускать код до или после определенных этапов в конвейере обработки запросов

  • Фильтры похожи, но на то же самое, что middleware
    • Middleware работает на уровне ASP.NET Core
    • Фильтры работают только на уровне MVC

Существуют несколько видов фильтров

  • Authorization Запускается первым. Определяет авторизован ли пользователь для доступа к ресурсу данного запроса
  • Resource Запускается сразу за Authorization. Может запускать код перед или после всего в конвейере.
  • Action Запускается сразу перед и после вызова соответствующего Action метода
  • Exception Добавляет глобальные политики для возникающих необработанных ошибок
  • Result Запускается сразу перед и после вызова соответствующего Action Result метода

Создание фильтра:

public class SampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        //Код – перед действием
    }
    public void OnActionExecuted(ActionExecutedContext context)
    {
        //Код – после действия
    }
}

Фильтры добавляются в ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add(typeof(SampleActionFilter));
    });
}

33. Реализация фильтров-сервисов.

Это просто пример из презентации, назовите классы по-другому

public class FeatureAuthFilter : IAuthorizationFilter
{
    IFeatureService featureAuth;
    public FeatureAuthFilter(IFeatureService service)
    {
        this.featureAuth = service;
    }
}
services.AddSingleton<IFeatureService, FeatureService>();
services.AddSingleton<FeatureFilter>();
[TypeFilter(typeof(FeatureAuthFilter))]
public IActionResult Index()
{
    return View();
}

34. Привязка моделей в ASP.NET Core.

Привязка моделей в ASP.NET Core MVC обеспечивает сопоставление данных в HTTP запросах и параметров методов контроллера

  • Параметрами могут быть как примитивные типы, так и пользовательские
  • Сопоставление производится по имени
  • В случае объектов классов сопоставление производится по именам публичный свойств

Пример: https://mysite.com/posts/edit/6 -> PostsController public IActionResult Edit(int? id)

Привязка моделей работает с данными:

  • Данные форм, отправленные в POST
  • Данные в URL
  • Данные в заголовках, куках, сессиях и т.д. с помощью кастомных привязок
  • Данные с данных источников хранятся парами имязначение
  • Фреймворк смотрит на параметры и ищет их в запросе, если не находит, идет смотреть следующий
  • Порядок просмотра источников данных указан выше

Если привязка завершается неудачно, фреймворк не выдает ошибку

  • Каждый action метод, принимающий пользовательский ввод, должен проверять, была ли привязка успешной
  • Результат можно узнать через свойство ModelState.IsValid
  • ModelState также содержит коллекцию ошибок
  • Привязка моделей по умолчанию отлично подходит для большинства сценариев разработки
  • Тем не менее все кастомизируется

Пройдёмся по списку ошибок:

public class UsersController : Controller
{
    public IActionResult Register(RegisterUserBindingModel model)
    {
        if(!ModelState.IsValid)
        {
            foreach (var error in ModelState.Values.SelectMany(v => v.Errors))
            {
                DoSomething(error);
            }
            // TODO: Return Error Page
        }
        return Ok("Success!");
    }
}

Фреймворк позволяет указать поведение привязки

  • [BindRequired] Добавляет model state ошибку если привязка не удалась.
  • [BindNever] Указываем, что данный параметр нужно игнорировать при привязке.
  • [From{source}] Используется для указания источника данных для привязки. [FromHeader], [FromQuery], [FromRoute], [FromForm], [FromBody]
  • [FromServices] Используется dependency injection для привязки параметров с сервисов.
  • [ModelBinder] Используется чтобы указать какой класс реализует связывание, которое будет применено для выбранного параметра.

Кастомный Binder

  • Для создания необходимо создать – BindingProvider и Binder

    [ModelBinder(BinderType = typeof(StudentEntityBinder))]
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
    public class StudentEntityBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            //TODO: Do Magic ...
            bindingContext.Result = ModelBindingResult.Success(model);
            return Task.CompletedTask;
        }
    }
    public class StudentEntityBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (context.Metadata.ModelType == typeof(Student))
            {
                return new BinderTypeModelBinder(typeof(StudentEntityBinder));
            }
            return null;
        }
    }
  • И сконфигурировать приложение для работы с новым binder’ом (0 - вставить в начало)

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers(options =>
        {
            options.ModelBinderProviders.Insert(0, new StudentEntityBinderProvider());
        });
    }

35. Валидация моделей в ASP.NET Core.

В .NET представлена абстрактная модель валидации через атрибуты - Одни атрибуты как правило описывают ограничения значений * Аналогично как ограничения в базах данных - Другие применяют шаблоны к данным * Кредитные карты, номера телефонов, адреса электронной почты и т. д. - Атрибуты простой способ валидации * Они задаются на уровне свойств

Популярные встроенные атрибуты:

  • [CreditCard] - строка соответствует кредитной карте
  • [Compare] - проверка на равенство
  • [EmailAddress] - строка соответствует email-адресу
  • [Phone] - строка соответствует шаблону телефона
  • [Range] - число в промежутке
  • [RegularExpression] - строка соответствует указанному регулярному выражению
  • [Required] - поле обязательно (не null)
  • [StringLength] - проверка длины строки
  • [Url] - строка соответсвует шаблону Url ссылки

Иногда нужно создавать кастомные атрибуты

public class IsBefore : ValidationAttribute
{
    private const string DateTimeFormat = "dd/MM/yyyy";
    private readonly DateTime date;
    public IsBefore(string dateInput)
    {
        this.date = DateTime.ParseExact(dateInput, DateTimeFormat, CultureInfo.InvariantCulture);
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if ((DateTime)value >= this.date) return new ValidationResult(this.ErrorMessage);
        return ValidationResult.Success;
    }
}

Использование:

public class RegisterUserModel
{
    [Required]
    public string Username { get; set; }
    [Required]
    [StringLength(20)]
    public string Password { get; set; }
    [IsBefore("01/01/2000")]
    public DateTime BirthDate { get; set; }
}

Также можно валидировать прямо в Bind Model

  • Реализуя IValidatableObject
  • public class RegisterUserModel : IValidatableObject
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public string ConfirmPassword { get; set; }
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if(string.IsNullOrEmpty(Username)) yield return new ValidationResult("Username cannot be empty");
            if(string.IsNullOrEmpty(Password)) yield return new ValidationResult("Password cannot be empty");
            if(ConfirmPassword != Password) yield return new ValidationResult("Passwords do not match");
        }
    }

36. JSON.

JavaScript Object Notation (JSON) - это открытый файловый стандарт

  • Применяется подход читабельного для человека текста для передачи объектов данных
  • Объекты данных состоят из пар атрибут-значение или массива данных
  • Формат прост как для людей, так и для автоматизированного анализа и генерации

У JSON истоки от JavaScript

  • Однако он не зависит от какого-либо языка
  • На многих языках есть инструменты для генерации и анализа JSON
{
    "firstName": "Ivan",
    "courses": ["C#", "ASP.NET"],
    "age": 21,
    "date": "2012-04-23T18:25:43.511Z"
}

JSON - это очень распространенный формат данных, используемый в веб-коммуникации

  • В основном для связи браузер-сервер или сервер-сервер
  • Официальный (тип медиа) MIME для JSON - это файлы JSON, использующие расширение .json
  • JSON обычно используется в качестве замены XML
    • JSON короче и проще для понимания
    • JSON быстрее считывается и генерируется, а также более интуитивный
    • JSON не поддерживает схемы и пространства имен

37. XML.

eXtensible Markup Language

  • Расширяемый язык разметки
    • Похож на JSON
    • С точки зрения читабельности человеком и автоматизированным способом
    • С точки зрения иерархии (значения внутри значений)
  • XML - это текстовый формат данных
    • Сильная поддержка различных языков используя Unicode
    • Дизайн отражает необходимость представления реальных документов

Пример

<?xml version="1.0" encoding="UTF-8" ?>
<records>
    <record id="1">
        <name>Ivan</name>
        <email>ivan@example.com</email>
        <company>RUT</company>
    </record>
    <record id="2">
        <name>Petr</name>
        <email>petr@example.com</email>
        <company>RUT</company>
    </record>
</records>

XML Существует 2 типа MIME

  • application/xml
  • text/xml

XML широко применяется:

  • В SOA(Сервис-ориентированная архитектура) подходе (например, WCF)
  • Для настройки .NET приложений
  • В форматах Microsoft Office

38. ASP.NET Core Web API.

Web API - это интерфейс прикладного программирования

  • Используется веб-браузером (SPA - одностраничное приложение), мобильными приложениями, играми, настольными приложениями, веб-сервером и т. д.
  • Серверные веб-API (Server-Side Web APIs) состоят из общедоступных конечных точек (endpoints) (URL-ов)
  • Данные точки предоставляют систему связи запрос-ответ
  • Общение как правило происходит в формате JSON или XML
  • Общение как правило происходит в рамках протокола
  • Чаще всего HTTP

Создание веб-API с помощью ASP.NET довольно простое

  • Нет ничего кардинально отличающегося от обычного вебприложения
  • Создаются контроллеры, в них как и обычно описываются методы-действия
  • Методы играют роль конечных точек
  • Контроллер аннотируется как API Controller
    [ApiController]
    [Route("api/[controller]")]
    public class WeatherForecastController : ControllerBase
    {}
  • Контроллер наследуется от ControllerBase
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        private readonly IProductService productService;
        public ProductController(IProductService productService)
        {
            this.productService = productService;
        }
    }  
  • Контроллер аннотируется [ApiController] и [Route] атрибутами
  • Аннотация [ApiController] предоставляет несколько удобных функций
    • Автоматические HTTP 400 ответы (для ошибок model state)
    • Привязка моделей из разных источников
    • Поддержка multipart/form-data
    • Поддержка глобального пути
    • Подробные сведения о ошибках, коды состояния ошибок

39. Возвращаемые значения в Web API.

ASP.NET Core предлагает несколько опций для возвращаемых значений:

  • Конкретный тип-значение
  • IActionResult Type
  • Используется когда возможны разные варианты ответа
    [HttpGet("{id}")]
    [ProducesResponseType(200, Type = typeof(Product))]
    [ProducesResponseType(404)]
    public IActionResult GetById(int id)
    {
        var product = this.productService.GetById(id);
        if (product == null) return NotFound();
        return Ok(product);
    }
  • Рекомендуется использовать ActionResult
    [HttpGet("{id}")]
    [ProducesResponseType(200)]
    [ProducesResponseType(404)]
    public ActionResult<Product> GetById(int id)
    {
        var product = this.productService.GetById(id);
        if (product == null) return NotFound();
        return product;
    }

40. Web API – примеры методов в рамках HTTP запросов.

  • Создание GET методов для WebApi:
    [HttpGet] // GET: /api/product
    public ActionResult<IEnumerable<Product>> GetProducts()
    {
        return this.productService.GetAllProducts();
    }
    [HttpGet("{id}")] // GET: /api/product/5
    public ActionResult<Product> GetProduct(long id)
    {
        var product = this.productService.GetById(id);
        if (product == null) return NotFound();
        return product;
    }
  • Создание POST методов для WebApi:
    [HttpPost] // POST: api/product
    public ActionResult<Product> PostProduct(ProductBindingModel productModel)
    {
        this.productService.RegisterProduct(productModel);
        return CreatedAtAction("GetProduct", new { id = productModel.Id }, productModel);
    }
    CreatedAtAction * Возвращает HTTP 201 (Created) * Добавляет Location в заголовки * Использует путь GetProduct для генерации URL
  • Создание PUT методов для WebApi:
    [HttpPut("{id}")] // PUT: api/product/5
    public IActionResult PutProduct(long id, ProductBindingModel productModel)
    {
        if (id != productModel.Id) return BadRequest();
        this.productService.EditProduct(id, productModel);
        return NoContent();
    }
    • Используется как Update – обновление существующей сущности (HTTP PUT)
    • Ответ - 204 (No Content)
  • Создание DELETE методов для WebApi:
    [HttpDelete("{id}")] // DELETE: api/product/5
    public ActionResult<Product> DeleteProduct(long id)
    {
        var product = this.productService.DeleteProduct(id);
        if (product == null) return NotFound();
        return product;
    }
    • HTTP DELETE
    • Ответ - 204 (No Content)

41. Сервисной слой.

  • Сервисной слой представляет собой «фасад», скрывающий логику работы с данными от контроллера
    • Сервисный слой является частью Model
    • Сервисный слой работает с Model, то есть с моделями предметной области (вашим доменом)
    • Контроллер при этому теряет связь с моделью и доменом, общаясь через соответствующие сервисы
  • Фасад – это паттерн ☺

Пример сервиса:

public interface IMovieService
{
    MovieDto GetMovie(int id);
    IEnumerable<MovieDto> GetAllMovies();
    MovieDto UpdateMovie(MovieDto movieDto);
    MovieDto AddMovie(MovieDto movieDto);
    MovieDto DeleteMovie(int id);
}

42. DTO.

  • Сервисный уровень возвращает и получает DTO
    • По сути всю логику с доменом сервисы инкапсулируют, тем самым слой контроллеров и выше становится независимым от модели
    • Модель может меняться, при этом DTO не затрагивается
    • DTO и ViewModel близкие понятия, но ViewModel привязаны к интерфейсам графическим, а DTO абстрактные данные с привязкой к логике данных

43. DI контейнер, сервис и контроллер.

По факту требуется указать, как это реализуется, ниже реализация из презентаций

public class MovieService:IMovieService
{
    private readonly MoviesContext _context;
    private readonly IMapper _mapper;
    public MovieService(MoviesContext context, IMapper mapper)
    {
        _context = context;
        _mapper = mapper;
    }
    //All methods…
}
public class MoviesApiController : ControllerBase
{
    private readonly IMovieService _service;
    public MoviesApiController(IMovieService service)
    {
        _service = service;
    }
    [HttpGet] // GET: /api/movies
    [ProducesResponseType(200, Type = typeof(IEnumerable<MovieDto>))]
    [ProducesResponseType(404)]
    public ActionResult<IEnumerable<MovieDto>> GetMovies()
    {
        return Ok(_service.GetAllMovies());
    }
    //Other actions
}
public void ConfigureServices(IServiceCollection services)
{
    //other code
    services.AddScoped<IMovieService, MovieService>();
}

44. Cross-Site Request Forgery.

Cross-Site Request Forgery (CSRF / XSRF) – одна из видов атак через HTTP протокол

Выполнение запросов за пользователя

Используя украденный cookies, хранящийся в браузере

Защита от таких атак обязательна!

AutoValidateAntiforgeryToken

При использовании tag helper <form> в ASP.NET Core,

  • автоматически добавляется в форму специальное скрытое поле со случайным значением, называемым токеном защиты от подделки (anti-forgery token)
  • Проверяйте наличие данного токена в POST методах:
    [AutoValidateAntiforgeryToken]
    public IActionResult SendMoney() {}
  • Глобально в контроллерах или приложениях
    [AutoValidateAntiforgeryToken]
    public class ManageController : Controller
    services.AddMvc(options => options.Filters.Add(new AutoValidateAntiForgeryTokenAttribute()))

45. Аутентификация и Авторизация. Концепция и разница.

  • Аутентификация
    • Процесс проверки личности пользователя или компьютера
    • Вопрос: Кто вы? Как вы это докажете?
    • Учетные данные могут быть паролями, смарт-картами, токенами и т. д.
  • Авторизация
    • Процесс определения того, что пользователю разрешено делать
    • Вопрос: Что вам разрешено делать? Вы можете увидить эту страницу?

46. ASP.NET Identity – основные компоненты для реализации собственной авторизации.

ASP.NET Identity - Фреймворк в ASP.NET для реализации аутентификации иавторизации

  • Поддерживается ASP.NET MVC, Pages, Web API (с помощью токенов)
  • Управляет Users, User Profiles, Login / Logout, Roles
  • Поддержка внешних провайдеров аутентификации и авторизации
  • Facebook, Google, Twitter и т. д.

Используем пакет Microsoft.AspNetCore.Identity.EntityFrameworkCore 3.1.10

Реализация:

  • ApplicationUser - модель пользовательских данных
    public class ApplicationUser : IdentityUser
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  • Обновляем контекст - Наследуем IdentityDbContext
    public class MoviesContext: IdentityDbContext<ApplicationUser>
    {
        //...
    }
  • Добавляем Identity для контекста в ConfigureServices
services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<MoviesContext>();
  • Создаем миграцию и обновляем базу данных!

    dotnet ef migration add %Migration_Name%
    dotnet ef database update
  • Добавляем Middleware

    app.UseAuthentication();
    app.UseAuthorization();
  • Добавляем в Seed пользователя и роль

    if (!roleManager.RoleExistsAsync("Admin").Result)
    {
        roleManager.CreateAsync(new IdentityRole { Name = "Admin" }).Wait();
    }
    if (userManager.FindByEmailAsync("admin@example.com").Result == null)
    {
        var user = new ApplicationUser { 
            UserName = "admin@example.com", 
            Email = "admin@example.com", 
            FirstName = "Super", 
            LastName = "Admin" 
        };
        IdentityResult result = userManager.CreateAsync(user, "P@ssw0rd").Result;
        if (result.Succeeded)
        {
            userManager.AddToRoleAsync(user, "Admin").Wait();
        }
    }
  • Добавляем основной код

    • Контроллеры
      • AccountController
      • ManageController
    • Помечаем методы/контроллеры, к которым нужен авторизованный доступ
      • К примеру - [Authorize(Roles = "Admin")]
    • Создаем страницы и ViewModels для авторизации, управления аккаунтом
  • Настройки для пароля можно указать в ConfigureServices:

services.AddIdentity<ApplicationUser, IdentityRole>(options => {
    options.Password.RequireNonAlphanumeric = false;
}).AddEntityFrameworkStores<MoviesContext>();

Используйте следующие атрибуты:

  • [Authorize] – доступ только авторизованным пользователям
  • [Authorize(Roles = "Admin")] – доступ только авторизованным пользователям с ролью «Admin»
  • [AllowAnonymous] – доступ без ограничений

Интерфейс доступа к данным (репозиториям) – пользователям и ролям

  • AddClaimsAsync(…)
  • FindByEmailAsync(…)
  • GenerateChangeEmailTokenAsync(…)
  • AddToRoleAsync(…)
  • FindByIdAsync(…)
  • GenerateEmailConfirmationTokenAsync(…)
  • IsInRoleAsync(…)
  • FindByNameAsync(…)
  • GeneratePasswordResetTokenAsync(…)
  • GetUserId(…)
  • GetClaimsAsync(…)
  • GetAuthenticationTokenAsync(…)
  • ConfirmEmailAsync(…)
  • GetEmailAsync(…)
  • IsEmailConfirmedAsync(…)
  • ChangeEmailAsync(…)
  • GetRolesAsync(…)
  • CreateSecurityTokenAsync(…)
  • CreateAsync(…)
  • GetUserAsync(…)
  • ResetPasswordAsync(…)
  • DeleteAsync(…)
  • CheckPasswordAsync(…)
  • RemoveFromRoleAsync(…)
  • Dispose(…)
  • UpdateAsync(…)
  • RemoveClaimsAsync(…)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment