.NET Разработчик
6.51K subscribers
427 photos
2 videos
14 files
2.04K links
Дневник сертифицированного .NET разработчика.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1595. #TipsAndTricks #PerformanceTips
Советы по Оптимизации Производительности
III. Параллельные вычисления и библиотека параллельных задач (TPL)
Параллельные вычисления могут помочь использовать мощность многоядерных процессоров и ускорить операции, связанные с ЦП.

1. Используйте параллельные циклы с Parallel.For() и Parallel.ForEach()
Плохо:
private void ProcessData(List<int> data)
{
for (int i = 0; i < data.Count; i++)
{
PerformExpensiveOperation(data[i]);
}
}

Здесь для обработки данных используется стандартный цикл for, что приводит к последовательному выполнению операций. Это не позволяет использовать весь потенциал современных многоядерных процессоров.
Хорошо:
private void ProcessData(List<int> data)
{
Parallel.ForEach(
data, item =>
PerformExpensiveOperation(item));
}

Параллельные циклы могут значительно ускорить обработку больших коллекций за счет распределения нагрузки между несколькими ядрами ЦП. Переключайтесь с обычных циклов for и foreach на их параллельные аналоги всякий раз, когда это возможно и безопасно.

2. Используйте класс Partitioner для эффективного распределения рабочей нагрузки.
Плохо:
private void ProcessData(IEnumerable<int> data)
{
Parallel.ForEach(data, item =>
PerformExpensiveOperation(item));
}

Здесь не уделяется особого внимания оптимизации разделения рабочей нагрузки между параллельными задачами. Это может привести к потенциальным накладным расходам и неравномерному распределению нагрузки.
Хорошо:
private void ProcessData(IEnumerable<int> data)
{
var partitioner = Partitioner.Create(data);
Parallel.ForEach(partitioner, item =>
PerformExpensiveOperation(item));
}

Используя класс Partitioner, вы можете эффективно распределять рабочие нагрузки по частям, уменьшая потенциальные накладные расходы и улучшая балансировку нагрузки между параллельными задачами.

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

Источник: https://dev.to/bytehide/50-c-advanced-optimization-performance-tips-18l2
👍21
День 1596. #TipsAndTricks #PerformanceTips
Советы по Оптимизации Производительности
IV. Важность кэширования данных
Кэширование может значительно повысить производительность приложений за счёт сокращения времени, затрачиваемого на выборку и обработку данных.

1. Реализовать кэширование данных с помощью кэша в памяти
Использование кэширования в памяти может значительно сократить время, требующее выборки данных из базы данных, и ускорить приложение.
Плохо:
public Product GetProductById(int id)
{
// Извлечение данных из БД каждый раз
var pr = _dbContext.Products
.FirstOrDefault(p => p.Id == id);
return pr;
}

Здесь данные о продукте извлекаются из базы каждый раз, когда вызывается метод. Это может привести к значительному снижению производительности, особенно если база данных расположена удалённо или находится под большой нагрузкой.
Хорошо:
private static MemoryCache _cache = 
new MemoryCache(new MemoryCacheOptions());

public Product GetProductById(int id)
{
// Извлечение из кэша, если возможно
if (!_cache.TryGetValue(id, out Product pr))
{
pr = _dbContext.Products
.FirstOrDefault(p => p.Id == id);
_cache.Set(id, pr, TimeSpan.FromMinutes(30));
}

return pr;
}

Использование кэширования в памяти для хранения данных сокращает затраты на выборку базы. Используйте MemoryCache для кэширования часто запрашиваемых данных и повышения производительности.

2. Реализуйте кэширование с помощью распределённых систем кэширования
Распределённые системы кэширования, такие как Redis, могут ещё больше повысить производительность вашего приложения за счёт кэширования данных способом, который масштабируется на нескольких серверах и обеспечивает высокую доступность. Например, используем распределённый кэш для извлечения списка популярных продуктов:
private static IDistributedCache _dCache;

public List<Product> GetProducts()
{
var key = "popularProducts";
var cached = _dCache.GetString(key);
if (cached == null)
{
var pr = _dbContext.Products
.Where(p => p.IsPopular).ToList();
_dCache.SetString(key,
JsonConvert.SerializeObject(pr),
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMinutes(30)
});

return pr;
}
else
{
return JsonConvert
.DeserializeObject<List<Product>>(cached);
}
}

Здесь мы используем распределённое кэширование с помощью Redis для хранения данных о популярных продуктах, что сокращает частоту выборки из базы данных. Используйте распределённые системы кэширования для кэширования на нескольких серверах и улучшения масштабируемости приложений.

Источник: https://dev.to/bytehide/50-c-advanced-optimization-performance-tips-18l2
👍13
День 1597. #TipsAndTricks #PerformanceTips
Советы по Оптимизации Производительности
V. Параллелизм и безопасность потоков
Обеспечение потокобезопасности может предотвратить нежелательные ошибки и проблемы с производительностью.

1. По возможности используйте структуры данных без блокировок
Выбор структур данных, таких как ConcurrentBag, ConcurrentQueue или ConcurrentDictionary, может помочь вам обеспечить безопасность потоков в многопоточных сценариях без ущерба для производительности.
Плохо:
private object _sync = new object();
private List<int> _list = new List<int>();

public void Add(int item)
{
lock (_sync)
{
_list.Add(item);
}
}

Здесь используется блокировка для синхронизации доступа к списку, что может привести к конфликтам и снижению производительности.
Хорошо:
private ConcurrentBag<int> _bag =
new ConcurrentBag<int>();
public void Add(int item)
{
_bag.Add(item);
}

Используя структуры данных без блокировок, вы можете свести к минимуму конфликты, повысить производительность и обеспечить потокобезопасность в многопоточных сценариях.

2. Используйте эффективные конструкции синхронизации
Использование SemaphoreSlim, ReaderWriterLockSlim или Monitor, может помочь вам защитить общие ресурсы и обеспечить безопасность потоков, сводя к минимуму конфликты и влияние на производительность.
Плохо: см. выше.

Хорошо:
private SemaphoreSlim _semaphore
= new SemaphoreSlim(1, 1);
private List<int> _list = new List<int>();

public async Task AddAsync(int item)
{
await _semaphore.WaitAsync();
try
{
_list.Add(item);
}
finally
{
_semaphore.Release();
}
}

