en
Feedback

Don't get caught by a cheater! Telemetrio finds and tags such channels 👉 If you want to see the tag, subscribe

C# | Вопросы собесов

C# | Вопросы собесов

Open in Telegram

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @sendme_ads

Show more
5 000
Subscribers
-124 hours
-57 days
-830 days
Posts Archive
GitHub теперь в Telegram! Более 7000+ репозиториев с исходным кодом нейросетей, ботов, сайтов и других интересных проектов дл
GitHub теперь в Telegram! Более 7000+ репозиториев с исходным кодом нейросетей, ботов, сайтов и других интересных проектов для разработчиков: Всё разбито по #хештегам. Подписывайтесь: @GitHub

🤔 Что такое boxing и unboxing? `Boxing` — это процесс преобразования значимого типа (например, int) в объект, чтобы хранить его в виде ссылочного типа. `Unboxing` — это обратный процесс преобразования объекта обратно в значимый тип. Эти операции создают накладные расходы на память и процессор, так как требуют размещения объектов в куче. Boxing и unboxing следует минимизировать для повышения производительности, особенно в критически важных местах программы. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое веб сокеты? Это технология, обеспечивающая двустороннюю связь между клиентом и сервером через один TCP-соединение. В отличие от традиционного HTTP, который работает по принципу запрос-ответ, WebSockets позволяют передавать данные в обоих направлениях в режиме реального времени, что делает их идеальными для приложений, требующих мгновенного обмена данными. 🚩Характеристики 🟠Двусторонняя связь Клиент и сервер могут отправлять данные друг другу независимо, без необходимости инициировать новый запрос. 🟠Постоянное соединение После установления WebSocket-соединение остается открытым, что позволяет передавать данные с минимальной задержкой. 🟠Эффективность Меньшие накладные расходы по сравнению с HTTP, так как заголовки передаются только при установлении соединения, а не для каждого сообщения. 🟠Масштабируемость Поддержка большого количества одновременных соединений, что полезно для чатов, игр и других приложений с интенсивным обменом данными. 🚩Как работают 1⃣Установка соединения Клиент инициирует соединение с сервером через HTTP-запрос с заголовком Upgrade, указывая, что он хочет перейти на WebSocket-протокол. 2⃣Рукопожатие (handshake) Сервер отвечает согласием на переход на WebSocket-протокол, и соединение устанавливается. 3⃣Обмен данными После установления соединения данные могут передаваться в обоих направлениях до тех пор, пока одно из сторон не закроет соединение. 🚩Пример использования Сервер на Python с использованием библиотеки websockets
import asyncio
import websockets

async def handler(websocket, path):
    async for message in websocket:
        print(f"Received message: {message}")
        await websocket.send(f"Echo: {message}")

