ASP.NET Core Flashcards
Классы WebApplication и WebApplicationBuilder
WebApplicationBuilder - создает объект приложения WebApplication, настраивая конфигурации, добавляя сервисы в DI-контейнер, настраивая логирование, окружение, конфигурацию хоста IHostBuilder.
Для управления хостом WebApplication определяет следующие методы:
- Run/RunAsync
- Start/StartAsync
- StopAsync
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet(“/”, () => “Hello World!”);
app.Run();
Паттерн MVC
Паттерн MVC - разделение приложения на три компонента:
1) Модель (описывает используемые в приложении данные, логику валидации данных):
1.1) Модель представлений (используется представлениями для отображения, не все свойства нужны представлению)
1.2) Модель домена (описывает логику управления данными )
2) Представление (отвечает за визуальную часть или пользовательский интерфейс)
3) Контроллер (центральный компонент MVC, который обеспечивает связь между пользователем и приложением, представлением и хранилищем данных, содержит логику обработки запроса пользователя)
Модель является независимым компонентом.
Благодаря разделению ответственности приложение легче разрабатывать, поддерживать и тестировать отдельные компоненты.
Функциональность MVC можно добавлять разными способами:
- AddMvc() - добавляет все сервисы фреймворка MVC (в том числе сервисы для работы с аутентификацией и авторизацией, валидацией и т.д.)
- AddMvcCore() - добавляет только основные сервисы фреймворка MVC
- AddControllersWithViews() - добавляет только те сервисы фреймворка MVC, которые позволяют использовать контроллеры и представления и связанную функциональность
- AddControllers() -позволяет использовать контроллеры, но без представлений
Мастер-страница Layout.cshtml
Мастер-страницы применяются для создания единообразного, унифицированного вида сайта.
Layout.cshtml - обычное представление, в которое включает в себя другие отдельные представления (определяет общее для всех веб-страниц):
- метод RenderBody() подставляет вместо себя конкретное представление
Конвейер обработки запроса и middleware
Обработка запроса в ASP.NET Core устроена по принципу конвейера по всем встроенным в конвейер компонентам (middleware).
Компонент middleware может либо передать запрос далее следующему в конвейере компоненту, либо выполнить обработку (как до, так и после следующего) и закончить работу конвейера.
Компоненты middleware встраиваются с помощью методов расширений:
- Run (такие компоненты обработку запроса дальше не передают)
- Map (применяется для сопоставления пути запроса с определенным делегатом, который будет обрабатывать запрос по этому пути)
- Use (такие компоненты передают запрос следующим)
Порядок подключения middleware имеет значение.
Способы маршрутизации
Способы маршрутизации в MVC:
- с помощью Endpoints (новый способ)
- с помощью RouterMiddleware (старый способ)
Маршрутизация MVC с помощью Endpoints
Достигается с помощью компонентов:
- EndpointRoutingMiddleware (UseRouting)
- EndpointMiddleware (UseEndpoints)
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// определение маршрутов
endpoints.MapControllerRoute(
name: “default”,
pattern: “{controller=Home}/{action=Index}/{id?}”);
});
параметр pattern
определяет шаблон маршрута, с которым будут сопоставляться входящие запросы.
Маршрутизация MVC с помощью RouterMiddleware и метода UseMvc
// добавление компонентов mvc и определение маршрута
app.UseMvc(routes =>
{
routes.MapRoute(“api”, “api/get”, new { controller = “Home”, action = “About” });
routes.MapRoute(
name: “default”,
template: “{controller=Home}/{action=Index}/{id?}”);
});
Маршрутизация MVC на основе атрибутов
- Маршруты, определенные с помощью атрибутов, имеют
высший приоритет. - Может применяться при новом и старом способе маршрутизации
- Атрибут маршрута можно установить глобально для всего контроллера
- для одного действия можно задать несколько маршрутов[Route(“Home/Index”)]
public IActionResult Index()
{
return Content(“ASP.NET Core на metanit.com”);
} - Можно применять ограничения маршрута:
[Route(“{id:int}/{name:maxlength(10)}”)]
public IActionResult Test(int id, string name)
{
return Content($” id={id} | name={name}”);
}
Области в системе маршрутизации
Область - представляет сегмент приложения, имеет свою собственную структуру каталогов.
Атрибут Area - позволяет ассоциировать контроллер с областью
[Area("Store")] public class HomeController : Controller { public IActionResult Index() { return View(); } }
Метод MapAreaControllerRoute - указать маршрут для области
Маршрутизация ASP.NET
- на основе Endpoints:
app.Map(“/”, () => “Index Page”);
//Маршрут с параметрами
app.Map(“/users/{id}”, (string id) => $”User Id: {id}”);
//Маршрут с параметром сложного типа данных
app.MapGet(“/user”, ([AsParameters] Person person) => $”Name: {person.Name} Age: {person.Age}”);
- Если обработчик запроса конечной точки возвращает в ответ объект класса, то по умолчанию подобные объекты при отправке сериализуются в JSON.
- Маршрут с параметрами:
app.Map(“/users/{id}”, (string id) => $”User Id: {id}”);
Настройка ASP.NET Core для работы с прокси
Исходная схема HTTPS-запроса и исходный ip-адрес теряется при его передаче через прокси-сервер, поэтому их нужно доп. передать в заголовке.
Прокси-серверы передают данные в заголовках HTTP:
- X-Forwarded-For (Содержит сведения о клиенте, который создал этот запрос, и обо всех предыдущих узлах в цепочке прокси-серверов)
- X-Forwarded-Proto (Значение исходной схемы передачи данных (HTTP или HTTPS) или список схем в цепочке)
- X-Forwarded-Host (Исходное значение поля Host в заголовке запроса)
- X-Forwarded-Prefix (Исходный базовый путь, запрошенный клиентом)
Чтобы получить заголовки от прокси-сервера, нужно добавить мидлварь ForwardedHeadersMiddleware (UseForwardedHeaders), которая считывает эти заголовки и заполняет ими поля HttpContext.
//установка опций для ForwardedHeadersMiddleware
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});</ForwardedHeadersOptions>
app.UseForwardedHeaders();
Отличия ASP.NET и ASP.NET Core
ASP.NET - платформа разработки веб-приложений для Windows, в состав котор. входят веб-сервисы.
ASP.NET Core:
- кроссплатформенный opensource-фреймворк
- встроенная поддержка DI
- модульная структура (можно подключать только нужные модули)
- Унифицированные контроллеры MVC и Web API
Авторизация по ролям
Авторизация по ролям позволяет разграничить доступ к ресурсам приложения в зависимости от роли.
[Authorize(Roles = “admin”)]
Чтобы использовать атрибут Authorize, нужно встроить в конвейер AuthorizationMiddleware (UseAuthorization) и подключить сервисы авторизации (AddAuthorization).
Аутентификация и авторизация
Аутентификация - процесс определения пользователя.
Авторизация - процесс определения, имеет ли пользователь право доступа к некоторому ресурсу.
Для встраивания в аутентификации в конвейер нужна AuthenticationMiddleware (UseAuthentication), которая использует сервисы аутентификации (регистрируются с помощью AddAuthentication)
Схемы аутентификации
Схема аутентификации позволяет выбрать определенный обработчик аутентификации.
Распространенные схемы аутентификации:
- “Cookies”:
- JWT “Bearer”
builder.Services.AddAuthentication(“Bearer”).AddJwtBearer();
builder.Services.AddAuthentication(“Cookies”).AddCookie();
Конфигурация
Конфигурация (IConfiguration, IConfigurationRoot (наследник)) - определяет базовые настройки приложения, может получать настройки из источников:
- args
- переменных среды
- из памяти
- из файла
- из кастомных источников
Конфигурация в файлах JSON, XML и Ini
builder.Configuration.AddJsonFile(“config.json”);
builder.Configuration.AddXmlFile(“config.xml”);
builder.Configuration.AddIniFile(“config.ini”);
Конфигурация из памяти
builder.Configuration.AddInMemoryCollection(new Dictionary<string, string>
{
{“name”, “Tom”},
{“age”, “37”}
});
Конфигурация из переменных среды
//в ASP.NET Core уже используется по умолчанию
builder.Configuration.AddEnvironmentVariables();
Конфигурация из аргументов командной строки (launchSettings.json)
используется по умолчанию
ASP.NET Кэширование MemoryCache
MemoryCache - позволяет сохранять данные в кэше в памяти.
//Регистрация сервиса IMemoryCache
builder.Services.AddMemoryCache();
- Использование через внедрение зависимостей:
cache.TryGetValue(id, out User? user);
cache.Set(user.Id, user, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(5)));
Распределенное кэширование c Redis
- Нужен сервер Redis
- Нужен пакет Microsoft.Extensions.Caching.StackExchangeRedis
//Добавление сервиса IDistributedCache
builder.Services.AddStackExchangeRedisCache(options => {
options.Configuration = “localhost”;
options.InstanceName = “local”;
});
//использование
var userString = await cache.GetStringAsync(id.ToString());
await cache.SetStringAsync(user.Id.ToString(), userString, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(2)
});
ASP.NET Identity
ASP.NET Identity - встроенный провайдер проверки подлинности, позволяет пользователям создавать учетные записи (хранит их в БД), аутентифицироваться, использовать для входа учетные записи внешних провайдеров (Facebook, Google, Microsoft).
- Настройка сервисов Identity:
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();</ApplicationDbContext></IdentityUser>
builder.Services.Configure<IdentityOptions>(options =>
{
// Password settings
// Lockout settings
// User settings
});</IdentityOptions>
//подключение middleware
app.UseAuthentication();
app.UseAuthorization();
- Для регистрации/логина используется SignInManager
- Для управление ролями используется RoleManager и UserManager
MVC HTML-хелперы
HTML-хелперы - вспомогательные методы для генерации html-разметки.
Пример:
//метод расширения для IHtmlHelper
public static HtmlString CreateList(this IHtmlHelper html, string[] items)
{
string result = “<ul>”;
foreach (string item in items)
{
result = $”{result}<li>{item}</li>”;
}
result = $”{result}</ul>”;
return new HtmlString(result);
}
//использование:
<div>
@Html.CreateList(cities)
</div>
MVC TagBuilder
TagBuilder - класс для создания html-тегов, может исп. для HTML-хелперов
Шаблонные HTML-хелперы
Шаблонные HTML-хелперы - смотрят на свойство модели и генерируют наиболее подходящий html-элемент:
- Display/DisplayFor
- Editor/EditorFor
- DisplayText/DisplayTextFor
- DisplayForModel (Создает поля для чтения для всех свойств модели)
- EditorForModel (Создает поля для редактирования для всех свойств модели)
- DisplayTextForModel
MVC Tag-хелперы
Tag-хелперы - для создания пользовательских тегов для многократного использования и выноса сложной логики построения сложного элемента в отдельный класс.
Пример:
//использование <timer></timer>
public class TimerTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = “div”; // заменяет тег <timer> тегом <div>
// устанавливаем содержимое элемента
output.Content.SetContent($"Текущее время:{DateTime.Now.ToString("HH:mm:ss")}");
}
}</timer>
MVC View Component
View Component - код, который объединяет логику на языке C# и связанную с ней разметку razor (частичное представление), не может обрабатывать HTTP-запросы, а генерируемый им контент включается в код родительского представления, в котором вызывается компонент, поддерживает внедрение зависимостей.
Способы определения View Component:
- как обычный класс (POCO)
- наследование от базового класса ViewComponent
- применение к классу атрибута [ViewComponent]
public class Timer : ViewComponent { public string Invoke() { return $"Текущее время: {DateTime.Now.ToString("hh:mm:ss")}"; } }
//использование компонента в коде .cshtml
@await Component.InvokeAsync(“Timer”)
//или так
@addTagHelper *, [Название_сборки_проекта]
<vc:[имя_компонента]></vc:[имя_компонента]>
MVC Контроллеры
Контроллер - класс, публичные методы которого являются действиями и к ним можно обратиться “адрес_сайта/Имя_контроллера/Действие_контроллера”, благодаря системе маршрутизации:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: “default”,
pattern: “{controller=Home}/{action=Index}/{id?}”);
});
Передача данных в контроллер
- При отправке GET-запроса значения передаются через строку запроса:
- Простые параметры:Home/Square?a=10&h=3
- Передача массива:Home/Sum?nums=1&nums=2&nums=3
- Передача сложных объектов: Параметры строки запроса должны соответствовать по имени свойствам объекта
Результаты действий контроллера
Результаты действий контроллера:
- string
- void
- экземпляр пользовательского класса
- IActionResult (ContentResult, EmptyResult, FileResult, ObjectResult, UnauthorizedResult, NotFoundResult, BadRequestResult, OkResult, ViewComponentResult, ViewResult, JsonResult) - эти объекты создаются соответствующими методами (Json(user) return JsonResult
)
MVC Переадресация
- для создания переадресации используются классыRedirectResult,LocalRedirectResult,RedirectToActionResultиRedirectToRouteResult.
Протокол HTTP поддерживает два типа переадресации:
- постоянная (301): RedirectPermanent(“~/Home/About”)
- временная (302): Redirect(“~/Home/About”)
Контекст контроллера HttpContext
HttpContext - содержит контекст запроса и все его данные:
- HttpRequest: Body, Cookies, Form, Headers, Query
- HttpResponse: Body, Cookies, ContentType, Headers, StatusCode
- User (представляет текущего пользователя, который обращается к приложению)
- Session (объект для работы с сессиями)
MVC Модель
Модель - должна описывать только одну сущность.
Виды моделей:
- Модель представления (используются для передачи данных в представление и наоборот) - содержит только необходимые для представления свойства
- Модели (как DTO, связь с БД) - содержит все свойства
Модель представления
//Модель представления
public class IndexViewModel
{
public IEnumerable<Phone> Phones { get; set; }
public IEnumerable<CompanyModel> Companies { get; set; }
}</CompanyModel></Phone>
//Использование
@model IndexViewModel
@foreach (Phone p in Model.Phones){…}
Привязка модели IModelBinder
Привязка модели (IModelBinder) - механизм сопоставления значений из HTTP-запроса с параметрами метода контроллера, которые могут иметь простой или сложный тип.
Приоритет поиска (его можно изменить атрибутами [FromHeader], [FromBody]):
- Данные форм
- Данные маршрута
- Данные строки запроса
Управление привязкой:
- Атрибут[BindRequired]
(требует обязательного наличия значения для свойства модели)
- Атрибут[BindNever]
(указывает, что свойство модели надо исключить из механизма привязки)
Можно создать кастомный привязчик модели для некоторых типов (например чтоб для даты указать kind=UTC):
- нужно реализовать метод BindModelAsync интерфейса IModelBinder
- нужно создать провайдер для этого привязчика, реализовать GetBinder интерфейса IModelBinderProvider
- добавить свой провайдер в список провайдеров привязчиков вверху коллекции (чтобы он переопределил дефолтный):
services.AddControllersWithViews(opts =>
{
opts.ModelBinderProviders.Insert(0, new CustomDateTimeModelBinderProvider());
});
MVC Представление и движок Razor
Представление (Razor View) - это файл .cshtml, который содержит код на html и конструкции Razor (C#), во время выполнения представления компилируются в html-страницы.
Razor - движок представлений, который позволяет встраивать C#-код в html-код.
В контроллере вернуть представление в виде ответа можно с помощью метода View(), который возвращает объект ViewResult, можно указать явно имя представления, либо оно будет сопоставлено с именем контроллера.
- View()
: для генерации ответа используется представление, которое по имени совпадает с вызывающим методом
- View(string viewName)
: в метод передается имя представления, что позволяет переопределить используемое по умолчанию представление
- View(object model)
: передает в представление данные в виде объекта model
- View(string viewName, object model)
: переопределяет имя представления и передает в него данные в виде объекта model
Синтаксис Razor:
@{
Layout = null;
}
@{
string[] phones = { “Lumia 950”, “iPhone 6S”, “Galaxy S 6”, “LG G4” };
}
<ul>
@foreach (var phone in phones)
{
<li>@phone</li>
}
</ul>
Передача данных в представление
Cпособы передачи данных из контроллера в представление:
1) View(data)
2) ViewData (словарь из пар ключ-значение, в качестве значения может выступать любой объект)
3) ViewBag (подобен ViewData, позволяет передать объекты сложного типа)
Секции в представлениях
RenderSection() - для вставки секций.
Пример:
//false - означает, что секция необязательная
<footer>@RenderSection("Footer", false)</footer>
//использование
@section Footer {
Все права защищены. Site Corp. 2016.
}
Файл _ViewImports.cshtml
_ViewImports.cshtml - содержит общие импорты для всех представлений (директивами Razor).
Частичные представления
Частичные представления - представления, которые можно встраивать в обычные представления (в основном применяются для рендеринга результатов ajax-запросов, а также для создания панелей меню, блоков входа на сайт).
Рендеринг частичных представлений:
public ActionResult GetMessage()
{
return PartialView(“_GetMessage”);
}
Встраивание частичного представления:
@await Html.PartialAsync(“_GetMessage”)
Внедрение зависимостей в представления
@inject HelloMvcApp.Services.ITimeService Timer
//использование Timer
<h2>Текущее время: @Timer.GetTime()</h2>
ASP.NET Core SignalR
SignalR - библиотека от Microsoft предназначена для создания приложений, работающих в режиме реального времени, использует двунаправленную связь для обмена сообщениями (чат, соц. сети)
Механизмы клиент-серверного обмена в SignalR:
- WebSockets (оптимальный)
- Server-Side Events (SSE)
- Long Polling
Исходя из возможностей клиента и сервера инфраструктура SignalR выбирает наилучший механизм для взаимодействия.
В качестве клиента в SignalR может выступать:
- приложение Javascript, запущенное на node.js
- приложение javascript, запущенное в браузере
- приложение .NET
- приложение Java
Серверная часть SignalR
Серверная часть SignalR:
- нужно реализовать Hub:
public class ChatHub : Hub
{
public async Task Send(string message)
{
await this.Clients.All.SendAsync(“Send”, message);
}
}
- добавить ChatHub в систему маршрутизации:
app.UseEndpoints(endpoints =>
{
//устанавливает класс ChatHub в качестве обработчика запросов по пути “/chat”
endpoints.MapHub<ChatHub>("/chat");
});</ChatHub>
Хабы можно использовать в контроллере:
[HttpPost]
public async Task<IActionResult> Create(string product)
{
await hubContext.Clients.All.SendAsync("Notify", $"Добавлено: {product} - {DateTime.Now.ToShortTimeString()}");
return RedirectToAction("Index");
}</IActionResult>
Клиентская часть SignalR на JavaScript
- Нужно подключить библиотеку signalr:
- на странице html:
//Колбек, который вызывается когда метод Send выполнится и вернет значение
const hubConnection = new signalR.HubConnectionBuilder()
.withUrl("/chat")
.build();
hubConnection.on(“Send”, function (data) {let elem = document.createElement("p"); elem.appendChild(document.createTextNode(data)); let firstElem = document.getElementById("chatroom").firstChild; document.getElementById("chatroom").insertBefore(elem, firstElem); }); //Обработчик кнопки sendBtn, при нажатие вызывается метод Send document.getElementById("sendBtn").addEventListener("click", function (e) { let message = document.getElementById("message").value; hubConnection.invoke("Send", message); }); hubConnection.start(); </script>
Группы в SignalR
Группы в SignalR - коллекция подключений, которые ассоциированы с именем группы, можно добавлять/удалять клиентов из группы (клиент может входить в несколько групп).
- Рассылка только тем клиентам, которые находятся в группе:
public async Task Send(string message, string username)
{
await Clients.Group(groupname).SendAsync(“Receive”, message, username);
}
Web API
Web API - не имеет представлений, но может иметь контроллеры, либо определять конечные точки прямо в Startup.
В Web API взаимодействие между сервером и клиентом через ajax-запросы.
services.AddControllers();
app.UseEndpoints(endpoints =>
{
// подключаем маршрутизацию на контроллеры
endpoints.MapControllers();
});
Валидация входных данных
- Валидация на стороне сервера:
ModelState.IsValid - Валидация на стороне клиента:
jquery.validate.min.js
<span></span>
Атрибуты валидации:
[Required]
[Required (ErrorMessage = “Не указан электронный адрес”)]
Можно создать кастомный атрибут валидации с помощью реализации метода IsValid класса ValidationAttribute
Локализация ASP.NET
Для работы с локализацией нужно подключить middleware RequestLocalizationMiddleware:
app.UseRequestLocalization(new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture("ru-RU"), SupportedCultures = supportedCultures, SupportedUICultures = supportedCultures });
- Значения брать из файлов ресурсов
ASP.NET Фильтры
Фильтры - позволяют выполнять некоторые действия до или после определенной стадии обработки запроса, т.е. встраивать в конвейер.
Типы фильтров:
- Фильтры авторизации (есть встроенная реализация (атрибут [Authorize]))
- Фильтры аутентификации (нет встроенной реализации IAuthenticationFilter)
- Фильтры ресурсов (есть встроенная реализация)
- Фильтры действий (есть встроенная реализация ActionFilterAttribute)
- Фильтры исключений (есть встроенная реализация HandleErrorAttribute)
- Фильтры RazorPages
Можно создать кастомный фильтр:
public class SimpleResourceFilter : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
context.HttpContext.Response.Cookies.Append(“LastVisit”, DateTime.Now.ToString(“dd/MM/yyyy hh-mm-ss”));
}
public void OnResourceExecuted(ResourceExecutedContext context) { // реализация отсутствует } } //Встраивание фильтра services.AddMvc(options => { options.Filters.Add(typeof(SimpleResourceFilter)); });
Чтобы выйти из конвейера фильтров, нужно установить свойствоResult
переданного в фильтр контекста
CORS (Cross Origin Resource Sharing)
CORS - выполнять запросы из приложения с одного адреса (или домена) к приложению, которое размещено по другому адресу.
Добавление CORS:
builder.Services.AddCors(); // добавляем сервисы CORS
// Глобальная настройка CORS
app.UseCors(builder => builder.AllowAnyOrigin());
//локальная настройка CORS (для конечных точек)
app.UseCors();
app.MapGet(“/”, async context => await context.Response.WriteAsync(“Hello World!”))
.RequireCors(options => options.AllowAnyOrigin());
Политики CORS
Политики CORS - набор правил взаимодействия сервера и клиент, применяются для упрощения комплексной конфигурации сервиса CORS.
Создание политики CORS:
builder.Services.AddCors(options => options.AddPolicy(“AllowLocalhost7027”, builder => builder
.WithOrigins(“https://localhost:7027”)
.AllowAnyHeader()
.AllowAnyMethod())
);
//Применение созданной политики AllowLocalhost7027
app.UseCors(“AllowLocalhost7027”);
ASP FluentValidation
FluentValidation - .NET библиотека дляописания правил валидации моделей ввиде текучего синтаксиса, и последующего их применения.
Пример:
public class BalanceItemValidator: AbstractValidator<BalanceItem>
{
public BalanceItemValidator()
{
RuleFor(item => item.Name).NotNull().NotEmpty().WithMessage("Please specify name");
RuleFor(item => item.StartDate).NotNull().NotEmpty();
RuleFor(item => item.Sum).NotNull().NotEmpty();
RuleFor(item => item.YearPersent).NotNull().NotEmpty();
}
}</BalanceItem>
ASP.NET Identity с OAuth 2.0
ASP.NET Identity с OAuth 2.0 - использует проверку подлинности внешних поставщиков (Facebook, Twitter, Google), которые назначают секреты клиента вашему приложению в процессе регистрации вашего приложения на платформе.
Эти секреты нужны, чтобы сервис Google доверял вашему приложению. Когда пользователь будет заходить в ваше приложение, приложение будет отправлять авторизационный запрос на внешний сервис и от него получать токен доступа к защищенным данным вашего приложения. При этом вашему приложению не нужно хранить учетные данные пользователя.
//Добавление сервиса аутентификации Google
builder.Services.AddAuthentication()
.AddGoogle(options =>
{
IConfigurationSection googleAuthNSection =
config.GetSection(“Authentication:Google”);
options.ClientId = googleAuthNSection[“ClientId”];
options.ClientSecret = googleAuthNSection[“ClientSecret”];
});
OAuth 2.0 - протокол авторизации (без аутентификации, аутентификация проходит на внешнем сервисе)
URL Rewriting
URL Rewriting - позволяет решить такие стандартные проблемы, как перенаправление с домена с www на домен без www и наоборот или перенаправление с протокола http на https.
URL Rewriting реализуется до того, как запрос попадет в систему маршрутизации, и начнется его непосредственное выполнение в конвейере.
//Пример:
//Если запрошенный адрес заканчивается на “.php”, то выполняем ряд преобразований, получая путь к html
var options = new RewriteOptions().Add(RewritePHPRequests);
app.UseRewriter(options);
//Реализация IRule
public class RedirectPHPRequests : IRule
{
private readonly string _extension;
private readonly PathString _newPath;
public RedirectPHPRequests(string extension, string newPath) { if (string.IsNullOrEmpty(extension)) { throw new ArgumentException(nameof(extension)); } if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?")) { throw new ArgumentException("Запрошенный путь недействителен", nameof(newPath)); } _extension = extension; _newPath = new PathString(newPath); } public void ApplyRule(RewriteContext context) { var request = context.HttpContext.Request; var pathValue = request.Path.Value; // запрошенный путь if (request.Path.StartsWithSegments(new PathString(_newPath))) return; if (pathValue != null && pathValue.EndsWith(".php", StringComparison.OrdinalIgnoreCase)) { var response = context.HttpContext.Response; response.StatusCode = StatusCodes.Status301MovedPermanently; context.Result = RuleResult.EndResponse; response.Headers[HeaderNames.Location] = _newPath + pathValue.Substring(0, pathValue.Length - 3) + _extension; } } }
ASP.NET Blazor
Blazor - UI-фреймворк для создания интерактивных приложений (исп. SignalR), которые могут работать как на стороне сервера, так и на стороне клиента, на платформе .NET, используя html + C# (вместо Javascript):
- Клиентская и серверная части приложения могут использовать общую логику на C#
Подсистемы Blazor:
1) Blazor Server (приложения отрабатывает на стороне сервера и отправляют клиенту обновленные страницы html)
2) Blazor WebAssembly (приложение работает на стороне клиента)
3) Blazor Server + Blazor WebAssembly
4) Blazor Hybrid (поверх .NET MAUI)
Компонент (.razor) - ключевой элемент Blazor, представляет элемент интерфейса, исп. синтаксис Razor:
- определяют логику рендеринга элементов интерфейса, а также логику обработки пользовательского ввода
- могут быть вложенными
- можно повторно использовать
Типы компонентов:
- Корневой компонент (App.razor - определяет каркас веб-страницы, а ост. компоненты расположены в нем)
- Компонент Routes (определяет конкретный компонент на основе маршрута, исп. встроенный компонент Router)
- Компоненты структуры:
- MainLayout (свойством @Body
рендерится выбранный для обработки запроса компонент)
- NavMenu
- Пользовательские компоненты
//Подключение Blazor
builder.Services.AddRazorComponents() //сервис для рендеринга компонентов не сервере
.AddInteractiveServerComponents(); //сервис для интерактивный рендеринга компонентов не сервере
app.MapRazorComponents<App>() //определим корневой компонент приложения (App.razor)
.AddInteractiveServerRenderMode(); //настраиваем режим интерактивного рендеринга на стороне сервера
app.UseAntiforgery();//установка middleware для защиты от поддельных данных (нужно для компонентов Blazor)</App>
Пример компонента Blazor:
<body>
<h1>@Message @name</h1>
<h2>@DisplayTime()</h2>
</body>
</html>
@code {
string name = “Eugene”;
string DisplayTime()
{
return $”Current time: {DateTime.Now.ToString(“HH:mm:ss”)}”;
}
string Message { get; } = “Hello”;
}
Blazor Обработка запросов
Режим интерактивного рендеринга (нажатия на кнопки работают) на сервере:
- Сервер обрабатывает полученную информацию
- Blazor вычисляет минимально необходимое количество изменений, чтобы привести интерфейс веб-страницы в соответствии с изменившимся состоянием компонента
- отправляет информацию об этих изменениях обратно клиенту через SignalR
- на клиенте будут изменяться только те части страницы, которые и должны быть изменены, перезагрузки страницы не будет
Режим рендеринга на клиенте:
- все действия будут выполняться и обрабатываться в браузере без участия сервера
Blazor Маршрутизация
Чтобы компонент мог участвовать в маршрутизации, в его коде должна быть определена директива@page, после которой идет обрабатываемый маршрут:
@page “/about”
Параметры маршрута с помощью атрибута [Parameter]:
@page “/user/{name}/{age:int}”
@code {
[Parameter]
public string Name { get; set; } = “”;
[Parameter] public int Age { get; set; } }
Чтобы получить параметры строки запроса в компоненте, применяется атрибут [SupplyParameterFromQuery]
вместе с атрибутом [Parameter]
:
@code {
[Parameter]
[SupplyParameterFromQuery]
public string? Name { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public int? Age { get; set; }
}
Мониторинг работоспособности приложения
- спец. компонент HealthChecksMiddleware
//подключение
builder.Services.AddHealthChecks();
//установка конечной точки
app.UseHealthChecks(“/health”);
app.MapHealthChecks(“/health”);
ASP.NET Обработка исключений
DeveloperExceptionPageMiddleware - middleware Для обработки исключений в приложении в стадии разработки (в проде клиенты не увидят подробных ошибок, а только статус код).
ExceptionHandlerMiddleware (UseExceptionHandler()) - middleware для отображения информации об ошибках:
// middleware, которое обрабатывает исключение app.UseExceptionHandler(app => app.Run(async context => { context.Response.StatusCode = 500; await context.Response.WriteAsync("Error 500. DivideByZeroException occurred!"); }));
Обработка ошибок HTTP: StatusCodePagesMiddleware - можно добавить в проект отправку информации о статусном коде
ASP.NET Политики доступа
Политики доступа добавляются к опциям при добавлении сервиса AddAuthorization
builder.Services.AddAuthorization(opts => {
//добавление политики OnlyForMicrosoft
opts.AddPolicy(“OnlyForMicrosoft”, policy => {
policy.RequireClaim(“company”, “Microsoft”);
});
});
//Использование политики доступа
app.Map(“/microsoft”, Authorize(Policy = “OnlyForMicrosoft”) => “You are working in Microsoft”);
ASP.NET + EF Core
Для взаимодействия с БД через EF Core:
- нужен контекст данных (наследник DbContext)
- строка подключения к БД
- добавить контекст в качестве сервиса
Пример:
// получаем строку подключения из файла конфигурации
string connection = builder.Configuration.GetConnectionString(“DefaultConnection”);
// добавляем контекст ApplicationContext в качестве сервиса в приложение
builder.Services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(connection));</ApplicationContext>
// получение данных из БД (через внедрение зависимостей)
app.MapGet(“/”, (ApplicationContext db) => db.Users.ToList());
Веб-серверы ASP.NET Core (IIS, Ketrel)
В состав ASP.NET Core входят:
1) Ketrel - кроссплатформенный высокопроизводительный HTTP-сервер с эффективным исп. памяти
2) IIS - HTTP-сервер (Windows), внутрипроцессный сервер для службы IIS
3) HTTP-sys (ранее назывался WebListener) - HTTP-сервер (Windows), основанный на драйвере ядра HTTP-sys, является альтернативой Kestrel (подключение: UseHttpSys).
ASP.NET Core - по умолчанию исп. веб-сервер Kestrel (кроссплатформенный) + IIS в качестве прокси (добавляет поддержку кэширования веб-страниц):
1) входящие запросы проходят через драйвер Http.Sys, который перенаправляет их на IIS на порт 80 или 443
2) IIS перенаправляет запрос приложению ASP.NET Core на определенный порт, на котором запущено приложение (5000, 5002, и др.)
3) Kestrel получает запрос и передает его в виде объекта HttpContext в конвейер ASP.NET Core
Kestrel
Kestrel - кроссплатформенный высокопроизводительный HTTP-сервер:
- используется по умолчанию в ASP.NET Core
- с эффективным исп. памяти
- поддерживает HTTPS
- поддерживает протоколы HTTP/1.1, HTTP/2 и HTTP/3, WebSockets
- простая интеграция с другими компонентами конвейера
- Kestrel можно использовать самостоятельно или с обратным прокси-сервером (IIS, Apache, Nginx)
- обращение нескольких процессов к одним и тем же IP-адресам и портам не поддерживается (обратный прокси-сервер, который может совместно использовать порты, способен пересылать запросы в Kestrel с уникальными IP-адресом и портом) - Когда на хосте есть несколько приложений, использующих один и тот же IP и порт (но разные домены)
- не поддерживает кэширование веб-страниц
//Настройка HTTPS для Kestrel
builder.WebHost.UseKestrel(opt =>
{
var cert = GetCertificate();
opt.ListenAnyIP(5555, listenOptions => { listenOptions.UseHttps(cert); });
});
IIS
Службы IIS - гибкий, безопасный и управляемый веб-сервер для размещения веб-приложений, включая ASP.NET Core с помощью нативного модуля AspNetCoreModule, который принимает запросы и перенаправляет в Kestrel:
- поддерживает кэширование
ASP.NET Состояния, куки, сессии
Способы хранения данных запроса:
1) В состоянии (HttpContext.Items)
2) В Куки (HttpContext.Request.Cookies (для чтения), HttpContext.Response.Cookies (для установки))
3) В Сессии
Сессия - ряд последовательных запросов в одном браузере в течении некоторого времени (~20 мин.):
- может использоваться для сохранения временных данных на сервере создается словарь, а на клиенте в куки устанавливается уникальный ID сессии
//// добавляем сервисы сессии
builder.Services.AddSession();
//добавляем middleware для работы с сессиями
app.UseSession();
//использование
app.Run(async (context) =>
{
if (context.Session.Keys.Contains(“name”))
await context.Response.WriteAsync($”Hello {context.Session.GetString(“name”)}!”);
else
{
context.Session.SetString(“name”, “Tom”);
await context.Response.WriteAsync(“Hello World!”);
}
});
ASP.NET Статические файлы
Статические файлы - файлы в папке wwwroot
(css, js):
- Чтобы клиенты могли получить статические файлы, нужно подключить midlleware: app.UseStaticFiles();
- Чтобы настроить отправку статических веб-страниц без обращения к ним по полному пути, нужно подключить middleware:
DefaultFilesOptions options = new DefaultFilesOptions();
options.DefaultFileNames.Clear(); // удаляем имена файлов по умолчанию
options.DefaultFileNames.Add(“hello.html”); // добавляем новое имя файла
app.UseDefaultFiles(options); // установка параметров
- Чтобы пользователи могли просматривать содержимое каталогов на сайте: app.UseDirectoryBrowser();
- Чтобы подключить все сразу: app.UseFileServer();
ASP.NET Dependency Injection
Dependency injection (внедрение зависимостей) - механизм, который позволяет сделать взаимодействующие в приложении объекты слабосвязанными (через абстракции), для этого используются IoC-контейнеры (Inversion of Control).
ASP.NET Core имеет встроенный IoC-контейнер, который представлен интерфейсом IServiceProvider, который хранит сервисы в коллекции IServiceCollection:
- содержит ряд встроенных сервисов (ILogger, ILoggerFactory, IWebHostEnvironmentя и др.)
- можно добавлять встроенные сервисы (AddMvc(), AddControllers() и др.)
- можно добавлять свои сервисы (AddTransient<IMessageSender, EmailMessageSender>();)
Внедрение зависимостей (сервисов) из IoC-контейнера:
- через конструктор класса
- через параметр метода Invoke компонента middleware
- через свойство Services объекта WebApplicationBuilder (serviceProvider.GetService<MyService>())
- через свойство Services объекта WebApplication (паттерн Service Locator (не рекомендуется)):
app.Services.GetService<ITimeService>();
- через свойство RequestServices контекста запроса HttpContext в компонентах middleware (паттерн Service Locator):
context.RequestServices.GetService<ITimeService>()</ITimeService></ITimeService></MyService>
ASP.NET Регистрация сервиса, реализующего несколько интерфейсов
Пример:
class ValueStorage : IGenerator, IReader {…}
//Независимая регистрация:
//Для каждого интерфейса будет создан свой объект ValueStorage
builder.Services.AddSingleton<IGenerator, ValueStorage>();
builder.Services.AddSingleton<IReader, ValueStorage>();
//Зависимая регистрация:
//будет использоваться только один объект ValueStorage
var valueStorage = new ValueStorage();
builder.Services.AddSingleton<IGenerator>(valueStorage);
builder.Services.AddSingleton<IReader>(valueStorage);</IReader></IGenerator>
ASP.NET Жизненный цикл зависимостей
Типы жизненного цикла зависимостей:
- Transient (при каждом обращении к сервису создается новый объект сервиса. В течение одного запроса может быть несколько обращений к сервису, соответственно при каждом обращении будет создаваться новый объект. Подобная модель жизненного цикла наиболее подходит для легковесных сервисов, которые не хранят данных о состоянии)
- Scoped (для каждого запроса создается свой объект сервиса. Один сервис в рамках запроса)
- Singleton (на всю жизнь приложения. Объект сервиса создается при первом обращении к нему, все последующие запросы используют один и тот же ранее созданный объект сервиса)
Объясните роль файла Startup.cs
Startup.cs в приложении ASP.NET Core служит точкой входа для настройки сервисов и промежуточного ПО, содержит два основных метода:
- ConfigureServices (регистрация сервисов в IServiceCollection)
- Configure (настраивает конвейер запросов приложения, определяя последовательность компонентов промежуточного ПО)
Middleware VS фильтры
- Middleware отвечает за обработку запросов и ответов (работают на уровне запросов,)
- фильтры фокусируются на определенных действиях в контроллерах MVC (работают на уровне слоя MVC, применяются для контроллеров, actions), но могут работать и как Middleware (т.к. HttpContext поле доступно).
назначение IActionResult
IActionResult - служит абстракцией для генерации HTTP-ответов.
Распространенные реализации IActionResult :
- JsonResult: сериализует объект в формат JSON
- ContentResult: возвращает содержимое в виде обычного текста
- FileResult: отправляет двоичное содержимое, такое как изображения или документы
- StatusCodeResult: устанавливает код состояния HTTP
- ViewResult: возвращает представление (веб-страницу)
Отличия Razor Pages и MVC
Razor Pages и MVC — это фреймворки веб-приложений.
Razor Pages:
- логика и представление в одном файле
- нет контроллеров
- поддерживают только методы GET и POST
- встроенная защита от подделок
MVC:
- все наоборот
Какова роль файла appsettings.json
appsettings.json - основной источник параметров конфигурации (нужен пакет Microsoft.Extensions.Configuration)
Логирование в ASP.NET Core
Логирование осуществляется с помощью интерфейса ILogger и класса LoggerFactory.
- Встроенные провайдеры логирования: Console, Debug, EventSource, EventLog, TraceSource, Azure App Service.
Пользовательские Middleware
Способы создания пользовательского Middleware:
1) Реализовать интерфейса IMiddleware (метод InvokeAsync)
2) Использовать делегат RequestDelegate
Добавление в конвейер пользовательских Middleware:
app.UseMiddleware<CustomMiddleware>()</CustomMiddleware>
Пример 1 (IMiddleware):
public class CustomMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// Pre-processing logic here
await next(context);
// Post-processing logic here
}
}
Пример 2 (RequestDelegate):
app.Use(async (context, next) =>
{
z = x * y;
await next.Invoke();
});
app.Run(async (context) => { await context.Response.WriteAsync($"x * y = {z}"); });
Глобальная обработка исключений
Способы глобальной обработки исключений:
1) С помощью пользовательского Middleware (реализовать IMiddleware):
- обернуть вызов next(context)
в try-catch (метод InvokeAsync)
- добавить в конвейер до всех остальных middleware: app.UseMiddleware<CustomMiddleware>()</CustomMiddleware>
2) С помощью пользовательских фильтров:
- нужно реализовать IExceptionFilter или IAsyncExceptionFilter (методы OnException/OnExceptionAsync)
- зарегистрировать фильтр глобально для всех контроллеров:
services.AddControllers(options => options.Filters.Add(new CustomExceptionFilter()))
Публикация и развертывание приложения ASP.NET Core
Способы развертывания:
1) в Docker
2) хостирование в Kestrel
3) хостирование в IIS
Как реализовать серверную пагинацию?
Пагинация - метод разделения большого списка элементов на несколько страниц.
- нужно использовать класс PagedList(пакет PagedList.Mvc)
- реализовать с помощью LINQ (Skip() и Take())
//Пример
public async Task<ActionResult<PagedList<Item>>> GetItems(int pageNumber = 1, int pageSize = 10)
{
var items = await _repository.GetItemsAsync(pageNumber, pageSize);
var totalCount = await _repository.GetTotalItemCountAsync();</Item>
var pagedList = new PagedList<Item> { Items = items, CurrentPage = pageNumber, PageSize = pageSize, TotalCount = totalCount, TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize) }; return Ok(pagedList); }
Пользовательские поставщики конфигурации
Создание пользовательских поставщиков конфигурации:
- реализовать IConfigurationSource (для определения источника данных конфигурации)
- реализовать IConfigurationProvider (для загрузки и анализа данных из источника)
- создать метод расширения для IConfigurationBuilder для добавления вашего пользовательского поставщика
Пример:
https://metanit.com/sharp/aspnet5/2.15.php
что такое ASP.NET Core WebAPI
ASP.NET Core WebAPI - предназначен для для создания RESTful-сервисов
управление версиями в WebAPI
Способы реализации управления версиями:
1) через маршрут (/api/v1/resource
)
2) через строку запроса (?version=1.0
)
3) через заголовок
//Нужен пакет Microsoft.AspNetCore.Mvc.Versioning
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
});
ResponseCache
ResponseCache - это атрибут для кэширования результатов действия контроллеров, предполагает установку в ответе клиенту заголовков кэширования (Cache-Control, Pragma, Vary
), которые определяют, как клиент и прокси-серверы должны кэшировать ответ на своей стороне.
- применяется к контроллерам и к его действиям
[ResponseCache(Location =ResponseCacheLocation.Client, Duration =300)] public IActionResult Index() { return View(); }
Сжатие ответа (компрессия) в ASP.NET Core
Способы компрессии в ASP.NET Core:
1) через прокси
2) middleware (пакет Microsoft.AspNetCore.ResponseCompression):
// добавляем сервис компрессии
services.AddResponseCompression(options=>options.EnableForHttps = true);
// подключаем компрессию
app.UseResponseCompression();
Провайдеры компрессии в ASP.NET Core
Механизм компрессии на уровне протокола HTTP концентрруется вокруг двух заголовков:
- Accept-Encoding (поддерживаемые форматы сжатия клиентом)
- content-encoding (сервер говорит, какой формат он использовал)
Провайдеры компрессии:
1) BrotliCompressionProvider
2) GzipCompressionProvider
3) пользовательские провайдеры (нужно реализовать ICompressionProvider):
public class DeflateCompressionProvider : ICompressionProvider
{
public string EncodingName => “deflate”;
public bool SupportsFlush => true;
public Stream CreateStream(Stream outputStream) { return new DeflateStream(outputStream, CompressionLevel.Optimal); } }
Кэширование статических файлов в ASP.NET Core
Кэширование статических файлов (js, css, файлы изображений):
app.UseStaticFiles(new StaticFileOptions()
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Add(“Cache-Control”, “public,max-age=600”);
}
});
Защита конфиденциальных данных с помощью секретов
- нужен пакет Microsoft.Extensions.Configuration.UserSecrets
- щелкните правой кнопкой мыши проект в Visual Studio и выберите «Управление секретами пользователя», чтобы создать файл secrets.json
if (env.IsDevelopment())
{
builder.AddUserSecrets();
}
else
{
// Add Azure Key Vault integration here
}
Swagger в ASP.NET Core WebAPI
Swagger - инструмент документирования API, упрощает процесс понимания, тестирования и использования API для разработчиков.
- нужен пакет Swashbuckle.AspNetCore
//зарегистрировать генератор Swagger
services.AddSwaggerGen();
//добавить в конвейер конечную точку /swagger
app.UseSwagger();
app.UseSwaggerUI();
Методы оптимизации производительности в приложении ASP.NET Core
Методы оптимизации производительности:
1) использовать кэширование ответов, статических файлов, данные из БД
2) использовать асинхронные запросы
3) сжатие ответов
4) использовать пул объектов в DI-контейнере, чтобы избежать накладных расходов на создание нового объекта
5) использовать пагинацию
Объясните различия между IApplicationBuilder, IHostingEnvironment и IConfiguration в ASP.NET Core
IApplicationBuilder, IHostingEnvironment и IConfiguration — три основных интерфейса в ASP.NET Core:
- IApplicationBuilder ( отвечает за построение конвейера запросов приложения)
- IHostingEnvironment (предоставляет информацию о среде хостинга, такую как путь к корневому каталогу контента, путь к корневому каталогу веб-сайта и имя среды)
- IConfiguration (представляет собой параметры конфигурации приложения)
Automapper
Automapper - позволяет проецировать одну модель на другую (модель домена и модель представления):
- пакет AutoMapper.Extensions.Microsoft.DependencyInjection
- нужно реализовать класс Profile
public class AppMappingProfile : Profile { public AppMappingProfile() { CreateMap<Person, Student>(); } }
//добавление сервиса
services.AddAutoMapper(typeof(AppMappingProfile));
//использование
var person = _mapper.Map<Person>(student);</Person>
//внедрение зависимостей
private readonly IMapper _mapper;
Типы тестирования приложений ASP.NET Core
1) Модульное тестирование (тест контроллеров):
- Moq
- NUnit, xUnit
2) Интеграционное тестирование (тестирование взаимодействия между компонентами и внешними системами (БД)):
- исп. WebApplicationFactory
3) Функциональное тестирование (тестирование сквозных сценариев, имитирующих взаимодействие с пользователем, часто с использованием таких инструментов, как Selenium для автоматизации браузера.)
Мониторинг и aнализ производительности приложения ASP.NET Core в проде
Мониторинг и метрики - обеспечивают видимость того, как работает ваше приложение, помогают в решении проблем отладки и позволяют принимать решения на основе данных для повышения производительности и масштабируемости.
Метрики: частота запросов, время ответа, возникновение исключений, загрузка ЦП, использование памяти.
Для мониторинга и анализа производительности приложения:
1) Подключите логирование (Serilog)
2) HttpMetrics Middleware (подключено по умолчанию в ASP.NET Core): пишет метрики в заголовки
3) Сторонние библиотеки метрик:
- Application Insights (облачный сервис от Microsoft Azure) - нужен аккаунт Azure
- Prometheus
Пример с Application Insights:
builder.Services.AddApplicationInsightsTelemetry();