Эффективные конструкции синхронизации позволяют защитить общие ресурсы и обеспечить безопасность потоков, сводя к минимуму конфликты и влияние на производительность.

3. Используйте Interlocked для атомарных операций
Вы можете выполнять простые атомарные операции, не полагаясь на блокировки, уменьшая конкуренцию и повышая производительность.
Плохо:
private int _counter;
private object _sync = new object();

public void Increment()
{
lock (_syncRoot)
{
_counter++;
}
}

Здесь ключевое слово lock используется для обеспечения потокобезопасности для увеличения счетчика. Однако это может привести к конфликтам и снижению производительности.
Хорошо:
private int _counter;
public void Increment ()
{
Interlocked.Increment(ref _counter);
}

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

Источник: https://dev.to/bytehide/50-c-advanced-optimization-performance-tips-18l2
👍12
День 1598. #Курсы
Сегодня предлагаю вам подборку плейлистов «для новичков», размещённых на канале dotnet. Это серии коротких видео, рассказывающие об основах определённого языка, технологии или инструмента. Думаю, некоторые будут полезны не только совсем новичкам в программировании, но и тем, кто захочет начать знакомиться с какой-то определённой темой.

Языки
C#
F#

Технологии
.NET
ASP.NET
Web API
Entity Framework Core
Xamarin
.NET MAUI
Blazor
ML.NET

Прочее
.NET в Azure
Docker и .NET
NuGet
Основы dotnet-monitor
Миграция с ASP.NET на ASP.NET Core

Инструменты Visual Studio
Начало Работы с GitHub
Автоматизированное Тестирование
Расширения Visual Studio
👍19
День 1599. #ЧтоНовенького
Улучшенная Обработка Исключений в
ASP.NET Core 8. Начало
ASP.NET Core 8 скоро выйдет и принесёт крутые улучшения: больше не нужно писать своё промежуточное ПО для обработки исключений!

В ASP.NET Core 8 вы можете создать класс, реализующий интерфейс IExceptionHandler:
public interface IExceptionHandler
{
ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken);
}

Важная вещь: нужно вернуть True или False:
- при True выполнение конвейера завершится, и другое промежуточное ПО в конвейере не будет вызываться.
- при False, конвейер продолжит выполнение.
public class DefaultExHandler : 
IExceptionHandler
{
private ILogger<DefaultExHandler> _logger;
public DefaultExHandler(
ILogger<DefaultExHandler> logger)
{
_logger = logger;
}

public async ValueTask<bool> TryHandleAsync(
HttpContext ctx,
Exception ex,
CancellationToken ct)
{
_logger.LogError(ex, "Error occurred");

await httpContext.Response
.WriteAsJsonAsync(
new ProblemDetails
{
Status = (int)HttpStatusCode.InternalServerError,
Type = ex.GetType().Name,
Title = "Error occurred",
Detail = ex.Message,
Instance = $"{httpContext.Request.iss.onethod} {httpContext.Request.Path}"
});

return true;
}
}

Вы можете записать в ответ что угодно. Здесь это экземпляр ProblemDetails, потому что это стандарт RFC для обработки ошибок, возвращаемых в ответах HTTP API. Код состояния HTTP по умолчанию — 500, но его можно настроить:
httpContext.Response.StatusCode = 
(int)HttpStatusCode.RequestTimeout;

Регистрация обработчика ошибок:
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddExceptionHandler<DefaultExHandler>();

var app = builder.Build();
app.UseExceptionHandler(opt => { });

app.Run();

Окончание следует…

Источник:
https://anthonygiretti.com/2023/06/14/asp-net-core-8-improved-exception-handling-with-iexceptionhandler/
👍12
День 1600. #ЧтоНовенького
Улучшенная Обработка Исключений в
ASP.NET Core 8. Окончание
Начало

Цепочка обработчиков исключений
Вы можете связать обработчики исключений в цепочку. При возврате False, конвейер продолжит выполнение и вызовет следующий обработчик исключений. Если все обработчики исключений возвратят False, конвейер выполнит все ПО промежуточного слоя, оставшиеся в конвейере. Вы также можете комбинировать обработчики исключений и промежуточное ПО.

Чтобы связать обработчики исключений, вы ДОЛЖНЫ определить обработчик исключений по умолчанию, который будет запускаться (и размещаться в самом конце) для обработки любого исключения, которое не было обработано предыдущими обработчиками. Порядок имеет значение! Ниже показан обработчик, который обрабатывает (только) TimeOutException и прерывает выполнение конвейера, если исключение фактически является TimeOutException. В противном случае выполнение конвейера продолжится и достигнет обработчика исключений по умолчанию:
public class TimeOutExHandler : 
IExceptionHandler
{
private ILogger<DefaultExHandler> _logger;
public TimeOutExceptionHandler(
ILogger<DefaultExHandler> logger)
{
_logger = logger;
}

public async ValueTask<bool> TryHandleAsync(
HttpContext ctx,
Exception ex,
CancellationToken ct)
{
_logger.LogError(ex, "A timeout occurred");

if (ex is TimeoutException)
{
httpContext.Response.StatusCode =
(int)HttpStatusCode.RequestTimeout;

await httpContext.Response
.WriteAsJsonAsync(
new ProblemDetails
{ … });
return true;
}
return false;
}
}

Использование:
var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddExceptionHandler<TimeOutExHandler>();
builder.Services
.AddExceptionHandler<DefaultExHandler>();

var app = builder.Build();

app.UseExceptionHandler(opt => { });



app.Run();

Если при выполнении конечной точки возникнет TimeOutException, оно будет обработано TimeOutExHandler. Любой другой вид исключений достигнет обработчика TimeOutExHandler, но не будет им обработан (т.к. TimeOutExHandler вернёт false), а будет обработан DefaultExHandler.

Источник: https://anthonygiretti.com/2023/06/14/asp-net-core-8-improved-exception-handling-with-iexceptionhandler/
👍9
День 1601. #ЗаметкиНаПолях
Полезные Расширения для IEnumerable. Начало
Мы уже рассматривали расширения для Task<T>, сегодня рассмотрим расширения для
IEnumerable.
Примечание: Будьте осторожны, если ваш тип IQueryable, потому что расширение может материализовать запрос. Вместо IEnumerable вы можете использовать IReadOnlyCollection, чтобы удостовериться, что вы имеете дело с материализованной коллекцией.