start_server = websockets.serve(handler, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Клиент на JavaScript
const socket = new WebSocket('ws://localhost:8765');

socket.onopen = function(event) {
    console.log('WebSocket is open now.');
    socket.send('Hello, Server!');
};

socket.onmessage = function(event) {
    console.log(`Message from server: ${event.data}`);
};

socket.onclose = function(event) {
    console.log('WebSocket is closed now.');
};

socket.onerror = function(error) {
    console.log(`WebSocket error: ${error}`);
};
🚩Плюсы ➕Реальное время Подходит для приложений, где важна минимальная задержка, таких как чаты, игровые приложения и финансовые торговые платформы. ➕Меньшие накладные расходы Меньшее количество данных передается по сети по сравнению с традиционными HTTP-запросами. ➕Удобство Простота в использовании и поддержка большинством современных браузеров. Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое многопоточность? Многопоточность — это возможность выполнения нескольких потоков (threads) одновременно в одной программе. В C# многопоточность поддерживается с помощью класса `Thread`, задач (`Task`) и `ThreadPool`. Многопоточность используется для выполнения параллельных операций, таких как обработка данных или выполнение задач, которые не должны блокировать основной поток. Она помогает повысить производительность, но требует осторожности для предотвращения гонок данных и взаимоблокировок. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое двухуровневый кеш? Это система кэширования, которая использует два различных уровня хранения данных для повышения производительности и обеспечения надежности. Такая система обычно включает более быстрый, но меньший по объему кеш первого уровня (L1) и более медленный, но более объемный кеш второго уровня (L2). Двухуровневое кэширование часто используется для улучшения времени доступа к данным и оптимизации использования ресурсов. 🚩Принципы 🟠Кеш первого уровня (L1) Характеристики: Высокая скорость доступа, меньший объем. Типичные реализации: В памяти (например, локальный кеш на уровне приложения или узла). Использование: Содержит наиболее часто используемые данные для быстрого доступа. 🟠Кеш второго уровня (L2) Характеристики: Медленнее, чем L1, но обладает большим объемом. Типичные реализации: Внешние системы хранения данных (например, распределенные кеши или базы данных в памяти, такие как Redis). Использование: Содержит данные, которые не поместились в L1 или которые используются реже. 🚩Пример двухуровневого кеша 1⃣Настройка локального кеша (L1)
var l1Cache = new L1Cache(100);
l1Cache.Set("myKey", "myValue");
var value = l1Cache.Get<string, string>("myKey");
2⃣Настройка удаленного кеша (L2) с использованием Redis
var redisCache = new RedisCache();
redisCache.Set("myKey", "myValue");
var value = redisCache.Get("myKey");
3⃣Реализация двухуровневого кеша
using System;
using Microsoft.Extensions.Caching.Memory;
using StackExchange.Redis;

public class CacheService
{
    private readonly MemoryCache _l1Cache;
    private readonly IDatabase _l2Cache;

    public CacheService(int l1CacheSize, string redisHost = "localhost", int redisPort = 6379, int redisDb = 0)
    {
        _l1Cache = new MemoryCache(new MemoryCacheOptions { SizeLimit = l1CacheSize });
        var redis = ConnectionMultiplexer.Connect($"{redisHost}:{redisPort}");
        _l2Cache = redis.GetDatabase(redisDb);
    }

    public string GetData(string key)
    {
        // Проверка в кеше L1
        if (_l1Cache.TryGetValue(key, out string l1Value))
        {
            Console.WriteLine("L1 Cache Hit");
            return l1Value;
        }

        // Проверка в кеше L2 (Redis)
        var l2Value = _l2Cache.StringGet(key);
        if (l2Value.HasValue)
        {
            Console.WriteLine("L2 Cache Hit");
            _l1Cache.Set(key, l2Value, new MemoryCacheEntryOptions().SetSize(1));
            return l2Value;
        }

        // Если данные не найдены, получение из исходного хранилища
        Console.WriteLine("Cache Miss");
        var dbValue = GetDataFromDatabase(key);
        
        // Добавление данных в оба кеша
        _l1Cache.Set(key, dbValue, new MemoryCacheEntryOptions().SetSize(1));
        _l2Cache.StringSet(key, dbValue);
        
        return dbValue;
    }

    private string GetDataFromDatabase(string key)
    {
        // Симуляция получения данных из базы данных
        return $"Data for {key}";
    }
}
🚩Плюсы ➕Увеличенная производительность Быстрый доступ к часто используемым данным через L1, при этом L2 обеспечивает хранение большого объема данных. ➕Оптимизация ресурсов Сбалансированное использование памяти и внешних хранилищ для кэширования. ➕Надежность Разделение кеша на уровни позволяет сохранить доступность данных при отказе одного из уровней. Ставь 👍 и забирай 📚 Базу знаний

🤔 Зачем нужны интерфейсы, если есть абстрактные классы? Интерфейсы в C# позволяют определять набор методов, которые должны быть реализованы в классах, но не содержат реализации. В отличие от абстрактных классов, интерфейсы не могут содержать полей или реализаций методов (до C# 8.0), и класс может реализовать несколько интерфейсов, но наследовать только один абстрактный класс. Интерфейсы используются для создания гибких архитектур, когда классы могут реализовать множество интерфейсов, предоставляя различные поведения. Они помогают достигать полиморфизма и создавать легко тестируемые системы. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое Redis? Это система управления базами данных с открытым исходным кодом, работающая в памяти и поддерживающая множество типов данных, таких как строки, списки, множества, хеши и другие. Redis часто используется как кэш, брокер сообщений и база данных. Он известен своей высокой производительностью, низкой задержкой и простотой в использовании. 🚩Особенности 🟠Работа в памяти Redis хранит все данные в памяти, что обеспечивает очень быструю скорость чтения и записи. Данные также могут периодически сохраняться на диск для обеспечения долговечности. 🟠Поддержка различных типов данных Строки (Strings): Самый простой тип данных в Redis, который может содержать текст или двоичные данные. Списки (Lists): Упорядоченные коллекции строк, которые можно использовать как очереди или стеки. Множества (Sets): Неупорядоченные коллекции уникальных строк. Упорядоченные множества (Sorted Sets): Коллекции уникальных строк, каждая из которых связана с числовым значением (score), определяющим порядок. Хеши (Hashes): Коллекции пар "ключ-значение", где каждый хеш связан с ключом. Bitmaps и HyperLogLogs: Для эффективного хранения и обработки больших объемов данных. 🟠Высокая производительность Благодаря хранению данных в памяти и простому протоколу клиент-сервер, Redis обеспечивает очень высокую скорость операций. 🟠Поддержка репликации Redis поддерживает мастер-слейв репликацию, что позволяет создать резервные копии данных и обеспечить отказоустойчивость. 🟠Кластеризация Redis Cluster позволяет распределить данные по нескольким узлам, обеспечивая горизонтальную масштабируемость. 🟠Поддержка Lua-скриптов Redis позволяет выполнять атомарные операции с помощью Lua-скриптов. 🟠Транзакции Redis поддерживает транзакции, позволяя выполнить несколько команд атомарно. 🚩Примеры использования 🟠Кэширование Redis часто используется для кэширования данных, что позволяет значительно уменьшить задержку доступа и снизить нагрузку на базу данных.
using StackExchange.Redis;
using System;

class Program
{
    static void Main()
    {
        ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
        IDatabase db = redis.GetDatabase();

        db.StringSet("key", "value");
        string value = db.StringGet("key");

        Console.WriteLine(value);
    }
}
🟠Сессии Хранение сессий пользователя для веб-приложений, что обеспечивает быстрое и эффективное управление состоянием. 🟠Очереди сообщений Использование списков или упорядоченных множеств для организации очередей сообщений.
using StackExchange.Redis;
using System;

class Program
{
    static void Main()
    {
        ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
        IDatabase db = redis.GetDatabase();

        db.ListLeftPush("queue", "task1");
        db.ListLeftPush("queue", "task2");

        string task = db.ListRightPop("queue");
        Console.WriteLine(task);
    }
}
🟠Счетчики и рейтинги Использование упорядоченных множеств для реализации счетчиков, рейтингов или систем рекомендаций.
using StackExchange.Redis;
using System;

class Program
{
    static void Main()
    {
        ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
        IDatabase db = redis.GetDatabase();

        // Add scores for users
        db.SortedSetAdd("scores", "user1", 100);
        db.SortedSetAdd("scores", "user2", 200);

        // Retrieve scores with scores included
        var scores = db.SortedSetRangeByRankWithScores("scores", 0, -1);

        foreach (var score in scores)
        {
            Console.WriteLine($"{score.Element}: {score.Score}");
        }
    }
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Чем отличается IQueryable от IEnumerable? `IEnumerable` используется для перебора коллекции в памяти и поддерживает ленивую загрузку данных. `IQueryable` позволяет работать с данными на уровне источника данных, поддерживая отложенное выполнение запросов и возможность составления SQL-запросов для баз данных. `IQueryable` чаще используется в LINQ для работы с базами данных, а `IEnumerable` — для работы с коллекциями, уже загруженными в память. `IQueryable` может оптимизировать запросы, выполняя их на сервере базы данных. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какие типы Exchanged существуют? 🟠Direct Сообщения направляются в очереди, которые связаны с обменником, если ключ маршрутизации сообщения точно совпадает с ключом маршрутизации, указанным в привязке. Логирование сообщений с разными уровнями важности, где каждая очередь получает сообщения с определенным уровнем (например, "info", "warning", "error").
channel.ExchangeDeclare(exchange: "direct_logs", type: "direct");
🟠Topic Сообщения направляются в очереди на основе шаблонов ключей маршрутизации. Поддерживаются подстановочные знаки: * (заменяет одно слово) и # (заменяет ноль или более слов). Маршрутизация сообщений в зависимости от нескольких критериев, например, "logs.error", "logs.info.user".
channel.ExchangeDeclare(exchange: "topic_logs", type: "topic");
🟠Fanout Широковещательно отправляет сообщения во все очереди, связанные с этим обменником, игнорируя ключ маршрутизации. Широковещательная рассылка сообщений всем подписчикам, например, рассылка уведомлений.
channel.ExchangeDeclare(exchange: "logs", type: "fanout");
🟠Headers Направляет сообщения в очереди на основе заголовков сообщений, а не ключей маршрутизации. Можно задавать правила маршрутизации с использованием заголовков. Маршрутизация сообщений на основе различных свойств, таких как content-type или любые другие произвольные атрибуты.
channel.ExchangeDeclare(exchange: "headers_logs", type: "headers");
🚩Пример настройки обменников и привязок Direct
using RabbitMQ.Client;

var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.ExchangeDeclare(exchange: "direct_logs", type: "direct");
var queueName = channel.QueueDeclare().QueueName;

channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: "info");

connection.Close();
Topic
using RabbitMQ.Client;

var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.ExchangeDeclare(exchange: "topic_logs", type: "topic");
var queueName = channel.QueueDeclare().QueueName;

channel.QueueBind(queue: queueName, exchange: "topic_logs", routingKey: "logs.*.user");

connection.Close();
Fanout
using RabbitMQ.Client;

var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.ExchangeDeclare(exchange: "logs", type: "fanout");
var queueName = channel.QueueDeclare().QueueName;

channel.QueueBind(queue: queueName, exchange: "logs", routingKey: "");

connection.Close();
Headers
using RabbitMQ.Client;

var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.ExchangeDeclare(exchange: "headers_logs", type: "headers");
var queueName = channel.QueueDeclare().QueueName;

var headers = new Dictionary<string, object>
{
    { "x-match", "all" },
    { "key1", "value1" },
    { "key2", "value2" }
};

channel.QueueBind(queue: queueName, exchange: "headers_logs", routingKey: "", arguments: headers);
Ставь 👍 и забирай 📚 Базу знаний

👀 Вы все еще не слышали про канал Путь в IT? Автор (Илья) на своем примере показывает, через что приходится проходить начина
👀 Вы все еще не слышали про канал Путь в IT? Автор (Илья) на своем примере показывает, через что приходится проходить начинающему специалисту. 😉 Почему такого контента вы еще не видели? Илья создает уникальные видео, совмещая тренировки, бытовые моменты и рабочий процесс. Сейчас начинающий специалист поступил в вуз и переехал в другой город, поэтому контент будет еще интересней. Если хочешь узнать админа лучше, зайди в закреп его канала. 👋 Подписывайся, данный канал будет разжигать в тебе огонь. Путь в IT

🤔 Что умеет Action фильтр? Action фильтр в ASP.NET позволяет выполнять дополнительную логику до и после выполнения действий контроллера. Он может использоваться для задач, таких как валидация входных данных, логирование, аутентификация или изменение результата выполнения действия. Фильтры упрощают повторное использование кода и делают обработку запросов более гибкой и расширяемой. Action фильтры можно применять ко всем действиям контроллера или только к определённым методам. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как устроен роутинг в RabbitMQ? Определяет, как сообщения от производителей (producers) направляются в очереди через обменники (exchanges). 1⃣Producers (Производители) Отправляют сообщения в обменники. 2⃣Exchanges (Обменники) Направляют сообщения в очереди на основе привязок (bindings) и типа обменника: Direct Exchange: Сообщения направляются в очереди, соответствующие точному ключу маршрутизации. Topic Exchange: Направляет сообщения в очереди по шаблону ключа маршрутизации. Fanout Exchange: Широковещательно отправляет сообщения во все очереди, связанные с обменником. Headers Exchange: Использует заголовки сообщений для маршрутизации. 3⃣Queues (Очереди) Получают сообщения от обменников. 4⃣Bindings (Привязки) Связывают обменники с очередями и определяют правила маршрутизации. 🚩Пример настройки 1⃣Объявление обменника и очереди
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

channel.exchange_declare(exchange='direct_logs', exchange_type='direct')
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key='info')

