Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин
GetOrAdd для кэширования, когда вы запрашиваете элемент из кэша, предоставляя при этом функциональность для его добавления, если элемент отсутствует.
LazyCache отлично подходит для кэширования вызовов базы данных, процедур построения сложных графов объектов и вызовов веб-сервисов, которые нужно временно сохранить для повышения производительности. Пакет позволяет кэшировать элементы в течение большего или меньшего времени, но по умолчанию он сохраняет кэшированные элементы до 20 минут.
Ключевые особенности LazyCache:
- Потокобезопасен и готов для использования в параллельном коде.
- Совместим с асинхронным кодом: доступна ленивая однократная оценка асинхронных делегатов с использованием метода GetOrAddAsync().
Всего загрузок: 7,3 млн.
Источник: www.syncfusion.com/blogs/p…aspx/ampCallerArgumentExpression. Он позволяет записывать выражение, переданное в качестве параметра, в виде строки (см. рисунок). Как и другие атрибуты CompilerServices, он применяется к необязательному параметру.
Кстати, его использует новый метод
ArgumentNullException.ThrowIfNull(nullArg);в .NET без явной передачи имени. Если раньше нам нужно было писать что-то подобное:
public bool DoSomething(string id, string name)
{
if (id is null)
throw new ArgumentNullException(nameof(id));
if (name is null)
throw new ArgumentNullException(nameof(id));
// ...
}
Теперь новый метод позволяет писать более чистый код:
public bool DoSomething(string id, string name)
{
ArgumentNullException.ThrowIfNull(id);
ArgumentNullException.ThrowIfNull(name);
// ...
}
Источник: twitter.com/Nick_Cr…49448459Parallel использует концепцию локальных значений — переменных, существующих локально внутри параллельного цикла. Это означает, что тело цикла может просто обратиться к значению напрямую, без необходимости синхронизации. Когда цикл готов к агрегированию всех своих локальных результатов, он делает это с помощью делегата localFinally. Следует отметить, что делегату localFinally нужно синхронизировать доступ к переменной для хранения результата. Пример параллельного суммирования:
int ParallelSum(IEnumerable<int> values)
{
int result = 0;
Parallel.ForEach(source: values,
localInit: () => 0,
body: (item, state, localValue) =>
localValue + item,
localFinally: localValue =>
Interlocked.Add(ref result, localValue)
);
return result;
}
В Parallel LINQ реализована более понятная поддержка агрегирования, чем в классе Parallel:
int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Sum();
}
На самом деле в PLINQ реализована встроенная поддержка многих распространённых операторов (например, Sum). Также предусмотрена обобщённая поддержка агрегирования с оператором Aggregate:
int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Aggregate(
seed: 0,
func: (sum, item) => sum + item
);
}
Если вы уже используете класс Parallel, следует использовать его поддержку агрегирования. В остальных случаях поддержка в PLINQ, как правило, более выразительна, а код получается короче.
UPD: Обновил пример ParallelSum примером из документации с использованием Interlocked.Add вместо lock.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 4.dotnet tool install -g upgrade-assistantАнализ Если вы выполните команду
upgrade-assistant analyzeвам будут предоставлены инструкции по тому, как будет выглядеть обновление. Инструкции включают в себя: - Какую целевую платформу (TFM) следует использовать для проекта? - Нужно ли обновлять какие-либо зависимости проекта? - Необходимо ли внести существенные изменения в код для обновления? - И многое другое! Во всех этих случаях помощник по обновлению скажет вам, что нужно сделать, и внесёт столько изменений, сколько сможет. Обновление Обновление похоже на анализ, за исключением того, что вам предоставляется возможность пропустить этап или выполнить действие. См. картинку ниже. Например, первым шагом является резервное копирование всех проектов. Если ваши проекты в Git, можно пропустить этот шаг. Также есть возможность предоставить более подробную информацию о каждом шаге. Если вы не уверены, будет ли этот этап дорогостоящим или вызовет нарушение работы кода, помощник по обновлению сообщит вам об этом. FAQ 1. Он работает с решениями или только с отдельными проектами? В решении помощник попросит указать точку входа для приложения. После этого он изучит все зависимости, их зависимости и наметит лучший способ выполнить обновление. Возможно, придётся повторить этот процесс для дополнительных точек входа для решения (приложение MVC, приложение функций Azure, API и т.п.). 2. Какие языки поддерживаются? C# и Visual Basic полностью поддерживаются! 3. С чем ещё может помочь инструмент? Upgrade Assistant может помочь со следующими типами проектов: - ASP.NET MVC - Windows Forms - Windows Presentation Foundation (WPF) - Консольные приложения - Библиотеки классов 4. Что насчёт других типов проектов? Вы, вероятно, заметили, что веб-формы ASP.NET отсутствуют в приведённом выше списке. Они входят в дорожную карту проекта вместе со многими другими функциями! Источник: consultwithgriff.com/rapid-p…ssistant
await foreach (int result in GetAsyncRange())
{
Console.WriteLine(result);
if (result >= 8)
break;
}
Часто бывает полезно отменять сами асинхронные потоки, передав маркер отмены потоку-источнику. Async метод, возвращающий IAsyncEnumerable<T>, может получать маркер отмены, который должен быть помечен атрибутом EnumeratorCancellation. После этого маркер можно использовать естественным образом:
async IAsyncEnumerable<int> GetAsyncRange(
[EnumeratorCancellation] CancellationToken ct = default)
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(100, ct);
yield return i;
}
}
using var cts = new CancellationTokenSource(500);
CancellationToken token = cts.Token;
await foreach (int result in GetAsyncRange(token)) {
Console.WriteLine(result);
}
В этом примере CancellationToken передается непосредственно методу, возвращающему асинхронный перечислитель. Это самый распространенный вариант использования.
Возможны и другие сценарии, когда маркер отмены применяется к перечислителю. Это нетипичный, но важный сценарий использования. По этой причине асинхронные потоки поддерживают метод расширения WithCancellation, который может использоваться для присоединения маркера отмены к конкретной итерации асинхронного потока:
async Task ConsumeSequence(IAsyncEnumerable<int> items)
{
using var cts = new CancellationTokenSource(500);
CancellationToken ct = cts.Token;
await foreach (int item
in items.WithCancellation(ct))
{
Console.WriteLine(item);
}
}
await ConsumeSequence(GetAsyncRange());
Примечания:
1. Заметьте, что GetAsyncRange() вызывается без токена отмены. При наличии атрибута EnumeratorCancellation компилятор автоматически обеспечит передачу маркера из WithCancellation параметру метода GetAsyncRange, помеченному атрибутом EnumeratorCancellation.
2. В нынешнем виде отменённое перечисление выбрасывает TaskCanceledException, которое нужно обработать в клиентском коде.
3. Метод расширения WithCancellation не препятствует ConfigureAwait(false). Оба метода расширения могут быть объединены в цепочку:
… items.WithCancellation(ct).ConfigureAwait(false)) …
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 3.WebApplication.CreateBuilder(). Во всех предыдущих версиях ASP.NET Core конфигурация разделена на 2 файла: Program.cs и Startup.cs (см. рисунок ниже). В .NET 6 добавлено множество изменений в C#, BCL и ASP.NET Core, и теперь всё может быть в одном файле.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseStaticFiles();
app.MapGet("/", () => "Hello World!");
app.MapRazorPages();
app.Run();
WebApplicationBuilder
Для начала рассмотрим WebApplicationBuilder.
var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages();Он отвечает за 4 основные вещи: 1. Добавление конфигурации с помощью
builder.Configuration. Он предоставляет тип ConfigurationManager для добавления новых источников конфигурации, а также для доступа к значениям конфигурации, как я описал в предыдущем посте.
2. Добавление сервисов с помощью builder.Services. Предоставляет доступ к IServiceCollection напрямую для добавления сервисов в контейнер DI.
3. Аналогично для журнала с помощью builder.Logging. Вы можете использовать, Например:
builder.Logging.AddFile();4. Общая конфигурация
IHostBuilder и IWebHostBuilder. Для тех точек расширения, которые напрямую зависят от IHostBuilder или IWebHostBuilder, WebApplicationBuilder предоставляет свойства Host и WebHost соответственно. Например, настройка Serilog для ASP.NET Core подключается к IHostBuilder. С помощью WebApplicationBuilder вы можете вызвать UseSerilog() на свойстве Host:
builder.Host.UseSerilog();Фактически,
WebApplicationBuilder – это то место, где вы выполняете всю настройку, кроме конвейера промежуточного ПО.
WebApplication
После того, как вы настроили всё необходимое в WebApplicationBuilder, вы вызываете Build() для создания экземпляра WebApplication:
var app = builder.Build();
WebApplication реализует несколько различных интерфейсов:
- IHost – для запуска и остановки хоста.
- IApplicationBuilder – для создания конвейера промежуточного ПО.
- IEndpointRouteBuilder – для добавления конечных точек.
Два последних пункта во многом связаны. В ASP.NET Core 3.x и 5 IEndpointRouteBuilder используется для добавления конечных точек путем вызова UseEndpoints() и передачи ему лямбды, например:
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
WebApplication значительно упрощает этот шаблон:
app.UseStaticFiles(); app.MapRazorPages();Это явно намного проще, хотя немного обманчиво, поскольку различие между промежуточным ПО и конечными точками гораздо менее очевидно, чем в .NET 5.x. Вероятно, это просто дело вкуса, но такой подход несколько размывает концепцию важности порядка настройки (которая относится к промежуточному ПО, но не к конечным точкам). Подробнее перевод статьи с примерами кода размещён на Хабре. Источник: andrewlock.net/explori…ric-host
1–15 дней - Дни 3–6 недель - Недели 8–20 недель - Месяцы 20+ недель - Хорошо подумайте, перед тем, как оцениватьХотя бизнесу нравится рассматривать оценки как обязательства, помните, что оценка — это всего лишь предположение, поэтому никаких обязательств не подразумевается. Обязательство — нечто такое, что вы обязаны сделать. Если вы обязуетесь сделать что-то к определённой дате, то к этой дате «что-то» должно быть готово. <…> Профессионалы не принимают на себя обязательств, если только они не уверены в возможности их выполнения. <…> Нарушение обязательств обернется огромным ущербом для вашей репутации; это проявление непорядочности, лишь немногим лучшее открытой лжи. — Идеальный программист Таким образом, чтобы помочь бизнесу в оценке требований и составлении соответствующих планов, вы должны устранить двусмысленность требования перед проведением оценки. А впоследствии информировать бизнес о вашем прогрессе. Чтобы свести к минимуму проблемы, связанные с отставанием, помните о двух важнейших аспектах: раннем обнаружении и прозрачности. Будьте по возможности честны в своих оценках. Оптимизму в них не место! — Идеальный программист Не изобретайте велосипед, используйте известные методики оценивания задач. Вот некоторые техники оценки, упомянутые в этих книгах: - PERT - Широкополосный дельфийский метод - Метод быстрого голосования - Покер планирования - Аффинная оценка - Анализ по трем переменным - Закон больших чисел Чем больше у вас опыта работы над тем или иным проектом, тем точнее вы оцените его задачи. Поэтому не беспокойтесь, если ваши первые оценки окажутся не такими точными, как могли бы быть. Это постепенный процесс, как и с любой долгосрочной целью, которой вы хотите достичь. Продолжение следует… Источник: www.freecodecamp.org/news/le…an-coder
ConfigurationManager был добавлен для поддержки новой модели WebApplication в ASP.NET. Однако он во многом является деталью реализации.
В .NET5 двумя основными типами конфигурации:
- IConfigurationBuilder - для добавления источников конфигурации. Вызов Build() считывает каждый из источников конфигурации и строит окончательную конфигурацию.
- IConfigurationRoot - представляет собой окончательную «построенную» конфигурацию.
Поставщики конфигурации обычно включают методы расширения (например, AddJsonFile() и AddAzureKeyVault()), которые добавляют источник конфигурации в список источников. IConfigurationRoot в свою очередь объединяет все значения из каждого источника конфигурации, чтобы дать окончательное представление всех значений.
Проблема "частичной сборки конфигурации" в .NET 5
Основная проблема с этим подходом проявляется, когда вам нужно построить конфигурацию «частично». Это распространённая проблема, когда вы храните свою конфигурацию в таком сервисе, как Azure Key Vault, или в базе данных. Рекомендуемый подход состоит в следующем:
- Добавить «начальные» значения конфигурации.
- Создать «частичный» результат конфигурации, вызвав IConfigurationBuilder.Build()
- Получить необходимые значения конфигурации из построенного IConfigurationRoot
- Использовать эти значения, чтобы добавить оставшиеся источники конфигурации
- Фреймворк неявно вызывает IConfigurationBuilder.Build(), генерируя окончательный IConfigurationRoot и используя его для окончательной конфигурации приложения.
Таким образом конфигурация из начальных источников загружается дважды, что может негативно повлиять на производительность.
Менеджер Конфигурации в .NET 6
В .NET 6 добавлен новый тип конфигурации, ConfigurationManager. Он реализует как IConfigurationBuilder, так и IConfigurationRoot, позволяя оптимизировать сценарий, описанный выше.
В ConfigurationManager, когда добавляется IConfigurationSource (например, когда вы вызываете AddJsonFile()), поставщик сразу загружается, и конфигурация обновляется. Это позволяет избежать загрузки источников конфигурации более одного раза в сценарии частичной сборки.
Однако ConfigurationManager оптимизирован для наиболее распространённого сценария – только добавление источников. Если какой-либо из источников изменится, ConfigurationManager должен удалить всё и начать заново, перебирая каждый из источников и перезагружая их.
Стоит ли вам беспокоиться о том, используете ли вы ConfigurationManager или ConfigurationBuilder? Скорее нет.
Новый WebApplicationBuilder, представленный в .NET 6, использует ConfigurationManager, оптимизированный для описанного выше случая, когда вам необходимо частично построить конфигурацию.
Однако WebHostBuilder или HostBuilder, представленные в более ранних версиях ASP.NET, по-прежнему поддерживаются в .NET 6, и они по-прежнему «за кулисами» используют типы ConfigurationBuilder и ConfigurationRoot.
Подробнее перевод статьи с примерами кода размещён на Хабре.
Источник: andrewlock.net/explori…dotnet-6async IAsyncEnumerable<int> GetAsyncRange()
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(100);
yield return i;
}
}
IAsyncEnumerable<T> включает поддержку LINQ в NuGet-пакете System.Linq.Async. Заметьте, что при этом в коде нужно использовать
using static System.Linq.AsyncEnumerable;Операторы LINQ можно применять к асинхронным потокам. Доступны все знакомые операторы:
Where, Select, SelectMany, Join и т.д. Результат представляет собой асинхронный поток:
IAsyncEnumerable<int> values =
GetAsyncRange().Where(value => value % 2 == 0);
await foreach (int result in values) {
Console.WriteLine(result);
}
Но что, если нам нужно передать в Where асинхронный предикат? Where их не поддерживает. Но есть подходящий оператор WhereAwait:
IAsyncEnumerable<int> values =
GetAsyncRange().WhereAwait(
async value => {
// Асинхронная работа для определения,
// должен ли элемент быть включён в результат
await Task.Delay(10);
return value % 2 == 0;
});
Методы LINQ для асинхронных потоков можно использовать и для обычных перечисляемых объектов, вызвав ToAsyncEnumerable() для любого IEnumerable<T>. Результат можно использовать с WhereAwait, SelectAwait и другими операторами, принимающими асинхронные делегаты.
Операторы LINQ для асинхронных потоков могут оканчиваться суффиксами Async и Await. Операторы, заканчивающиеся суффиксом Async, возвращают обычное значение, допускающее ожидание. Операторы с суффиксом Await получают асинхронный делегат. Т.е. Await в имени подразумевает, что они используют await внутри переданного делегата.
Пример WhereAwait был приведёт выше.
Суффикс Async применяется только к операторам терминации (termination operators), которые извлекают некоторое значение или выполняют некоторые вычисления и возвращают асинхронное скалярное значение. Пример такого оператора — CountAsync, версия Count для асинхронного потока, которая может подсчитать количество элементов, соответствующих некоторому предикату:
int count = await GetAsyncRange() .CountAsync(value => value % 2 == 0);Предикат может также быть асинхронным. В этом случае используется метод
CountAwaitAsync, поскольку он получает асинхронного делегата и производит одно терминальное значение:
int count = await GetAsyncRange().CountAwaitAsync(
async value => {
await Task.Delay(10);
return value % 2 == 0;
});
Итого
- Операторы без суффиксов (Where, Select) получают синхронные делегаты и выдают асинхронную последовательность.
- Операторы, которые получают асинхронные делегаты, имеют суффикс Await (WhereAwait, SelectAwait), и выдают асинхронную последовательность.
- Операторы, возвращающие терминальное значение, имеют суффикс Async (CountAsync), а также могут иметь суффикс Await, если получают асинхронный делегат (CountAwaitAsync).
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 3.<text> и автозаполнение. Новый редактор также изменяет способ диагностики, чтобы гарантировать отображение только наиболее важных диагностических сообщений.
6. Razor теперь полностью поддерживает Visual Studio Live Share.
Известные проблемы и дорожная карта
Razor накопил большое количество запросов на добавление функций и исправлений ошибок. Решение этих проблем в устаревшем редакторе Razor было трудным и дорогостоящим. Новый редактор позволит быстрее предоставлять исправления ошибок и новые функции. Есть ещё несколько функциональных пробелов, которые необходимо устранить в следующих выпусках:
- Поддержка сниппетов (с помощью Tab)
- Горячая клавиша «Обернуть в div» - Shift+Alt+W
- Ctrl+щелчок мыши для перехода к определению
- Сворачивание кода в #region
- Встроенное форматирование JavaScript
- Поддержка перетаскивания файлов HTML, CSS и JavaScript
- Улучшения производительности и надёжности
- Поддержка горячей перезагрузки для проектов Blazor Web Assembly при отладке
Следить за дорожной картой вы можете на GitHub.
Если вы обнаружите, что ваша продуктивность в новом редакторе ограничена, вы можете вернуться к предыдущей версии редактора, перейдя в Tools > Options > Text Editor > HTML > Advanced (Инструменты > Параметры > Текстовый редактор > HTML > Дополнительно) и выбрав True в раскрывающемся списке рядом с пунктом Use legacy Razor editor for ASP.NET Core (Использовать устаревший редактор Razor для ASP.NET Core). Имейте в виду, что старый редактор Razor будет иметь ограниченную функциональность и не будет включать улучшения, описанные выше.
Источник: devblogs.microsoft.com/visuals…dio-2022