1. IsNullOrEmpty
Метод аналогичен методу для строк:
public static bool IsNullOrEmpty<T>(
this IEnumerable<T>? source)
=> source is null || !source.Any();

Использование:
Enumerable.Empty<int>().IsNullOrEmpty();
// true
new[] { 1, 2 }.IsNullOrEmpty();
// false
((IEnumerable<int>)null).IsNullOrEmpty();
// true

2. Разделение
Популярная операция над коллекциями: одна коллекция содержит все элементы, соответствующие предикату, другая – все не соответствующие:
public static (IEnumerable<T> True, IEnumerable<T> False) 
Partition<T>(
this IEnumerable<T> source,
Func<T, bool> predicate)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(predicate);

var trueItems = new List<T>();
var falseItems = new List<T>();

foreach (var item in source)
{
if (predicate(item))
trueItems.Add(item);
else
falseItems.Add(item);
}

return (trueItems, falseItems);
}

Использование:
var numbers = Enumerable.Range(0, 5);
var (even, odd) =
numbers.Partition(n => n % 2 == 0);

3. Медиана
LINQ предоставляет метод Average для среднего арифметического, но нет метода для медианного значения:
public static double Median<T>(
this IEnumerable<T> source)
where T : IConvertible
{
ArgumentNullException.ThrowIfNull(source);

var sorted = source
.Select(x => x.ToDouble(
CultureInfo.InvariantCulture))
.OrderBy(x => x).ToList();
var count = sorted.Count;

if (count == 0)
throw new InvalidOperationException(
"Исходная коллекция пуста.");

if (count % 2 == 0)
return (sorted[count / 2 - 1] + sorted[count / 2]) / 2;

return sorted[count / 2];
}

Использование:
var median = new[] { 1, 1, 1, 1, 5, 6, 7, 8, 9 }
.Median(); // 5
var average = new[] { 1, 1, 1, 1, 5, 6, 7, 8, 9 }
.Average(); // 4.333333333333333

Окончание следует…

Источник:
https://steven-giesel.com/blogPost/1b8eaaef-01a3-4799-9a96-f0d37197d175
👍14
День 1602. #ЗаметкиНаПолях
Полезные Расширения для IEnumerable. Окончание
Начало

4. Мода
Мода – число, которое чаще всего встречается в наборе:
public static IEnumerable<T> 
Mode<T>(this IEnumerable<T> source)
{
ArgumentNullException.ThrowIfNull(source);

var groups = source.GroupBy(x => x);
var maxCount = groups.Max(g => g.Count());
return groups
.Where(g => g.Count() == maxCount)
.Select(g => g.Key);
}

Использование:
var mode = new[] { 1, 1, 1, 1, 5, 6, 7, 8, 9 }
.Mode(); // 1

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

5. Среднеквадратичное отклонение
Это мера того, насколько разбросаны числа:
public static double 
StandardDeviation<T>(
this IEnumerable<T> source)
where T : IConvertible
{
ArgumentNullException.ThrowIfNull(source);

var values = source
.Select(x => x.ToDouble(
CultureInfo.InvariantCulture))
.ToList();
var count = values.Count;

if (count == 0)
throw new InvalidOperationException(
"Исходная коллекция пуста.");

var avg = values.Average();
var sum = values.Sum(d => Math.Pow(d - avg, 2));
return Math.Sqrt(sum / count);
}

Использование:
var stdDev = new[] { 1, 1, 1, 1, 5, 6, 7, 8, 9 }
.StandardDeviation(); // 3.1622776601683795

6. Перемешивание
Этот метод перемешивает элементы в последовательности, используя алгоритм перемешивания Фишера-Йейтса:
public static IEnumerable<T> 
Shuffle<T>(this IEnumerable<T> source)
{
ArgumentNullException.ThrowIfNull(source);

var arr = source.ToArray();
var random = Random.Shared;
for (var i = arr.Length - 1; i > 0; i--)
{
var idx = random.Next(i + 1);
(arr[i], arr[idx]) = (arr[idx], arr[i]);
}
return arr;
}

Использование:
var numbers = Enumerable.Range(0, 5);
var random = numbers.Shuffle();
// 4, 0, 1, 3, 2

Источник: https://steven-giesel.com/blogPost/1b8eaaef-01a3-4799-9a96-f0d37197d175
👍8👎1
День 1603. #ЧтоНовенького
Подсказки IntelliSense в Visual Studio Теперь Могут Управлять Завершениями Кода из GitHub Copilot
В последней версии GitHub Copilot изменение вашего выбора в списке IntelliSense в Visual Studio даёт GitHub Copilot дополнительный контекст, так что вы можете легко получить одно- и многострочные автодополнения кода в зависимости от вашего выбора.

В этом видео кратко показан процесс.

В последнем выпуске (версия 1.84+) предложения Copilot видны не только в списке IntelliSense, когда IntelliSense открыт, но ваш выбор IntelliSense также управляет предложениями Copilot. Это поможет вам исследовать и получить именно то автодополнение кода, которое вы ищете. Это особенно полезно в сочетании с помеченными звёздочками завершениями, которые встроенный в Visual Studio IntelliCode AI располагает вверху списка предложений. До этого пользователям Copilot в Visual Studio приходилось выбирать между принятием завершения Copilot или открытием списка IntelliSense, после чего предложения Copilot больше не отображались.

Нажмите Tab, чтобы принять элемент IntelliSense, затем снова Tab, чтобы принять предложение Copilot. Чтобы скрыть список IntelliSense или принять предложение Copilot (посмотреть предложение с подсветкой синтаксиса), нажмите левую клавишу Ctrl.

Разработчикам, возможно, придётся вручную обновить Copilot до версии 1.84. В Visual Studio выберите Extensions > Extension Manager > Updates (Расширения > Диспетчер расширений > Обновления), чтобы получить последнюю версию GitHub Copilot.

Чтобы начать работу с GitHub Copilot, убедитесь, что вы используете Visual Studio 2022 версии 17.4.4 или более позднюю. Затем ознакомьтесь с руководством в этом видео.

Copilot бесплатен для утверждённых GitHub студентов и коллаборантов популярных проектов с открытым исходным кодом. Подробности о Copilot для физических лиц и Copilot для бизнеса можно найти на веб-сайте GitHub.