connection.close()
2⃣Отправка сообщения
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

channel.exchange_declare(exchange='direct_logs', exchange_type='direct')
routing_key = 'info'
message = 'Hello, RabbitMQ!'
channel.basic_publish(exchange='direct_logs', routing_key=routing_key, body=message)

connection.close()
3⃣Получение сообщений
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

channel.exchange_declare(exchange='direct_logs', exchange_type='direct')
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key='info')

def callback(ch, method, properties, body):
    print(f"Received {body}")

channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
print('Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое async и await? `async` и `await` — это ключевые слова в C#, которые используются для работы с асинхронным кодом. `async` обозначает метод как асинхронный, а `await` позволяет приостановить выполнение метода до завершения асинхронной операции, не блокируя основной поток. Это позволяет писать асинхронный код, который выглядит как синхронный, улучшая читаемость и производительность программ. Асинхронные операции полезны для выполнения долгих задач, таких как запросы к базе данных или сети. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

Откройте подписку на Кинопоиск и Музыку за 1₽ Ответьте на 1 вопрос и получите в подарок доступ к Кинопоиску, Музыке и Книгам
Откройте подписку на Кинопоиск и Музыку за 1₽ Ответьте на 1 вопрос и получите в подарок доступ к Кинопоиску, Музыке и Книгам на 60 дней за 1 рубль. ✨ Сервисы будут доступны не только для Вас, но и для трёх ваших близких Попробовать #реклама 18+ kinopoisk.ru О рекламодателе

🤔 Какие методы есть в Action фильтре? Используются для выполнения логики до и после выполнения метода действия контроллера. Они предоставляют механизм для выполнения кросс-секционных задач, таких как логирование, обработка исключений, валидация и т.д. Action фильтры реализуют интерфейс IActionFilter или IAsyncActionFilter. 🚩Методы в Action фильтре 🟠OnActionExecuting Этот метод вызывается перед выполнением метода действия. Здесь можно добавить логику, которая будет выполняться до вызова действия, например, логирование или проверка условий.
public void OnActionExecuting(ActionExecutingContext context)
{
    // Логика до выполнения действия
}
🟠OnActionExecuted Этот метод вызывается после выполнения метода действия. Здесь можно добавить логику, которая будет выполняться после вызова действия, например, логирование результатов или модификация ответа.
public void OnActionExecuted(ActionExecutedContext context)
{
    // Логика после выполнения действия
}
🟠OnActionExecutionAsync Этот метод объединяет функциональность OnActionExecuting и OnActionExecuted в одном асинхронном методе. Здесь можно определить логику, которая будет выполняться как до, так и после выполнения метода действия.
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
    // Логика до выполнения действия
       
    var resultContext = await next();
       
    // Логика после выполнения действия
}
🚩Реализации Action фильтра Синхронный Action фильтр:
public class SampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Логика до выполнения действия
        Console.WriteLine("Before executing action");
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Логика после выполнения действия
        Console.WriteLine("After executing action");
    }
}
Асинхронный Action фильтр:
public class SampleAsyncActionFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // Логика до выполнения действия
        Console.WriteLine("Before executing action");
        
        var resultContext = await next();
        
        // Логика после выполнения действия
        Console.WriteLine("After executing action");
    }
}
🚩Применение Action фильтра Action фильтр можно применять к контроллерам или действиям контроллера с помощью атрибута [ServiceFilter] или [TypeFilter]. Также его можно зарегистрировать глобально в Startup.cs. Применение к контроллеру или действию:
[ServiceFilter(typeof(SampleActionFilter))]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}
Глобальная регистрация:
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(config =>
    {
        config.Filters.Add(typeof(SampleActionFilter));
    });
}
Ставь 👍 и забирай 📚 Базу знаний

