Платформа .NET
Что такое ASP.NET и чем ASP.NET Core отличается от классического ASP.NET?
ASP.NET — семейство технологий Microsoft для веб-приложений. Классический ASP.NET основан на .NET Framework; ASP.NET Core — отдельная современная кроссплатформенная платформа для .NET. Ниже классические ASMX-примеры относятся к .NET Framework.
Состав ASP.NET:
-
Веб-сервисы:
- Поддержка создания и использования веб-сервисов для обмена данными между приложениями по сети.
-
Программная инфраструктура:
- Набор инструментов и библиотек для разработки, тестирования и развертывания веб-приложений.
-
Модель программирования:
- Обеспечивает удобные средства для написания кода, включая поддержку серверных и клиентских сценариев, а также работу с данными.
Особенности:
-
Интеграция с .NET Framework:
- ASP.NET входит в состав платформы .NET Framework и является развитием более старой технологии Microsoft ASP, предлагая улучшенные возможности и производительность.
ASP.NET предоставляет мощные инструменты и возможности для разработки современных веб-приложений, включая поддержку веб-сервисов, программной инфраструктуры и удобной модели программирования, интегрированной в .NET Framework.
Какие типы фильтров есть в ASP.NET Core MVC?
Типы фильтров действий в ASP.NET Core:
Основные категории фильтров ASP.NET Core MVC:
-
Фильтры авторизации (
Authorization Filter):- Фильтры авторизации проверяют право доступа первыми в конвейере фильтров. Аутентификацию обычно выполняет middleware, а не фильтр действия.
-
Фильтры ресурсов (
Resource Filter):- Фильтры ресурсов выполняются после фильтров авторизации, до привязки модели; их завершающая часть оборачивает оставшийся конвейер, включая выполнение результата.
-
Фильтры действий (
Action Filter):- Выполняются перед и после выполнения метода действия контроллера, позволяют изменять аргументы метода или обрабатывать результаты выполнения.
-
Фильтры результатов (
Result Filter):- Выполняются перед и после выполнения результата действия (например, возврат View или Json), позволяют модифицировать результат.
-
Фильтры исключений (
Exception Filter):- Обрабатывают исключения, возникающие в ходе выполнения действий контроллера, позволяют реализовать глобальную обработку ошибок.
Пример применения фильтров:
public class MyActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Логика перед выполнением действия
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Логика после выполнения действия
}
}
public class MyExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
// Логика обработки исключений
}
}
Фильтры в ASP.NET Core позволяют выполнять дополнительную логику на разных этапах обработки запроса, обеспечивая гибкость и возможность управления процессом выполнения действий и обработки результатов.
Что такое Web Service?
Веб-службы ASP.NET — это тип проектов
веб-приложения, которые обеспечивают бизнес-логику в интернете и используют
логику данных. Они предназначены для взаимодействия с другими веб-службами,
программами на альтернативных платформах или веб-формами.
Особенности веб-служб ASP.NET:
-
Отсутствие элементов управления логикой представления:
- Проект веб-службы не содержит элементов управления логикой представления, таких как страницы или контролы для отображения данных.
-
Использование другими сервисами:
- Большинство веб-служб создаются для использования другими веб-службами, программами на различных платформах или веб-формами для получения и обработки данных.
Состав веб-службы ASP.NET:
-
Библиотека DLL:
- Содержит бизнес-логику и логику данных, используемую веб-службой.
-
Файл ASMX:
- Определяет веб-службу и является точкой входа для запросов к веб-службе.
<%@ WebService Language="C#" CodeBehind="MyService.asmx.cs" Class="MyNamespace.MyService" %> -
Файл Codebehind:
- Содержит класс, специально созданный для работы с веб-службами, реализующий методы, доступные для вызова.
using System.Web.Services; namespace MyNamespace { [WebService(Namespace = "http://tempuri.org/")] public class MyService : WebService { [WebMethod] public string HelloWorld() { return "Hello, World!"; } } }
Веб-службы ASP.NET состоят из библиотеки DLL, файла ASMX и файла Codebehind, который содержит класс, специально созданный для работы с веб-службами. Они обеспечивают бизнес-логику и логику данных в интернете и предназначены для использования другими веб-службами или приложениями на различных платформах.
Что такое CLR?
Common Language Runtime (
CLR
) — это исполняющая среда для байт-кода CIL (MSIL), в который
компилируются программы, написанные на .NET-совместимых языках программирования
(C#, Managed C++, Visual Basic .NET, F#, и другие).
Основные компоненты CLR:
-
Компиляция:
- CLR компилирует код приложения на языке CIL (Common Intermediate Language) во время его исполнения (JIT-компиляция).
-
Библиотека классов:
- Предоставляет MSIL-программам доступ к библиотеке классов .NET Framework, обеспечивая доступ к стандартным функциям и службам.
Механизм работы CLR:
-
Компиляция кода:
-
Программы, написанные на .NET-совместимых языках, сначала компилируются в CIL.
-
CLR затем компилирует CIL-код в машинный код во время выполнения программы.
-
-
Управление выполнением:
- CLR управляет выполнением программ, обеспечивая такие функции, как автоматическое управление памятью (сборка мусора), обработка исключений, безопасность типов, а также управление потоками и синхронизацией.
-
Интероперабельность:
- CLR обеспечивает взаимодействие между управляемым кодом (кодом .NET) и неуправляемым кодом (кодом, который не работает под управлением CLR, например, API Windows).
Пример работы CLR:
-
Написание программы на C#:
public class HelloWorld { public static void Main() { System.Console.WriteLine("Hello, World!"); } } -
Компиляция в CIL:
- Программа компилируется в промежуточный язык (CIL), который затем исполняется CLR.
-
Выполнение CLR:
- При запуске программы CLR компилирует CIL-код в машинный код и управляет его выполнением.
Что такое сборщик мусора (Garbage Collector) на базовом уровне?
Сборщик мусора (
Garbage Collector
) — это автоматическая система управления памятью, которая
освобождает память, занимаемую объектами, которые больше не используются в
программе.
Основные функции:
-
Освобождение памяти:
- Освобождает память недостижимых объектов, включая недостижимые циклы ссылок. Ненужный объект с достижимой ссылкой остается живым.
-
Предотвращение утечек памяти:
- Помогает предотвратить утечки памяти, удаляя неиспользуемые объекты.
-
Улучшение производительности:
- Позволяет программистам не управлять вручную памятью, что уменьшает вероятность ошибок и улучшает производительность приложения.
Сборщик мусора автоматически управляет памятью, удаляя неиспользуемые объекты и освобождая ресурсы, что помогает предотвратить утечки памяти и улучшить производительность.
Что такое делегат?
Делегат — это тип, который представляет ссылку на метод с определенным списком параметров и возвращаемым значением. Делегаты позволяют передавать методы как параметры другим методам и являются основой для событий и обратных вызовов.
Основные функции:
-
Представление метода:
- Делегат хранит ссылку на метод и может вызвать этот метод.
-
Обратные вызовы:
- Используются для реализации обратных вызовов и событий.
-
Многоадресные делегаты:
- Делегаты могут ссылаться на несколько методов и вызывать их последовательно.
Пример:
// Определение делегата
public delegate void MyDelegate(string message);
// Метод, соответствующий делегату
public void ShowMessage(string message) {
Console.WriteLine(message);
}
// Использование делегата
MyDelegate del = ShowMessage;
del("Hello, World!"); // Выведет "Hello, World!"
Делегат в C# представляет собой тип, который содержит ссылку на метод, позволяет передавать методы как параметры и используется для событий и обратных вызовов.
Отличается ли Delegate от Action?
Delegate и Action — оба являются типами делегатов в
C#, но имеют некоторые отличия.
Delegate
-
Пользовательский тип:
-
System.Delegate — базовый класс типов делегатов. Ключевое слово delegate объявляет пользовательский тип делегата; это не одно и то же.
-
Пример:
public delegate void MyDelegate(string message);
-
-
Гибкость:
- Позволяет определять делегаты с любыми параметрами и возвращаемыми значениями.
Action
-
Предопределенный тип:
-
Action — это предопределенный делегат в .NET, который представляет метод, принимающий параметры и не возвращающий значение (
void). -
Пример:
Action<string> myAction = message => Console.WriteLine(message);
-
-
Ограничения:
- Action может принимать от 0 до 16 параметров, но всегда возвращает
void.
- Action может принимать от 0 до 16 параметров, но всегда возвращает
Action — готовое семейство делегатов с результатом void; delegate позволяет объявить собственную сигнатуру. Все такие типы наследуются от System.MulticastDelegate, а через него — от System.Delegate.
Что такое LINQ и для чего используется? Приведите несколько примеров применения LINQ.
LINQ (Language Integrated Query) — это технология
в .NET, которая позволяет выполнять запросы к коллекциям данных прямо в коде,
используя синтаксис, аналогичный SQL.
Основные использования:
-
Запросы к коллекциям объектов:
- LINQ to Objects: Выполнение запросов к коллекциям в памяти (например, массивы, списки).
-
Запросы к базам данных:
- LINQ to SQL / LINQ to Entities: Выполнение запросов к реляционным базам данных через ORM (например, Entity Framework).
-
Запросы к XML:
- LINQ to XML: Выполнение запросов к XML-документам.
Примеры применения LINQ:
-
LINQ to Objects:
var numbers = new List<int> { 1, 2, 3, 4, 5 }; var evenNumbers = from n in numbers where n % 2 == 0 select n; foreach (var num in evenNumbers) { Console.WriteLine(num); // Выведет 2, 4 } -
LINQ to SQL:
using (var context = new MyDataContext()) { var query = from p in context.Products where p.Price > 50 select p; foreach (var product in query) { Console.WriteLine(product.Name); } } -
LINQ to XML:
var xml = XDocument.Load("data.xml"); var items = from item in xml.Descendants("Item") where (int)item.Element("Price") > 100 select item; foreach (var item in items) { Console.WriteLine(item.Element("Name").Value); }
LINQ используется для выполнения запросов к различным типам данных (объекты, базы данных, XML) с использованием удобного и выразительного синтаксиса.
Что такое пространство имен (namespace) и зачем это нужно?
Пространство имен (
namespace
) — это логическая группировка классов, интерфейсов, структур,
перечислений и делегатов, которая используется для организации кода и
предотвращения конфликтов имен.
Зачем это нужно:
-
Организация кода:
- Пространства имен помогают структурировать и упорядочивать код, особенно в больших проектах.
-
Предотвращение конфликтов имен:
- Позволяют избежать конфликтов имен, когда разные части кода или библиотеки имеют одинаковые имена классов или методов.
Пример:
namespace MyApp.Utilities
{
public class UtilityClass
{
public void DoSomething() { /* ... */ }
}
}
namespace MyApp.Models
{
public class User
{
public string Name { get; set; }
}
}
Использование:
using MyApp.Utilities;
using MyApp.Models;
class Program
{
static void Main()
{
UtilityClass utility = new UtilityClass();
utility.DoSomething();
User user = new User { Name = "John Doe" };
Console.WriteLine(user.Name);
}
}
Пространства имен в C# используются для организации кода и предотвращения конфликтов имен, что делает код более управляемым и читаемым.
Какие исключения нельзя остановить в блоке catch?
Возможность обработки зависит от исключения и версии runtime. Переполнение стека, возникшее при выполнении, обычно завершает процесс; OutOfMemoryException можно поймать, но восстановление часто ограничено нехваткой памяти.
-
StackOverflowException:-
Возникает при переполнении стека из-за чрезмерной рекурсии.
-
Пример:
try { RecursiveMethod(); } catch (StackOverflowException ex) { // Не обрабатывается }
-
-
OutOfMemoryException:-
Возникает, когда системе не хватает памяти для продолжения выполнения.
-
Пример:
try { // Код, вызывающий OutOfMemoryException } catch (OutOfMemoryException ex) { // Не обрабатывается корректно }
-
-
ThreadAbortException:-
ThreadAbortException относится к .NET Framework: после catch оно обычно выбрасывается повторно. В .NET Core и .NET 5+ Thread.Abort не поддерживается и вызывает PlatformNotSupportedException.
-
Пример:
try { Thread.CurrentThread.Abort(); } catch (ThreadAbortException ex) { // Поток будет прерван после catch }
-
-
ExecutionEngineException:-
ExecutionEngineException устарело: современные версии runtime его не выбрасывают. Фатальную ошибку CLR нельзя считать обычным восстанавливаемым исключением.
-
Пример:
try { // Код, вызывающий ExecutionEngineException } catch (ExecutionEngineException ex) { // Не обрабатывается корректно }
-
Не объединяйте эти случаи: OutOfMemoryException перехватывается, реальное переполнение стека обычно нет, а ThreadAbortException и ExecutionEngineException требуют оговорок о версии .NET.
Какая разница между .NET Standard Class Library и .NET Core Class Library?
Разница между .NET Standard Class Library и .NET Core Class Library:
-
.NET Standard Class Library:
-
Цель: Предназначена для обеспечения совместимости кода между различными реализациями .NET (например, .NET Framework, .NET Core, Xamarin).
-
Совместимость: Может использоваться в любых проектах, поддерживающих .NET Standard.
-
Пример: Подходит для создания библиотек, которые должны работать на разных платформах.
-
-
.NET Core Class Library:
-
Цель: Предназначена для использования исключительно в .NET Core и .NET 5/6/7+ проектах.
-
Совместимость: Ограничена только .NET Core и последующими версиями .NET.
-
Пример: Подходит для создания библиотек, которые используют специфичные для .NET Core функции и не планируются для использования на других платформах.
-
Объясните разницу между отложенным и немедленным исполнением в LINQ. Приведите примеры.
Отложенное выполнение (
Deferred Execution
):
-
Запрос не выполняется сразу, а только при фактическом доступе к данным (например, при переборе результатов).
-
Примеры методов:
Select,Where,Take.
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var query = numbers.Where(n => n > 2); // Запрос не выполнен
foreach (var number in query)
{
Console.WriteLine(number); // Запрос выполняется здесь
}
Немедленное выполнение (
Immediate Execution
):
-
Запрос выполняется сразу и возвращает результаты в виде коллекции или другого значения.
-
Примеры методов:
ToList,ToArray,Count,First.
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var results = numbers.Where(n => n > 2).ToList(); // Запрос выполнен немедленно
foreach (var number in results)
{
Console.WriteLine(number); // Доступ к уже выполненным результатам
}
Итог:
-
Отложенное выполнение: Запрос выполняется только при фактическом доступе к данным.
-
Немедленное выполнение: Запрос выполняется сразу и результаты сохраняются.
Для чего нужен метод ConfigureServices в Startup.cs?
Метод ConfigureServices в файле
Startup.cs используется для настройки служб (сервисов)
приложения в ASP.NET Core.
Основные задачи:
-
Регистрация служб:
-
Добавление служб в контейнер внедрения зависимостей (Dependency Injection).
-
Примеры служб: базы данных, кэширование, аутентификация.
-
-
Конфигурация параметров:
- Настройка параметров приложения, таких как параметры подключения к базе данных или внешним сервисам.
-
Добавление middleware:
- Регистрация зависимостей middleware возможна здесь, но сам HTTP-конвейер задается вызовами app.Use… в Configure или Program.cs.
Пример:
public void ConfigureServices(IServiceCollection services)
{
// Регистрация службы базы данных
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// Регистрация служб MVC
services.AddControllersWithViews();
// Регистрация пользовательских служб
services.AddScoped<IMyService, MyService>();
}
ConfigureServices регистрирует службы в DI-контейнере. В современном минимальном хостинге это обычно builder.Services в Program.cs; порядок middleware задается отдельно.
Чем отличаются AddTransient и AddScoped в ASP.NET Core?
Разница между services.AddTransient и services.AddScoped в ASP.NET Core:
-
services.AddTransient:-
Время жизни: Создает новый экземпляр службы каждый раз при ее запросе.
-
Использование: Подходит для легковесных, статeless служб.
-
Пример:
services.AddTransient<IMyService, MyService>();
-
-
services.AddScoped:-
Время жизни: один экземпляр на DI-scope. В обычном HTTP-конвейере ASP.NET Core scope создается для каждого запроса; scope также можно создать явно.
-
Использование: Подходит для служб, которые должны сохранять состояние в рамках одного запроса.
-
Пример:
services.AddScoped<IMyService, MyService>();
-
Итог:
-
AddTransient: Создает новый экземпляр каждый раз при запросе. -
AddScoped: один экземпляр на scope, обычно на HTTP-запрос.
Что такое Kestrel?
Kestrel — это кроссплатформенный, высокопроизводительный
HTTP-сервер, встроенный в ASP.NET Core.
Основные особенности:
-
Высокая производительность:
- Разработан для обеспечения высокой скорости обработки запросов.
-
Кроссплатформенность:
- Работает на Windows, Linux и macOS.
-
Обработка HTTP-запросов:
- Используется как встроенный веб-сервер для обработки HTTP-запросов в ASP.NET Core приложениях.
Пример использования:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.UseStartup<Startup>();
});
}
Kestrel — это высокопроизводительный, кроссплатформенный
HTTP-сервер для ASP.NET Core приложений, используемый для
обработки HTTP-запросов.
Опишите ASP.NET MVC request pipeline.
ASP.NET MVC request pipeline — это
последовательность этапов обработки HTTP-запроса, который проходит через
приложение ASP.NET MVC.
Основные этапы:
-
Маршрутизация (Routing):
-
Запрос сопоставляется с маршрутами, определенными в приложении.
-
Пример:
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
-
-
Инициализация контроллера (Controller Initialization):
- На основе маршрута создается экземпляр соответствующего контроллера.
-
Выполнение действия (Action Execution):
-
Контроллер вызывает метод действия, соответствующий запрашиваемому маршруту.
-
Пример:
public IActionResult Index() { /* ... */ }
-
-
Обработка результатов действия (Result Execution):
- Метод действия возвращает результат (например, представление или JSON-данные), который обрабатывается.
-
Генерация ответа (Response Generation):
- Созданный результат (например, HTML-страница) отправляется обратно клиенту.
Пример запроса:
-
Запрос:
- Клиент отправляет запрос:
GET /Home/Index
- Клиент отправляет запрос:
-
Маршрутизация:
- Маршрут
/Home/Indexсопоставляется сHomeControllerи методомIndex.
- Маршрут
-
Инициализация контроллера:
- Создается экземпляр
HomeController.
- Создается экземпляр
-
Выполнение действия:
- Вызывается метод
Indexконтроллера.
- Вызывается метод
-
Обработка результата:
- Метод
Indexвозвращает представление.
- Метод
-
Генерация ответа:
- Представление рендерится в HTML и отправляется клиенту.
ASP.NET MVC request pipeline обрабатывает запросы через последовательность этапов: маршрутизация, инициализация контроллера, выполнение действия, обработка результата и генерация ответа, обеспечивая гибкость и управляемость процесса обработки запросов.
Как в ASP.NET WebAPI настроить кэширование ответов на HTTP-запросы?
Для настройки кэширования ответов на HTTP-запросы в ASP.NET WebAPI можно использовать заголовки Cache-Control и Expires, а также атрибуты кэширования.
Основные методы:
-
Кэширование ответа в ASP.NET Core:
- ResponseCache задает HTTP-заголовки кэширования, но сам не хранит ответы на сервере. Для серверного output caching в ASP.NET Core 7+ нужны AddOutputCache, UseOutputCache и соответствующая политика. Классический System.Web.Mvc.OutputCache не работает как фильтр ApiController.
[HttpGet] [ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)] public IActionResult Get() { return Ok("Hello, World!"); } -
Использование
middleware:- Для более гибкой настройки кэширования можно использовать middleware для управления заголовками кэширования.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.Use(async (context, next) => { context.Response.Headers["Cache-Control"] = "public,max-age=60"; await next(); }); app.UseMvc(); } -
Настройка кэширования с помощью
ResponseCacheAttribute:- В ASP.NET Core можно использовать атрибут
ResponseCacheдля настройки кэширования.
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client, NoStore = false)] public IActionResult Get() { // Ваш код return Ok(); } - В ASP.NET Core можно использовать атрибут
-
Настройка кэширования на стороне клиента:
- Использование заголовков HTTP, таких как
Cache-ControlиExpires, для управления кэшированием на стороне клиента.
[HttpGet] public HttpResponseMessage Get() { var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent("Hello, World!"); response.Headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromMinutes(1) }; return response; } - Использование заголовков HTTP, таких как
Пример:
-
Пример серверного OutputCache в ASP.NET Core 7+:
// Program.cs, ASP.NET Core 7+ var builder = WebApplication.CreateBuilder(args); builder.Services.AddOutputCache(); var app = builder.Build(); app.UseOutputCache(); app.MapGet("/api/data", () => new { Message = "Hello" }) .CacheOutput(policy => policy.Expire(TimeSpan.FromSeconds(60))); app.Run(); -
Использование атрибута
ResponseCacheв ASP.NET Core WebAPI:[ApiController] [Route("api/[controller]")] public class MyApiController : ControllerBase { [HttpGet] [ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any, NoStore = false)] public IActionResult Get() { var data = new { Message = "Hello" }; return Ok(data); } }
Расскажите о Rest Maturity Model
REST Maturity Model (Модель зрелости REST) – это модель,
предложенная Леонардом Ричардсоном, для оценки зрелости REST API на основе их
соответствия архитектурным принципам REST.
Уровни зрелости:
-
Уровень 0 – Отсутствие REST:
-
Описание: Использование единственной точки входа (обычно единственный URL) и использование методов POST для всех операций.
-
Пример: SOAP или XML-RPC, где все взаимодействие происходит через один URI и один метод.
-
-
Уровень 1 – Использование ресурсов:
-
Описание: Разделение API на множество ресурсов, где каждый ресурс имеет уникальный URI.
-
Пример: API, где каждый ресурс (например,
/users,/orders) имеет свой собственный URI, но все еще используется только один HTTP метод (обычно POST).
-
-
Уровень 2 – Использование HTTP методов:
-
Описание: Использование стандартных HTTP методов (GET, POST, PUT, DELETE) для выполнения операций на ресурсах.
-
Пример: API, где используется GET для чтения, POST для создания, PUT для обновления и DELETE для удаления ресурсов.
-
-
Уровень 3 – Гипермедиа (HATEOAS):
-
Описание: Включение гипермедиа в ответы API, что позволяет клиентам динамически обнаруживать доступные действия и переходы на другие ресурсы.
-
Пример: В ответе на запрос включены ссылки на связанные действия или ресурсы (например,
{"self": "/orders/1", "cancel": "/orders/1/cancel"}).
-
Для чего используются и как работают multi-stage билды в Docker?
Multi-stage билды в Docker используются для
создания оптимизированных Docker-образов, уменьшая их размер и улучшая
безопасность. Это достигается путем разделения процесса сборки на несколько
этапов, где промежуточные этапы не включаются в финальный образ.
Как работают multi-stage билды:
-
Разделение на этапы:
-
В Dockerfile определяется несколько этапов сборки с использованием ключевого слова
FROMдля каждого этапа. -
Каждый этап может использовать разные базовые образы и выполнять различные действия.
-
-
Копирование артефактов:
- Результаты (артефакты) из одного этапа могут быть скопированы в следующий этап с помощью команды
COPY --from=stage_name.
- Результаты (артефакты) из одного этапа могут быть скопированы в следующий этап с помощью команды
-
Финальный минимальный образ:
- Финальный образ содержит только необходимые для работы приложения файлы, без инструментов и зависимостей, используемых на этапах сборки.
Пример использования multi-stage билдов в Dockerfile:
# Первый этап: сборка приложения
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app
COPY . .
RUN dotnet publish -c Release -o out
# Второй этап: создание минимального образа для выполнения
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "MyApp.dll"]
Преимущества:
-
Уменьшение размера образа:
- Финальный образ содержит только необходимые файлы и зависимости, что снижает размер образа.
-
Повышение безопасности:
- Исключение инструментов сборки и временных файлов уменьшает поверхность атаки.
-
Упрощение управления зависимостями:
- Отделение этапов сборки и выполнения позволяет четко управлять зависимостями.
Что такое маршалинг?
Маршалинг (
Marshaling
) – это процесс преобразования объектов или данных из одного
формата или контекста в другой, для передачи между различными компонентами
программного обеспечения или между разными средами выполнения.
Основные применения:
-
Межпроцессное взаимодействие (Inter-process communication, IPC):
- Передача данных между процессами, которые могут работать на одном или разных компьютерах.
-
Удаленные вызовы процедур (Remote Procedure Calls, RPC):
- Вызов методов или процедур на удаленных серверах, часто с использованием сетевых протоколов.
-
Интеграция разных технологий:
- Взаимодействие между компонентами, написанными на разных языках программирования или работающими в разных средах (например, взаимодействие между C# и COM-объектами).
Пример использования маршалинга в C#:
P/Invoke для вызова нативного кода:using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
MessageBox(IntPtr.Zero, "Hello, World!", "Hello", 0);
}
}
Основные задачи маршалинга:
-
Преобразование данных:
- Преобразование данных из одного представления в другое, подходящее для передачи или использования в другом контексте.
-
Управление памятью:
- Обеспечение правильного управления памятью при передаче данных между разными средами.
-
Сериализация и десериализация:
- Преобразование объектов в формат, пригодный для хранения или передачи (например, JSON, XML) и обратно.
Как работает async / await (подробно)? Почему нельзя использовать async void методы?
async / await
:
Как работает:
-
asyncметод:-
Определяет метод как асинхронный, позволяет использовать await внутри метода.
-
Возвращает
TaskилиTask<T>, что позволяет методам асинхронно ожидать завершения.
-
-
awaitметод:-
Приостанавливает выполнение метода до завершения ожидаемой задачи.
-
Возвращает управление вызывающему потоку, позволяя выполнять другие задачи.
-
public async Task<int> FetchDataAsync()
{
HttpClient client = new HttpClient();
string data = await client.GetStringAsync("http://example.com");
return data.Length;
}
async void методы
Почему нельзя использовать:
-
Нет возможности
await:- Невозможно ожидать завершения async void метода, что затрудняет обработку ошибок и отладку.
-
Обработка исключений:
- Исключения не могут быть пойманы вызывающим кодом, что может привести к неожиданным сбоям.
-
Потеря возможности компоновки:
- Методы, возвращающие
Task, могут быть легко комбинированы и использованы в других асинхронных операциях.
- Методы, возвращающие
async voidследует использовать только для обработчиков событий, где нет необходимости в возвращаемом значении или обработке ошибок.
private async void Button_Click(object sender, EventArgs e)
{
await FetchDataAsync();
}
Итог:
-
async / await позволяет писать асинхронный код, который выглядит синхронным, улучшая читаемость и поддержку.
-
async void следует избегать, кроме как в обработчиках событий, из-за проблем с обработкой ошибок и невозможностью ожидания завершения.
Как работает lock? Можно ли использовать структуры внутри выражения lock?
lock
в C#:
Как работает:
-
Определение:
lockобеспечивает эксклюзивный доступ к определенному ресурсу для одного потока, предотвращая одновременный доступ из других потоков. -
Синтаксис: Заключает критическую секцию кода, которая должна выполняться атомарно.
-
Механизм: Использует объект-закрытие (object lock), чтобы определить область блокировки. Внутри
lockблокируется указанное объектное выражение, и освобождается после выхода из блока.
private static readonly object _lockObject = new object();
public void CriticalSection()
{
lock (_lockObject)
{
// Код внутри этого блока может быть выполнен только одним потоком одновременно
}
}
Использование структур в lock
Можно ли использовать структуры:-
Нет, нельзя: Нельзя использовать структуры (значимые типы) внутри выражения
lock. -
Причина:
lockтребует ссылочный тип (object), так как структуру можно легко скопировать, что приведет к неэффективной блокировке и потенциальным ошибкам.
Что такое Expression Tree?
Expression Tree (Дерево выражений) – это структура
данных в .NET, которая представляет синтаксическое дерево выражения кода,
позволяя анализировать и выполнять код во время выполнения.
-
Динамическое создание и модификация кода:
- Позволяет программно создавать и изменять выражения.
-
Компиляция и выполнение:
- Выражения могут быть скомпилированы в исполняемый код и выполнены.
-
Анализ и трансформация:
- Позволяет анализировать структуру кода, оптимизировать или преобразовывать выражения перед выполнением.
Expression Tree
в C#:
using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
// Создание параметра для выражения
ParameterExpression param = Expression.Parameter(typeof(int), "x");
// Создание выражения для x * 2
Expression multiply = Expression.Multiply(param, Expression.Constant(2));
// Создание лямбда-выражения
Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(multiply, param);
// Компиляция и выполнение
Func<int, int> compiled = lambda.Compile();
int result = compiled(5);
Console.WriteLine(result); // Вывод: 10
}
}
Как в .NET Core можно настроить хранение секретов на компьютерах разработчиков и на рабочих средах?
В .NET Core можно настроить хранение секретов на компьютерах разработчиков и на рабочих средах с помощью следующих подходов:
На компьютерах разработчиков:
-
Secret Manager:
-
Описание: Secret Manager держит секреты разработки вне проекта. Он не шифрует хранилище и не предназначен для производственной среды.
-
Использование: Секреты хранятся в локальной пользовательской конфигурации.
-
Команды:
# Установка Secret Manager dotnet user-secrets init # Добавление секретов dotnet user-secrets set "MySecret" "Value" -
Пример кода для чтения секретов:
public class Program { public static void Main(string[] args) { var builder = new ConfigurationBuilder() .AddUserSecrets<Program>(); var configuration = builder.Build(); string mySecret = configuration["MySecret"]; // Передайте секрет нужному компоненту; не выводите его в лог. } }
-
На рабочих средах:
-
Переменные окружения (Environment Variables):
-
Описание: Секреты могут быть заданы как переменные окружения.
-
Пример настройки: В среде (например, в Azure или Docker) задать переменные окружения.
-
Пример кода для чтения переменных окружения:
public class Program { public static void Main(string[] args) { var builder = new ConfigurationBuilder() .AddEnvironmentVariables(); var configuration = builder.Build(); string mySecret = configuration["MySecret"]; // Передайте секрет нужному компоненту; не выводите его в лог. } }
-
-
Azure Key Vault:
-
Описание: Облачное хранилище для управления доступом и защитой секретов.
-
Настройка:
-
Создать хранилище секретов в Azure Key Vault.
-
Настроить доступ для приложения.
-
-
Пример кода для чтения секретов из Key Vault:
public class Program { public static void Main(string[] args) { var builder = new ConfigurationBuilder() .AddAzureKeyVault(new Uri("https://<your-keyvault-name>.vault.azure.net/"), new Azure.Identity.DefaultAzureCredential()); var configuration = builder.Build(); string mySecret = configuration["MySecret"]; // Передайте секрет нужному компоненту; не выводите его в лог. } }
-
Для хранения секретов на компьютерах разработчиков в .NET Core используется Secret Manager. На рабочих средах предпочтительны переменные окружения или более защищенные решения, такие как Azure Key Vault, для управления и защиты секретов.
Как включить CORS в AspNetCore?
Включение
CORS
в
ASP.NET Core
:
Шаги:
-
Добавить сервисы
CORSвStartup.cs:- В методе
ConfigureServicesдобавить сервисы CORS с нужной политикой.
public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy("AllowSpecificOrigin", builder => { builder.WithOrigins("http://example.com") .AllowAnyHeader() .AllowAnyMethod(); }); }); services.AddControllers(); } - В методе
-
Включить
CORSв обработке запросов:- В методе
Configureдобавить использование CORS.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseCors("AllowSpecificOrigin"); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } - В методе
-
(Опционально) Настроить
CORSна уровне контроллера или действия:- Использовать атрибут
[EnableCors]для настройки CORS на уровне контроллера или действия.
[ApiController] [Route("[controller]")] public class MyController : ControllerBase { [EnableCors("AllowSpecificOrigin")] [HttpGet] public IActionResult Get() { return Ok("CORS is enabled!"); } } - Использовать атрибут
Включение CORS в ASP.NET Core включает добавление и настройку сервиса CORS в Startup.cs, и его применение в конвейере обработки запросов. Это позволяет управлять политиками доступа для кросс-доменных запросов.
Что такое CPU и IO-bound задачи?
CPU-bound
задачи:
Определение: Задачи, ограниченные вычислительной мощностью процессора, где производительность зависит от скорости обработки данных CPU.
Примеры:-
Сложные вычисления (например, вычисление факториала больших чисел).
-
Обработка изображений и видео.
-
Шифрование и дешифрование данных.
-
Увеличение мощности процессора.
-
Параллелизация задач (многопоточность, многопроцессорность).
void CalculateFactorial()
{
long result = 1;
for (int i = 1; i <= 20; i++)
{
result *= i;
}
Console.WriteLine(result);
}
IO-bound
задачи:
Определение: Задачи, ограниченные скоростью ввода-вывода (IO), где производительность зависит от времени ожидания операций ввода-вывода, таких как чтение/запись на диск или сетевые операции.
Примеры:-
Чтение и запись файлов.
-
Запросы к базам данных.
-
Сетевые запросы (HTTP, FTP).
-
Асинхронное выполнение (async/await).
-
Параллельное выполнение операций ввода-вывода.
async Task ReadFileAsync()
{
using (var reader = new StreamReader("file.txt"))
{
string content = await reader.ReadToEndAsync();
Console.WriteLine(content);
}
}
Итог:
-
CPU-bound задачи: Ограничены производительностью процессора, выигрывают от улучшения вычислительных мощностей.
-
IO-bound задачи: Ограничены скоростью операций ввода-вывода, выигрывают от асинхронного и параллельного выполнения.