Источник: https://devblogs.microsoft.com/visualstudio/github-copilot-visual-studio-intellisense/
👍6
День 1604. #TipsAndTricks #PerformanceTips
Советы по Оптимизации Производительности
VI. Оптимизация обработки исключений
Обработка исключений — важнейший аспект программирования, но неправильное использование может привести к снижению производительности. Посмотрим, как эффективно и ответственно обрабатывать исключения.

1. Избегайте использования исключений для управления потоком
Обработка исключений как части нормального потока исполнения программы может значительно повлиять на производительность, создавая ненужную работу для оптимизатора и приводя к потенциальным проблемам производительности во время выполнения.
Плохо:
try
{
int.Parse(input);
}
catch (FormatException)
{
// обработка неправильного ввода
}
Здесь попытка парсинга недопустимой входной строки вызовет исключение. Генерация исключения здесь не идеальна для производительности и вынуждает обрабатывать FormatException как часть потока исполнения программы.

Хорошо:
if (int.TryParse(input, out int result))
{
// Используем значение
}
else
{
// обработка неправильного ввода
}
Здесь используется метод TryParse, чтобы не полагаться на исключение для потока исполнения. Такой подход обеспечивает лучшую производительность и более чистый код.

2. Используйте фильтры исключений, чтобы свести к минимуму блоки захвата
Фильтры исключений помогают писать эффективный код обработки исключений, который делает блоки захвата более краткими и простыми в обслуживании.
Плохо:
try
{
// …
}
catch (Exception ex)
{
if (ex is InvalidOperationException
|| ex is ArgumentNullException)
{
// обработка этих видов исключений
}
else
{
throw;
}
}
Здесь несколько исключений перехватываются в одном блоке catch с вложенными операторами if, используемыми для определения типа их обработки. Это может привести к более запутанному и сложному в сопровождении коду.

Хорошо:
try
{
// …
}
catch (Exception ex) when (
ex is InvalidOperationException ||
ex is ArgumentNullException)
{
// обработка этих видов исключений
}
Хороший пример демонстрирует использование фильтров исключений. Это позволяет перехватывать исключения только при выполнении определённого условия, что упрощает блоки перехвата и устраняет необходимость в нескольких блоках перехвата или повторной генерации необработанных исключений. См. подробнее о фильтрах исключений

Источник: https://dev.to/bytehide/50-c-advanced-optimization-performance-tips-18l2
👍8
День 1605. #Карьера
9 Ментальных Моделей Сеньора, Которыми Должен Овладеть Каждый
Сеньор — это не звание, а способ мышления. Большинство руководств и курсов сосредоточены на том, чтобы научить вас новейшим фреймворкам, а не научить вас мыслить. Вот 9 ментальных моделей, которые помогут вам мыслить, как сеньор.

1. Принцип Парето: 20% усилий дадут 80% результатов. 20% вашей работы дадут вам 80% навыков. 20% ПО, над которым вы будете работать, обеспечат вам 80% признания. И т.д. Определите и сосредоточьте свои усилия на 20%, которые окупаются.

2. Закон Паркинсона: вы потратите всё время, которое выделите себе, независимо от того, сколько времени реально требуется. Выделив 100 часов на побочный проект, вы потратите 100 часов. Даже если его можно было сделать за 10. Нужны твёрдые сроки, иначе вы никогда не закончите.

3. Решения "с односторонней и двусторонней дверью": первые необратимы, так что не торопитесь, вторые можно легко отменить, поэтому избегайте оверинжиниринга. SQL и NoSQL база — решение первого типа. А выбор между for, foreach и LINQ можно легко изменить. Выбор фреймворка для изучения обратим – всегда можно переключиться на другой. А выбор между остаться разработчиком или стать техническим менеджером, обычно сложно откатить назад, т.к. непросто сохранить технические навыки на управленческой должности.

4. Закон Конвея: структура ПО будет имитировать структуру команд и организации, которые его создают. Команды разработчиков строятся вокруг технических навыков членов: frontend- и backend-инженеры, администраторы БД и специалисты по DevOps. ПО, которое они создают, будет отражать структуру их коммуникации. Обратите внимание на то, как команды общаются и организуются. Структура и качество ПО, которое они производят, будут такими же.

5. Круг Компетенции: знать, что вы знаете, а что нет, и придерживаться того, что вы знаете, пока круг не расширится. Лишь немногие разработчики понимают круг своей компетенции и работают над его улучшением. Большинство отвлекаются на новые фреймворки, перескакивают с одного дела на другое и превращают набор своих навыков в бессвязную кучу. Определите свой круг компетенции, оставайтесь в нём и неустанно работайте над его расширением!

6. Рассуждение от основ: чтобы глубоко понять что-то, надо разбить это на основополагающие элементы и рассуждать на этом уровне. В эпоху новых фреймворков и библиотек, разработчики, которым удаётся понять принципы, лежащие в их основе, могут с лёгкостью ориентироваться во всём этом хаосе.

7. Мышление второго порядка: всегда думайте о последствиях. Вы довольны своей работой, но компания сталкивается с финансовыми проблемами. Можно сменить работу, но надо пройти собеседование. Значит сначала нужно преодолеть свои страхи, а уже потом улучшать навыки. Вы можете думать, что всё будет хорошо, и ничего не делать. Но мышление второго порядка заставит вас понять, что это самый рискованный вариант. Хорошие исполнители всегда учитывают последствия своего поведения и действуют соответственно.

8. Обратное мышление: решение задачи является обратным задаче. Чтобы найти решение проблемы, подумайте о том, как проблему создать. Что делать, чтобы получить повышение? Подумаем, что нужно, чтобы оставаться на том же уровне: не улучшать навыки, делать минимум, лишь бы не уволили, не просить больше, не ходить на собеседования и т.п. Теперь переверните всё вышеописанное, и у вас есть решение проблемы!

9. Делать вещи правильно или делать правильные вещи: если вы делаете неправильные вещи, вы никогда не достигнете своих целей. Вы можете услышать о популярности Kubernetes и потратить сотни часов на его изучение и сертификацию по облачным сервисам. Но, если ваша работа с этим не связана, эти навыки не практикуются, а реальные ваши навыки (о которых могут спросить на собеседовании) деградируют. Это не проблема нехватки времени или дисциплины. Вы правильно делали неправильные вещи.