😂 На одном кодинге уже давно не вывезешь, перспектива 2024 года - Информационная Безопасность Ловите два канала на тему ИБ и
😂 На одном кодинге уже давно не вывезешь, перспектива 2024 года - Информационная Безопасность Ловите два канала на тему ИБ и хакинга Арсенал Безопасника - Проект по кибербезопасности - сборник лучших инструментов и утилит по OSINT, хакингу и деанону Бункер Хакера - Все что необходимо, для того чтобы начать свой путь в безопасности - инструменты, книги, справочники, гайды и ресурсы.

🤔 В чём разница между string и StringBuilder? `string` в C# — это неизменяемый тип данных, что означает, что каждое изменение строки создаёт новый объект в памяти. `StringBuilder` — это изменяемый тип, который позволяет эффективно манипулировать строками без создания новых объектов, что улучшает производительность при частых изменениях строк. `StringBuilder` предпочтительнее использовать для конкатенации строк в циклах или при выполнении множества операций со строками. `string` лучше подходит для случаев, когда строка не меняется. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

Timetta — контроль проектов, ресурсов, финансов и задач Комплексное решение для проектно-ориентированного бизнеса. Приложение для контроля проектов, финансов, ресурсов, времени для средних и крупных команд. ✅Планируйте проекты ✅Оценивайте бюджеты ✅Подбирайте ресурсы ✅Контролируйте задачи Узнать больше #реклама 16+ timetta.com О рекламодателе

🤔 Что такое конвейер обработки запросов? Представляет собой последовательность компонентов middleware, через которые проходит HTTP-запрос, начиная с момента его получения сервером и до отправки ответа клиенту. Каждый компонент в конвейере выполняет определенные задачи, такие как аутентификация, авторизация, логирование, обработка ошибок и так далее. Конвейер позволяет легко управлять обработкой запросов, добавляя или удаляя компоненты middleware. 🚩Как работает 1⃣Получение запроса Когда сервер получает HTTP-запрос, он передается в первый компонент middleware в конвейере. 2⃣Последовательная обработка Запрос проходит через каждый компонент middleware последовательно. Каждый компонент может: 🟠Обрабатывать запрос и передать его следующему компоненту. 🟠Обрабатывать запрос и завершить его обработку, не передавая дальше. 🟠Внести изменения в запрос или ответ. 3⃣Передача управления Компонент middleware может передать управление следующему компоненту, вызывая метод next.Invoke(). После завершения обработки запроса следующим компонентом, управление возвращается обратно к предыдущему компоненту. 4⃣Формирование ответа Когда запрос доходит до конца конвейера и обработка завершается, ответ формируется и проходит обратно через все компоненты middleware в обратном порядке, что позволяет им вносить изменения в ответ перед его отправкой клиенту. Вот пример того, как можно настроить конвейер обработки запросов в ASP.NET Core:
public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        // Логирование запросов
        app.Use(async (context, next) =>
        {
            Console.WriteLine($"Request: {context.Request.Method} {context.Request.Path}");
            await next.Invoke();
            Console.WriteLine($"Response: {context.Response.StatusCode}");
        });

        // Обработка статических файлов
        app.UseStaticFiles();

        // Маршрутизация
        app.UseRouting();

        // Аутентификация
        app.UseAuthentication();

        // Авторизация
        app.UseAuthorization();

        // Конечные точки обработки запросов
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Hello, World!");
            });
        });
    }
}
🚩Зачем нужен? 🟠Гибкость Конвейер позволяет легко добавлять и удалять компоненты, изменяя способ обработки запросов. 🟠Модульность Каждый компонент middleware выполняет свою задачу, что делает код более структурированным и легким для поддержки. 🟠Расширяемость Можно легко добавить новые компоненты для обработки различных аспектов запросов, таких как кэширование, компрессия и другие. 🟠Повторное использование Один и тот же компонент middleware может быть использован в разных приложениях, что снижает дублирование кода. Ставь 👍 и забирай 📚 Базу знаний