Источник: https://dev.to/dragosnedelcu/9-senior-developer-mental-models-every-programmer-should-master-1jlk
👍22
День 1606. #BestPractices
Правильно Используем HttpClient. Начало
Самый простой способ делать HTTP-запросы в .NET — использовать HttpClient. Это отличная абстракция, особенно при передаче данных в JSON. К сожалению, легко неправильно использовать HttpClient.

Самый простой способ — создать новый экземпляр, задать необходимые свойства и использовать его для отправки запросов. Однако каждый экземпляр использует собственный пул соединений в целях изоляции. Если сервер находится под высокой нагрузкой, а приложение постоянно создаёт новые подключения, это может привести к исчерпанию доступных портов. Это вызовет исключение во время выполнения при попытке отправить запрос.

Вместо самостоятельного управления временем жизни HttpClient вы можете использовать IHttpClientFactory для создания экземпляра. Просто вызовите метод CreateClient и используйте возвращённый экземпляр HttpClient для отправки запросов.

Дорогостоящей частью HttpClient является фактический обработчик сообщений — HttpMessageHandler. Каждый HttpMessageHandler имеет внутренний пул HTTP-соединений, который можно использовать повторно. IHttpClientFactory будет кэшировать HttpMessageHandler и повторно использовать его при создании нового экземпляра HttpClient. Важным примечанием здесь является то, что экземпляры HttpClient, созданные IHttpClientFactory, должны быть недолговечными.
// в Program регистрируем фабрику:
services.AddHttpClient();

// в сервисе внедряем её
public class MyService
{
private IHttpClientFactory _factory;

public MyService(
IHttpClientFactory factory)
{
_factory = factory;
}

public async Task<string> GetAsync()
{
var client =
_factory.CreateClient();
client.BaseAddress =
new Uri("https://my.api.com");

}
}

Сокращаем дублирование с помощью именованных клиентов
Использование IHttpClientFactory решит большинство проблем, связанных с созданием HttpClient вручную. Но нам по-прежнему необходимо настраивать параметры запроса по умолчанию каждый раз, когда мы получаем новый экземпляр из CreateClient().

Можно настроить именованный клиент. AddHttpClient принимает имя и делегат, который можно использовать для настройки параметров по умолчанию экземпляра HttpClient:
services.AddHttpClient(
"client1",
(c) =>
{
c.BaseAddress =
new Uri("https://my.api.com");
}
);

Отличие в том, что теперь нужно указывать имя при получении экземпляра через CreateClient:
var client = _factory.CreateClient("client1");

Окончание следует…

Источник:
https://www.milanjovanovic.tech/blog/the-right-way-to-use-httpclient-in-dotnet
👍21
День 1607. #BestPractices
Правильно Используем HttpClient. Окончание
Начало

Замена именованных клиентов типизированными
Недостатком использования именованных клиентов является необходимость разрешать HttpClient, каждый раз передавая имя. Добиться того же поведения можно через типизированный клиент, вызвав AddClient<TClient>(), где TClient – сервис, в который будет внедряться HttpClient.

Замечание: «Под капотом» всё равно используется именованный клиент, имя которого совпадает с именем типа. Также это зарегистрирует MyService с временем жизни transient.
services.AddHttpClient<MyService>(
(c) =>
{
c.BaseAddress =
new Uri("https://my.api.com");
}
);

В MyService внедряем HttpClient, а не фабрику:
public class MyService
{
private HttpClient client;

public MyService(HttpClient client)
{
_client = client;
}

public async Task<string> GetAsync()
{
return await
client.GetFromJsonAsync(…);
}
}

Избегайте типизированных клиентов в синглтонах
Поскольку типизированный клиент является transient-сервисом, внедрение его в singleton-сервис приведёт к его кэшированию на время существования singleton-сервиса, что помешает типизированному клиенту реагировать на изменения DNS. Если вы хотите использовать типизированный клиент в singleton-сервисе, рекомендуется использовать SocketsHttpHandler в качестве основного обработчика и настроить свойство PooledConnectionLifetime. Также, т.к. теперь SocketsHttpHandler будет управлять пулом подключений, для него можно установить бесконечное время жизни:
services.AddHttpClient<MyService>(
(c) => { … }
)
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new SocketsHttpHandler()
{
PooledConnectionLifetime
= TimeSpan.FromMinutes(15)
};
})
.SetHandlerLifetime(Timeout.InfiniteTimeSpan);

Какой вариант использовать?
Согласно рекомендациям Microsoft:
- Используйте статический или singleton-экземпляр HttpClient с настроенным PooledConnectionLifetime, так как это решает проблемы как исчерпания портов, так и отслеживания изменений DNS.
- Используйте IHttpClientFactory, если вы хотите переместить конфигурацию в одно место или использовать несколько разных клиентов, настроенных для разных вариантов использования. Но помните, что клиенты должны быть недолговечными, и после создания клиента фабрика больше не может управлять им.
- Используйте типизированный клиент, если вам нужна возможность настройки IHttpClientFactory.

Источник: https://www.milanjovanovic.tech/blog/the-right-way-to-use-httpclient-in-dotnet
👍9
День 1608. #ЧтоНовенького
Новинки
ASP.NET Core в .NET 8 Превью 5
Последний выпуск .NET 8 Preview 5 содержит важные дополнения в ASP.NET Core, которые кратко сегодня рассмотрим.

1. Продуктивность.
Улучшения отладки в ASP.NET Core касаются введения атрибутов настройки отладки (DebuggerDisplay), упрощающих извлечение важной информации, связанной с такими типами, как HttpContext, HttpRequest, HttpResponse и ClaimsPrincipal, в отладчике Visual Studio.

2. «Незаметные повторные подключения» в SignalR. Эта новая функция направлена на минимизацию времени простоя клиентов, сталкивающихся с временными сбоями в работе сети. Временная буферизация данных как на стороне сервера, так и на стороне клиента и подтверждение сообщений обеспечивают более плавное взаимодействие с пользователем. В настоящее время эта поддержка ограничена клиентами .NET, использующими WebSockets, а конфигурация пока недоступна. Разработчики могут свободно использовать эту функцию и настраивать параметры options.UseAks в HubConnectionBuilder. Ожидается, что в будущих версиях будет представлена конфигурация на стороне сервера, настраиваемые параметры буферизации, ограничения времени ожидания и расширенная поддержка других видов клиентов.

3. Blazor
- Компонент Blazor Router теперь интегрируется с маршрутизацией конечных точек для обработки маршрутизации как на стороне сервера, так и на стороне клиента. Эта интеграция обеспечивает согласованную маршрутизацию к компонентам независимо от того, используется ли рендеринг на стороне сервера или на стороне клиента. Новый шаблон Blazor Web App включает образцы страниц, такие как Index.razor и ShowData.razor, которые используют маршрутизацию конечных точек и потоковую визуализацию для отображения данных прогноза погоды, а улучшенная поддержка навигации ожидается в будущих предварительных версиях .NET 8.

- Blazor Server предоставляет возможность включения интерактивности для отдельных компонентов. С помощью нового атрибута [RenderModeServer] разработчики могут активировать интерактивность для определённых компонентов, используя метод расширения AddServerComponents. Это усовершенствование обеспечивает большую гибкость и контроль при создании интерактивных приложений в режиме рендеринга Blazor Server.

4. Обобщённые атрибуты, добавленые в C#11, теперь предоставляют более ясные альтернативы атрибутам, которые ранее полагались на параметр типа System.Type. Обобщённые варианты теперь доступны для следующих атрибутов: ProducesResponseType<T>, Produces<T>, MiddlewareFilter<T>, ModelBinder<T>, ModelMetadataType<T>, ServiceFilter<T> и TypeFilter<T>.

5. Аутентификация и авторизация. Шаблоны проектов ASP.NET Core React и Angular удалили зависимость от Duende IdentityServer. Вместо этого теперь используется пользовательский интерфейс ASP.NET Core Identity по умолчанию и аутентификация по файлам cookie. Кроме того, представлен новый анализатор Roslyn, чтобы облегчить принятие более «краткого» синтаксиса с использованием API AddAuthorizationBuilder, где это применимо.

6. В области Native AOT добавлены улучшения для минимальных API, создаваемых во время компиляции. Они включают поддержку параметров, дополненных атрибутом AsParameters, и автоматический вывод метаданных для типов запросов и ответов.

Разработчики могут оставлять отзывы и следить за ходом работы над ASP.NET Core в .NET 8, посетив официальный репозиторий проекта на GitHub.

Источник: https://www.infoq.com/news/2023/06/aspnet-core-8-preview-5/
👍4👎1
День 1609. #TipsAndTricks #PerformanceTips
Советы по Оптимизации Производительности
VII. Обнуляемость и обнуляемые ссылочные типы
Обработка ссылочных типов, допускающих значение null, является важной частью программирования на C#, особенно для предотвращения исключений NullReferenceException. Рассмотрим несколько советов по безопасной работе с типами, допускающими значение null, без ущерба для производительности.

1. Используйте операторы объединения с null (??, ??=)
Операторы объединения с null помогают писать краткий и производительный код при работе с типами, допускающими значение NULL, гарантируя, что значения null заменяются значением по умолчанию.
Плохо:
string input = GetNullableString();
if (input == null)
{
input = "default";
}
Неудачный пример демонстрирует многословный и менее производительный код при работе с нулевыми значениями.

Хорошо:
var input = GetNullableString() ?? "default";
Здесь используется оператор объединения с нулевым значением, который обеспечивает более лаконичный и эффективный способ обработки нулевых значений в C#. Это обеспечивает лучшую производительность и более понятный код.

2. Используйте обнуляемые ссылочные типы, чтобы избежать исключений NullReferenceException во время выполнения
Обнуляемые ссылочные типы, появившиеся в C# 8.0, помогают перехватывать потенциальные исключения NullReferenceException во время компиляции, а не во время выполнения.
Плохо:
string name = GetName();
int length = name.Length;
Здесь у нас потенциально во время выполнения может возникнуть исключение NullReferenceException, что может привести к неожиданным сбоям.

Хорошо:
string? name = GetName();
int length = name?.Length ?? 0;
Используя обнуляемые ссылочные типы, и условный доступ с нулевым значением через оператор ?., вы можете избежать потенциальных исключений NullReferenceException в своём коде. Это помогает создавать более безопасный и производительный код, который легче понять как во время разработки, так и во время отладки.

Источник: https://dev.to/bytehide/50-c-advanced-optimization-performance-tips-18l2
👍13
День 1610. #ЗаметкиНаПолях
Отключаем HSTS для Локального Хоста в Браузерах на Движке Chromium
Http Strict Transport Security (HSTS) — это механизм безопасности, который предписывает браузеру автоматически перенаправлять http-запросы на https перед отправкой запроса на сервер. При разработке веб-приложения иногда полезно отключить HSTS для локального хоста. Это связано с тем, что включение HSTS на локальном хосте влияет на другие приложения. Например, некоторые приложения запускают локальный веб-сервер и открывают браузер. Однако, если они не могут использовать сертификат безопасности, то не могут использовать https. Если веб-сайт один раз активирует HSTS на локальном хосте, эти приложения перестанут работать, поскольку они не прослушивают https.

ASP.NET Core достаточно умён, чтобы не отправлять заголовок HSTS, когда приложение работает на локальном хосте. Однако это может быть не так для других веб-фреймворков.

Отключение политики HSTS вручную
Вы можете открыть страницу about://net-internals/#hsts в браузере, работающем на движке Chromium (Chrome, Edge и т.п.) и удалить политику безопасности домена для localhost в разделе "Delete domain security policies".

Использование другого домена для разработки
HSTS применяется отдельно для каждого домена. Поэтому вы можете использовать другой домен для вашего приложения, например, myapp.local вместо localhost. Таким образом, даже если приложение использует HSTS, это не повлияет на другие приложения, использующие localhost. Чтобы настроить домен, нужно отредактировать файл hosts (C:\Windows\System32\drivers\etc\hosts), добавив туда запись вроде:
127.0.0.1 myapp.local

Затем, измените applicationUrl в файле launchSettings.json вашего приложения на использование https://myapp.local, и можно использовать https://myapp.local в браузере.

См. также «Принудительный HTTPS в Приложениях ASP.NET Core»

Источник: https://www.meziantou.net/disabling-hsts-for-localhost-on-chromium-based-browsers.htm
👍12
День 1611. #Карьера
Парное Программирование: Лучшие Практики и Инструменты. Начало
В этой серии рассмотрим концепцию парного программирования, его преимущества и полезные инструменты, а также развеем несколько распространённых мифов.

Парное программирование — это метод, при котором два разработчика работают вместе над одной и той же задачей. При этом один человек пишет код (водитель), а другой просматривает каждую строку и даёт обратную связь (штурман). Этот подход отличается от традиционного сольного программирования и имеет некоторые преимущества.

Обязанность водителя - работа с компьютером и ввод кода. Обязанность штурмана — думать о том, что нужно делать и в каком направлении двигаться. Они постоянно общаются и меняются ролями обычно каждые несколько минут.

Преимущества
1. Улучшенное качество кода
Два программиста могут быстро выявлять ошибки друг друга, что улучшает качество кода и значительно снижает вероятность пропуска ошибок. Партнёры могут предлагать друг другу ценную информацию, улучшения и получать отзывы о своих идеях, прежде чем приступить к их реализации. Таким образом, команда может создавать более чистый, функциональный и оптимизированный код.

2. Расширение сотрудничества и коммуникации
Парное программирование помогает коллегам работать над одной кодовой базой и делиться своими знаниями и навыками, что приводит к лучшему решению проблем, а также устраняет разрыв в общении между коллегами, поскольку способствует общению, позволяя быстро и легко обмениваться информацией.
Например, во время работы над новой функцией один программист может объяснить свой мыслительный процесс и идеи, а другой – дать отзыв и задать вопросы, чтобы прояснить, что нужно сделать. Таким образом, команда может работать вместе, чтобы найти лучшее решение и избежать недоразумений.

3. Повышение продуктивности
Когда два программиста работают вместе, они могут быстрее выполнять задачи, разделяя ответственность. Один может работать над проблемой, а другой - искать потенциальные ошибки. Таким образом, команда может более эффективно работать и решать проблемы. Хотя это зависит от конкретного человека, некоторые программисты более продуктивны, работая в одиночку.
Например, пара, работающая над проектом, может потратить 1-2 часа на выполнение задачи, на выполнение которой у одиночного разработчика ушло бы 3-4 часа. Вторая пара может сосредоточиться на поиске ошибок или других проблем в коде. Это означает, что команда выполнит задачу за меньшее время и с меньшими усилиями, повышая общую продуктивность.

Мифы
1. Это дорого
На самом деле повышенная стоимость - это инвестиции в продуктивность команды, качество кода и инновации. В долгосрочной перспективе это экономит время и снижает затраты, вследствие обнаружения ошибок на ранних стадиях.

2. Это медленно
Парное программирование может быть быстрее, чем другие подходы к кодированию, потому что оно позволяет быстро вносить исправления. Когда два разработчика сотрудничают, они могут избежать многих ошибок и ускорить решение проблем.

3. Это давит на разработчиков
Некоторые считают, что парное программирование может оказывать слишком большое давление на разработчиков, что приводит к конфликтам. Однако это происходит только при плохом атмосфере в команде. Так что всё зависит от того, какие у вас отношения с вашим партнёром. Если хорошие, то вас это не коснётся.

Окончание следует…

Источник:
https://dev.to/documatic/pair-programming-best-practices-and-tools-154j
👍13
День 1612. #Карьера
Парное Программирование: Лучшие Практики и Инструменты. Окончание
Начало

Лучшие практики
1. Чёткое определение ролей
Чётко определите роли водителя и штурмана. Водитель пишет код, а штурман проверяет и даёт обратную связь. Часто меняйтесь ролями, чтобы оба разработчика были вовлечены.

2. Эффективная коммуникация
Оба разработчика должны активно участвовать, выражать свои мысли и внимательно слушать. Делитесь идеями, задавайте вопросы и обсуждайте код. Используйте инструменты для совместной работы.

3. Уважение и эмпатия
Цените мнения, идеи и опыт друг друга. Будьте открыты для конструктивной критики и избегайте личных нападок. Создайте среду, которая поощряет сотрудничество и обучение.

4. Перерывы
Важно делать регулярные перерывы, чтобы предотвратить усталость и сохранить продуктивность. Используйте перерывы, чтобы поразмышлять о прогрессе, обсудить проблемы и спланировать следующие шаги. Учитывайте уровень энергии друг друга и соответственно планируйте перерывы.

5. Возможности обучения
Делитесь знаниями и опытом с партнёром. Будьте открыты для новых идей и подходов. Поощряйте непрерывное обучение и рост обоих разработчиков.

6. Активные обзоры кода
Обсуждайте возможные улучшения, заблаговременно выявляйте дефекты и устраняйте недостатки дизайна.

7. Планирование
Перед началом сеанса обсудите и согласуйте цели и задачи. Разбейте работу на более мелкие, управляемые части. Установите сроки и приоритеты задач, чтобы сохранять концентрацию и прогресс.

8. Документирование
Делайте заметки, записывайте важные обсуждения, решения и идеи. Создавайте документацию, которой можно поделиться с командой, помогая распространять знания и обеспечивать согласованность по всему проекту.

9. Выводы
После завершения сеанса найдите время, чтобы обдумать свой опыт. Обсудите, что получилось, а что можно улучшить. Постоянно совершенствуйтесь на основе извлечённых уроков.

Инструменты
Live Share
Расширение VS и VS Code, которое позволяет разработчикам сотрудничать в режиме реального времени.

Replit
Онлайн-инструмент, позволяющий сотрудничать с другими разработчиками в браузере, без необходимости загружать или устанавливать какое-либо дополнительное ПО. Идеален, когда просто нужно отредактировать код вместе с другими в режиме реального времени. Поддерживает более 50 языков программирования.

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

Codeanywhere
Облачная IDE, которая позволяет писать код, сотрудничать и управлять проектами из любого места, используя любое устройство с подключением к Интернету. Предоставляет полный набор инструментов и функций для облегчения написания кода и оптимизации процесса разработки.

CodeTogether
Позволяет создавать и присоединяться к совместным сеансам кодирования из Eclipse, IntelliJ или VS Code. Гости могут присоединиться к сеансу из любой поддерживаемой IDE или из браузера.

Источник: https://dev.to/documatic/pair-programming-best-practices-and-tools-154j
👍5
День 1613. #ЗаметкиНаПолях
Сжатие Ответов в
ASP.NET Core
Уменьшение размера ответа API может заметно повысить производительность вашего приложения. А поскольку пропускная способность сети является ограниченным ресурсом, следует, по крайней мере, рассмотреть преимущества сжатия ответов.

Использовать сжатие ответов в приложениях .NET очень просто. Нужно вызвать два метода:
- AddResponseCompression – для настройки сервисов сжатия ответа;
- UseResponseCompression – для добавления промежуточного ПО сжатия ответа в конвейер.

Сжатие ответов по умолчанию отключено в HTTPS, поэтому его надо явно включить:
builder.Services
.AddResponseCompression(opts =>
{
opts.EnableForHttps = true;
});

Когда использовать
В идеале лучше использовать серверное сжатие ответа, если ваш сервер приложений (IIS, Apache, Nginx) поддерживает его. Если сервер не поддерживает сжатие ответов, то оправдано использование промежуточного ПО. Однако т.к. оно происходит на уровне приложения, производительность обычно падает.

Еще одной проблемой является безопасность, т.к. использование сжатия ответов в HTTPS может подвергнуть вас атакам CRIME и BREACH. Вот что можно сделать, чтобы защититься от них:
- Добавить токены защиты от подделки (anti-forgery).
- Не отправлять секреты приложения в теле запроса.
- Добавить ограничитель трафика

Настройка провайдеров сжатия
При вызове AddResponseCompression по умолчанию добавляются два провайдера сжатия (но можно добавить свои в настройках AddResponseCompression):
- BrotliCompressionProvider
- GzipCompressionProvider
По умолчанию используется сжатие Brotli, если оно поддерживается клиентом. В противном случае будет использоваться Gzip. Можно настроить уровень сжатия для Brotli и Gzip:
- Optimal,
- Fastest (по умолчанию),
- NoCompression,
- SmallestSize.

builder.Services
.Configure<BrotliCompressionProviderOptions>(opts =>
{
opts.Level = CompressionLevel.Optimal;
});
Заметим, что уровень SmallestSize ожидаемо имеет сильное негативное влияние на время ответа.

Итого
Сжатие ответов — хороший метод повышения производительности API и снижения сетевых затрат. В идеале желательно использовать серверное сжатие ответов, если оно поддерживается вашим сервером приложений. Если нет, сжатие ответов в приложении доступно в .NET через промежуточное ПО.
Это увеличивает нагрузку на ЦП и может подвергнуть HTTPS некоторым рискам безопасности, но есть способы смягчить это.
Обычно конфигурации по умолчанию для провайдера сжатия и уровня сжатия дают отличные результаты.
Вы можете протестировать значение сжатия ответа в своём приложении и изучить изменения в размере и времени ответа. Попробуйте разные провайдеры сжатия, изменяя заголовок Accept-Encoding клиента, а также настраивая разные уровни сжатия в приложении.

Источник: https://www.milanjovanovic.tech/blog/response-compression-in-aspnetcore
👍10
День 1614. #ЧтоНовенького
Новинки Превью 5 .NET 8
Продолжаем рассматривать, что нового появилось в превью 5 8й версии .NET.

1. IHttpSysRequestTimingFeature
Новый интерфейс IHttpSysRequestTimingFeature предоставляет подробные данные о временных метках, связанных с обработкой запросов при использовании сервера HTTP.sys. Раньше информация о запросе HTTP.sys предоставлялась через интерфейс IHttpSysRequestInfoFeature. С добавлением IHttpSysRequestTimingFeature мы движемся к более чётко определённым API, которые обеспечивают лучший доступ к данным о времени запроса.
namespace Microsoft.AspNetCore.Server.HttpSys
{
public interface IHttpSysRequestTimingFeature
{
ReadOnlySpan<long> Timestamps { get; }
bool TryGetTimestamp(
HttpSysRequestTimingType timestampType,
out long timestamp);
bool TryGetElapsedTime(
HttpSysRequestTimingType startingTimestampType,
HttpSysRequestTimingType endingTimestampType,
out TimeSpan elapsed);
}
}

Свойство Timestamps предоставляет доступ ко всем временным меткам HTTP.sys. Временные метки получаются с помощью QueryPerformanceCounter, а частота временных меток может быть определена с помощью QueryPerformanceFrequency.

Метод TryGetTimestamp извлекает метку времени для предоставленного типа времени, а метод TryGetElapsedTime даёт время, прошедшее между двумя указанными временами.

Это усовершенствование предоставляет разработчикам:
- Более детальное понимание различных этапов обработки запросов.
- Возможности точной диагностики производительности.
- Улучшенный доступ к данным о времени запросов HTTP.sys и контроль над ними.

2. Имя хоста в ITlsHandshakeFeature
Имя хоста Server Name Indication (SNI) теперь доступно в интерфейсе ITlsHandshakeFeature.

/// <summary>
/// Gets the host name from the "server_name" (SNI) extension of the client hello if present.
/// See <see href="https://www.rfc-editor.org/rfc/rfc6066#section-3">RFC 6066</see>.
/// </summary>
string? HostName => null;

SNI является частью процесса TLS-рукопожатия и позволяет клиентам указывать имя хоста, к которому они пытаются подключиться. Это позволяет серверам, на которых размещается несколько виртуальных хостов или доменов, предоставлять правильный сертификат безопасности во время процесса установки связи, следовательно, позволяет работать нескольким HTTPS-сайтам (или другим сервисам поверх TLS) на одном IP-адресе без использования одного и того же сертификата для всех сайтов. Обычно SNI обрабатывается только в стеке TLS и используется для выбора соответствующего сертификата, но теперь раскрытие имени хоста позволяет другим компонентам приложения использовать эту информацию для диагностики, ограничения скорости, маршрутизации и т. д.

Предоставление имени хоста особенно полезно для крупномасштабных сервисов, управляющих тысячами привязок SNI. С помощью этой функции вы получаете ценную информацию о выбранном SNI во время TLS-рукопожатия, тем самым значительно улучшая свои возможности отладки при росте количества клиентов. Это позволяет быстрее решать проблемы и повышать надёжность обслуживания.

Источник: https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-5/#servers
👍8