.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
День 1285. #NuGet
Генерация Сортируемых Guid с Помощью NewId. Окончание
Начало

NewId вместо полностью случайных Guid предоставляет UUID, который можно легко отсортировать. Рассмотрим простое приложение:
using MassTransit;

foreach (var i in Enumerable.Range(0, 5))
{
NewId id = NewId.Next();
Console.WriteLine(id);
}

Эта программа генерирует 5 идентификаторов. В результате получается что-то вроде этого:
be170000-f32d-18db-de59-08da26f2ad5a
be170000-f32d-18db-1816-08da26f2ad5b
be170000-f32d-18db-8694-08da26f2ad5b
be170000-f32d-18db-4dbd-08da26f2ad5b
be170000-f32d-18db-65b3-08da26f2ad5c

На первый взгляд может показаться, что все они одинаковы, но давайте разобьём первый экземпляр на 3 части:
- be170000-f32d-18db — очевидно, это постоянное значение для всех идентификаторов.
- de59 — меняется с каждым ID.
- 08da26f2ad5a — иногда меняется, и меняется постепенно.

NewId использует 3 разных источника для создания идентификатора:
1. ID машины/процесса – константа для данной машины (может быть настроена для включения идентификатора процесса).
2. Временную метку - обеспечивает базовый порядок идентификатора.
3. Последовательность - увеличивающийся идентификатор.

Объединив все 3 вместе, вы можете получить идентификатор, который (с натяжкой) упорядочен благодаря компоненту метки времени. Включив идентификатор рабочего процесса, вы можете заставить процессы генерировать независимые ID, избегая при этом коллизий. Это можно сделать, например, вызвав в начале программы:
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());

А использование «последовательности» означает, что вы можете генерировать 2^16-1 идентификаторов в миллисекунду для каждого процесса/машины.

Очевидно, что такие ID приводят к гораздо менее фрагментированному индексу базы данных. Конечно, с идеально последовательными целыми числами они не сравнятся. Но сравнение индексов в оригинальной статье показало, что полностью случайные Guid приводят к почти 99% фрагментации индекса, тогда как фрагментация индекса NewId составляет лишь 5%.

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

Идентификаторы, сгенерированные NewId, раскрывают личность машины, сгенерировавшей идентификатор (фактически, это её MAC-адрес), и время, когда она это сделала. Это может быть проблемой для некоторых чувствительных к безопасности приложений.

Источник: https://andrewlock.net/generating-sortable-guids-using-newid/
👍16
День 1286. #ЗаметкиНаПолях #AsyncTips
Реагирование на Запросы на Отмену Посредством Периодического Опроса

Задача
: В коде имеется цикл, который должен поддерживать отмену.

Решение
Если в коде присутствует цикл обработки, то в нём нет низкоуровневых функций API, которым можно было передать CancellationToken. В этом случае необходимо периодически проверять, не был ли отменён токен. Следующий пример периодически проверяет токен в ходе выполнения цикла, создающего вычислительную нагрузку на процессор:
public int Cancelable(CancellationToken ct)
{
for (int i = 0; i != 100; ++i)
{
Thread.Sleep(1000); // вычисления
ct.ThrowIfCancellationRequested();
}
return 42;
}

Если тело цикла выполняется очень быстро, то, возможно, стоит ограничить частоту проверки токена отмены. Измерьте быстродействие до и после таких изменений, чтобы выбрать лучший вариант. Следующий пример похож на предыдущий, но выполняет больше итераций более быстрого цикла, поэтому добавлено ограничение на частоту проверки маркера:
public int Cancelable(CancellationToken ct)
{
for (int i = 0; i != 100000; ++i)
{
Thread.Sleep(1); // вычисления
if (i % 1000 == 0)
ct.ThrowIfCancellationRequested();
}

return 42;
}

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

В большинстве случаев ваш код должен просто передать CancellationToken на следующий уровень. Метод периодического опроса (polling), использованный в этом рецепте, следует применять только в том случае, если у вас имеется вычислительный цикл, который должен поддерживать отмену.

У типа CancellationToken имеется другой метод IsCancellationRequested, который начинает возвращать true при отмене токена. Некоторые разработчики используют его для реакции на отмену, обычно возвращая значение по умолчанию или null. В большинстве случаев использовать этот метод не рекомендуется. В стандартном паттерне отмены выдаётся исключение OperationCanceledException, для чего вызывается метод ThrowIfCancellationRequested. Если код, находящийся выше в стеке, захочет перехватить исключение и действовать так, словно результат равен null, это нормально, но любой код, получающий CancellationToken, должен следовать стандартному паттерну отмены. Если вы решите не соблюдать паттерн отмены, по крайней мере чётко документируйте свои намерения.

Работа метода ThrowIfCancellationRequested основана на периодическом опросе токена отмены; ваш код должен вызывать его с регулярными интервалами. Также существует способ регистрации обратного вызова, который вызывается при запросе на отмену. Об этом в будущих постах.

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
👍4
День 1287. #ЗаметкиНаПолях
Рекомендации по Обеспечению Безопасности Проектов на GitHub
Сегодня ПО подвержено постоянно меняющемуся набору угроз. Вот как вы можете защитить свои проекты на GitHub.

Средний проект на GitHub напрямую использует около 10 зависимостей с открытым исходным кодом. Это, наверное, неудивительно, но удивительно, что тот же репозиторий использует более 600 транзитивных зависимостей, которые получаются из 10 прямых зависимостей.

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

GitHub предоставляет ряд встроенных инструментов, предназначенных для помощи в управлении деревом зависимостей, включая граф зависимостей и проверку зависимостей.

1. Для каждого репозитория граф зависимостей показывает зависимости, экосистемы и пакеты, на которых основана каждая зависимость. Граф зависимостей можно посмотреть на вкладке Insights вашего репозитория.
Подробнее про граф зависимостей.

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

3. При помощи Dependabot вы можете не только обнаруживать уязвимые зависимости, но и исправлять их. Он автоматически проверяет ваши файлы зависимостей на наличие устаревших зависимостей и открывает для каждой отдельный пул реквест. Затем он уведомляет вас и предлагает исправления, позволяя вам всегда работать с последними и наиболее безопасными выпусками.

Оповещения Dependabot можно включить как в общедоступных, так и в частных репозиториях. Вы также можете настроить уведомления, чтобы получать только те уведомления, которые вам нужны, и ничего больше. Кроме того, вы можете увидеть все оповещения, которые влияют на конкретный проект, на вкладке безопасности или в графе зависимостей.

Чтобы включить Dependabot, на главной странице репозитория под именем репозитория нажмите на вкладку Settings (Настройки). В левой боковой панели нажмите на Code security and analysis (Безопасность и анализ кода). На этой странице включите Dependency graph (Граф зависимостей), (Dependabot alerts) Предупреждения Dependabot и Dependabot security updates (Обновления безопасности Dependabot).
После этого GitHub предложит вам добавить файл dependabot.yml в папку .github вашего репозитория. В этом файле вам нужно будет настроить параметр package-ecosystem - "nuget" для проектов на .NET и schedule > interval – для желаемой частоты проверок.

Источник: https://github.blog/2022-04-28-best-practices-to-keep-your-projects-secure-on-github/
👍5
DotNext возвращается!

В ноябре JUG Ru Group организует конференцию для .NET‑разработчиков — DotNext 2022 Autumn. В программе — технические доклады и дискуссии об архитектуре, производительности, безопасности, фреймворках и инструментах.

Участники конференции любят обсуждать нетривиальные задачи и новые подходы в .NET‑разработке. И если вам есть что сказать, тогда подавайте заявку на выступление: https://bit.ly/3zDv3Zk

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

Всем спикерам JUG Ru Group дарит билет на все конференции сезона в онлайне и офлайне.

А билеты можно купить здесь: https://bit.ly/3Qdd5np
👍5
День 1288. #TypesAndLanguages
6. Запрещать или Разрешать при Разработке ПО
Дискуссии в области разработки ПО довольно часто касаются личных предпочтений. Несмотря на то, что все участники дебатов спорят, основываясь на своих знаниях, навыках или опыте, их дискуссии довольно часто сводятся к вопросу вкуса и цвета.

Одним из примеров является спор «Открытое Наследование или Разрешённое Наследование» Мартина Фаулера. Вопрос в том, должны ли мы по умолчанию разрешать наследование класса или блокировать его. Мы можем привести множество аргументов за и против, но нет единого показателя, показывающего, какой подход лучше. То же самое относится к тому, чтобы сделать методы виртуальными или запечатанными по умолчанию. Или о том, насколько всё делать приватным или открытым. Эти дискуссии, как правило, основаны на личном ощущении участников дебатов, и может быть довольно занимательно узнавать аргументацию, стоящую за каждым из вариантов.

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

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

То же самое относится и к разработке ПО. Допустим, вы нашли ошибку в длинной функции, меняющей состояние приложения. Что вы сделаете? Варианты:
1. Вы решаете, что вы и ваша команда больше не будете так писать. Вы делаете акцент на обзорах кода, чтобы не пропускать такие функции.
2. Вы решаете, что такие функции вообще нельзя разрешать. Вы меняете свой стек на использование чистых функций (например, на F# или Haskell).
3. Вы просто улучшаете свои навыки, чтобы лучше поддерживать длинные функции, меняющие состояние приложения.

Похоже, что индустрия обычно выбирает первый вариант. В сети можно много прочитать о «чистом коде». Такие принципы, как «метод должен иметь не более двух параметров», подкрепляются такими утверждениями, как «Я работаю в отрасли уже 30 лет, поэтому я знаю лучше». Однако в итоге это просто вопрос личных предпочтений. На предпочтение могут влиять когнитивные навыки, окружающая среда, опыт, мастерство, риск, стоимость и, возможно, многие другие причины. Однако нет метрик, показывающих, что «контейнеры DI — это плохо» (как говорят Java-программисты, в то время как .NET-программисты получают поддержку DI «из коробки» в .NET Core), «функции должны иметь длину не более 10 строк» ​​(а затем вы видите, что пул реквесты в коде ядра Linux делают совершенно по-другому), или «чистые функции лучше, чем нечистые» (а затем вы заворачиваете свой код в морской узел, чтобы создать конечный автомат без состояния в нём).

Должны ли мы запрещать или разрешать? Я склоняюсь к последнему. Но опять же, это вопрос предпочтений.

Источник: https://blog.adamfurmanek.pl/2022/07/16/types-and-programming-languages-part-15/
👍10
День 1289. #ЗаметкиНаПолях
Хранение Динамических Данных с Помощью EF Core. Начало
Рассмотрим, как можно хранить «динамические» пользовательские данные с помощью Entity Framework Core. Динамические в том смысле, что вы можете не знать, какими будут пары данных ключ/значение, но их по-прежнему важно сохранить. На ум приходят два способа, каждый со своими преимуществами и недостатками. Сегодня рассмотрим первый.

1. Использование сериализации/десериализации JSON
В Entity Framework Core вы можете использовать методы преобразования для сериализации данных при записи в базу данных и десериализации данных при чтении из таблицы.

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

Недостатки:
- сериализация/десериализация может быть дорогостоящей,
- вы либо получаете все пользовательские значения, либо ничего (нельзя выбрать, какие значения возвращаются в запросе).

Настройка
Во-первых, определим объект для хранения:
public class Entity
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
= DateTime.UtcNow;
public Dictionary<string, string>
Values { get; set; } = new();
}

Dictionary<string,string> выбран ради простоты использования с System.Text.Json, в котором нет конвертера для Dictionary<string,object>. Хотя конвертер можно написать, как это сделал Йозеф Оттоссон в своем блоге.

Следующий шаг — настроить преобразование как часть конфигурации EF Core. Здесь используется SQLite, но это должно работать с любой реляционной базой данных, которая может хранить текст в столбце.
public class Database : DbContext
{
public DbSet<Entity> Entity { get; set; }

protected override void
OnModelCreating(ModelBuilder mb)
{
var opts = new JsonSerializerOptions(
JsonSerializerDefaults.General);

mb.Entity<Entity>()
.Property(x => x.Values)
.HasColumnName("Values")
.HasColumnType("BLOB")
.HasConversion(
v => JsonSerializer.Serialize(v, options),
s => JsonSerializer
.Deserialize<Dictionary<string, string>>(s, options),
ValueComparer.CreateDefault(
typeof(Dictionary<string, string>), true)
);
}
}

Для использования в коде, как и в любом словаре, нам нужно только предоставить словарю пару ключ/значение:
var json = new Entity
{
Values = new()
{
{"Name", "Dotnet"},
{"Status", "Awesome"}
}
};

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

Источник:
https://khalidabuhakmeh.com/storing-dynamic-user-data-with-ef-core
👍7
День 1290. #ЗаметкиНаПолях
Хранение Динамических Данных с Помощью EF Core. Окончание
Начало

2. Хранение пользовательских данных в инвертированной таблице
Инвертированные таблицы — это когда мы храним пары ключ/значение в отдельных строках. В этом случае ключи и значения становятся столбцами, что обеспечивает гибкость.

Преимущества такого подхода:
- Мы можем хранить «бесконечное» количество пользовательских данных.
- Мы можем отфильтровать отдельные строки, чтобы получить одно значение.
- Мы можем реализовать логику уникальности ключей для каждой сущности.

Недостатки:
- Столбцы значений должны иметь строгий тип, скорее всего строковый тип.
- Эти таблицы могут быстро расти в зависимости от объема пользовательских данных.

Настройка
Настройка инвертированной таблицы не отличается от типичных отношений «один ко многим».
public class Entity
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
= DateTime.UtcNow;
public ICollection<Values> Values { get; set; }
= new List<Values>();

public Entity AddValue(string name, string value)
{
var existing = Values?.
FirstOrDefault(v => v.Name.Equals(name));

if (existing is { })
existing.Value = value;
else
Values?.Add(
new Values {Name = name, Value = value}
);

return this;
}
}

public class Values
{
public int Id { get; set; }
public int EntityId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}

Метод AddValue в типе Entity будет работать с оговоркой, что у вас есть все значения из связанной таблицы Values в памяти. Если нет, вы получите повторяющиеся пары ключ/значение в своей коллекции.

Посмотрим, как сохранить эти пользовательские значения:
var invertedTable = new Entity()
.AddValue("Name", "Dotnet")
.AddValue("Status", "Awesome");

Разница с первым методом в том, что подход с инвертированной таблицей требует включения значений при чтении сущностей из базы данных:
var invertedTable = db
.EntityWithInvertedTables
.OrderByDescending(o => o.CreatedAt)
.Include(x => x.Values)
.First();

Вызов Include загрузит все значения из связанной таблицы. Хотя, вы можете загрузить только нужные значения (но помните, что в этом случае метод сущности AddValue перестанет корректно работать):

.Include(x => x.Values.Where(v => v.Name == "Name"))
.First();

Источник: https://khalidabuhakmeh.com/storing-dynamic-user-data-with-ef-core
👍3
День 1291. #ЧтоНовенького
Миграция из
ASP.NET в ASP.NET Core в Visual Studio
Я уже писал про экспериментальное расширение для Visual Studio Microsoft Project Migrations, которое позволяет обновить ваши проекты ASP.NET на ASP.NET Core. Сегодня подробнее про процесс обновления.

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

В Visual Studio после установки расширения щёлкните правой кнопкой на проект и выберите Migrate Project. При этом
- Новый проект ASP.NET Core создаётся и добавляется в решение.
- Проект ASP.NET Core уже настроен с помощью YARP как прокси для передачи запросов исходному проекту ASP.NET.
- Оба проекта будут настроены как стартовые проекты.

Процесс создания нового проекта показан в видео ниже.

Теперь вы можете начать перенос отдельных элементов из проекта ASP.NET в проект ASP.NET Core. В настоящее время расширение поддерживает миграцию: контроллеров, представлений и классов. Для этого щелкните на элементе правой кнопкой и выберите команду Migrate. Расширение проанализирует выбранный элемент, чтобы определить, от каких элементов он зависит, и также попытается перенести их. Попутно могут обнаружиться элементы, которые невозможно перенести автоматически, их необходимо будет перенести вручную. При этом вы можете снять галочки с зависимостей, если хотите пропустить их миграцию. Позже можно повторно запустить миграцию элемента, чтобы перенести дополнительные или ранее пропущенные зависимости. При повторном запуске миграции будут пропущены все элементы, которые уже были перенесены.

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

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

Известные проблемы
Расширение всё ещё на раннем этапе разработки, и в текущей версии существуют различные известные проблемы и ограничения. Вот что на данный момент не поддерживается:
- Файлы веб-контента (например, CSS/JS и т. д.) не переносятся.
- Классы, использующие Entity Framework.
- Файлы, связанные с .NET Identity.
- Проекты библиотек классов .NET Framework.
- Представления веб-форм ASP.NET.
- Миграция представлений Razor в настоящее время очень ограничена; в настоящее время нет поддержки частичных представлений или файлов layout.
- Области ASP.NET MVC.

Источник: https://devblogs.microsoft.com/dotnet/introducing-project-migrations-visual-studio-extension/
👍4
День 1292. #юмор
Кстати о E2E тестах.
День 1293. #Оффтоп #МоиИнструменты
Notebook Editor для Visual Studio
Сегодня посоветую вам видео Скотта Хенсельмана https://youtu.be/WfozTizHMlM, в котором он рассказывает про расширение Jupiter Notebooks для Visual Studio.

Jupiter Notebooks – это смесь документа Word со средой исполнения. Если вам нужно научить кого-то языку, новому функционалу, попросить кандидата на интервью выполнить задание, либо просто описать, какие действия нужно сделать в программе. Вместо того, чтобы писать всё это в текстовом документе, откуда куски кода придётся копировать и вставлять в среду исполнения, используйте Jupiter Notebooks, где можно исполнять код прямо в документе.

Скотт рассказывает про инструмент на примере обучающих курсов от Microsoft по C# и Machine Learning.

На GitHub есть репозиторий с примерами использования https://github.com/dotnet/csharp-notebooks/

Источник: https://techcommunity.microsoft.com/t5/educator-developer-blog/using-visual-studio-notebooks-for-learning-c/ba-p/3580015
👍2
День 1294. #ЗаметкиНаПолях #AsyncTips
Отмена по тайм-ауту
Тайм-аут — всего лишь одна из разновидностей запроса на отмену. Код, который необходимо отменить, просто отслеживает токен отмены, как и при любой другой отмене; ему не нужно знать, что источником отмены является таймер. У источников токенов отмены существуют вспомогательные методы, которые автоматически выдают запрос на отмену по тайм-ауту:
using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(5));

Кроме того, тайм-аут можно передать конструктору:
async Task IssueTimeoutAsync()
{
using var cts = new CancellationTokenSource(
TimeSpan.FromSeconds(5));

var token = cts.Token;
await Task.Delay(TimeSpan.FromSeconds(10), token);
}

Отмена async-кода
Многие асинхронные API поддерживают CancellationToken, поэтому обеспечение отмены обычно сводится к простой передаче токена. Как правило, если ваш метод вызывает функции API, получающие CancellationToken, то ваш метод также должен получать CancellationToken и передавать его всем функциям API, которые его поддерживают.

К сожалению, некоторые методы не поддерживают отмену. В такой ситуации простого решения не существует. Невозможно безопасно остановить произвольный код, если только он не упакован в отдельный исполняемый модуль. Если ваш код вызывает код, не поддерживающий отмену и вы не хотите упаковывать этот код в отдельный исполняемый модуль, всегда можно имитировать отмену, просто игнорируя результат.

Отмена должна предоставляться как вариант там, где это возможно. Дело в том, что правильно реализованная отмена на высоком уровне зависит от правильно реализованной отмены на нижнем уровне. Таким образом, когда вы пишете собственные async-методы, постарайтесь как можно тщательнее обеспечить поддержку отмены. Никогда неизвестно заранее, какие высокоуровневые методы будут вызывать ваш код, и им тоже может понадобиться отмена.

Отмена параллельного кода
Простейший способ поддержки отмены — передача CancellationToken параллельному коду через ParallelOptions:
void Rotate(
IEnumerable<Matrix> matrices,
float degrees,
CancellationToken ct)
{
Parallel.ForEach(matrices,
new ParallelOptions { CancellationToken = ct },
m => m.Rotate(degrees));
}

В Parallel LINQ (PLINQ) также предусмотрена встроенная поддержка отмены с оператором WithCancellation:
IEnumerable<int> MultiplyBy2(
IEnumerable<int> values,
CancellationToken ct)
{
return values.AsParallel()
.WithCancellation(ct)
.Select(item => item * 2);
}

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

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
👍10
День 1295. #ЧтоНовенького #CSharp11
Обзор Новинок C# 11. Начало
C# 11 должен выйти ноябре 2022 года вместе с .NET 7. Рассмотрим новые функции, которые обещают выпустить в новой версии языка.
Эти функции все ещё находятся в стадии превью и, возможно, не все войдут в окончательный выпуск C# 11.

Попробовать новые функции можно в Visual Studio 2022 (версия 17.3.0 или выше). Также необходимо загрузить .NET 7 SDK (версия 7.0.0 preview 6 или выше). Кроме того, в функциях предварительного просмотра IDE нужно включить Use previews of the .NET SDK (Предварительный просмотр .NET SDK).

1. Обязательные члены
Модификатор required можно использовать для свойства, чтобы убедиться, что мы явно устанавливаем значение при инициализации объекта.
public class RequiredMember
{
public required string Name { get; set; }
}

Когда мы инициализируем объект, мы должны убедиться, что мы установили значение для этого свойства. В противном случае будет выдана ошибка компиляции:
var requiredMember = new RequiredMember { Name = "Dave" };

Также возможно установить обязательный член внутри конструктора объекта. Однако мы должны добавить атрибут. Если мы просто установим требуемое свойство через параметр, это вызовет ошибку компиляции при вызове такого конструктора. Нужно установить атрибут [SetsRequiredMembers] над конструктором. Это сообщает компилятору, что мы устанавливаем необходимые элементы внутри конструктора:
public class RequiredMember
{
public required string Name { get; set; }

[SetsRequiredMembers]
public RequiredMember(string name)
{
Name = name;
}
}
Что интересно, установка атрибута отменяет требование собственно установки значения свойства, и ошибки при этом не возникнет.

2. Структуры со значениями по умолчанию
В C# 10 нам приходилось явно устанавливать значения по умолчанию для каждого из его членов при добавлении в структуру конструктора:
public struct AutoDefaultStruct
{
public int Number { get; set; }
public AutoDefaultStruct()
{
Number = 0;
}
}
Если бы мы не установили свойство Number в конструкторе, это вызвало бы ошибку компиляции. В C# 11 если эти элементы не заданы в конструкторе, для них будут установлены значения по умолчанию. В данном случае для Number будет установлено значение 0.

3. Необработанные строковые литералы
Использование строк, содержащих кавычки, или ссылки на фрагменты кода, такие как JSON, стало намного проще. Раньше приходилось экранировать кавычки обратной косой чертой.

Необработанные строковые литералы начинаются и заканчиваются тремя кавычками """...""". Теперь кавычки теперь будут рассматриваться как часть строки.

Также можно интерполировать с помощью знака $. Количество знаков $, предваряемых строкой, представляет собой количество фигурных скобок, необходимых для ссылки на переменную:
public class RawStringLiteral
{
public static int MyNumber = 1;

public string MyJsonString =
$$"""
{
"number": "{{MyNumber}}"
}
""";
}
В примере выше использованы два знака $ в начале, поэтому нужно включить две фигурные скобки, чтобы указать переменную, на которую мы хотим сослаться.

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

Источник:
https://www.roundthecode.com/dotnet/c-sharp-11-preview-features-dotnet-7
👍10
День 1296. #ЧтоНовенького #CSharp11
Обзор Новинок C# 11. Окончание
Начало

4. Обобщённые атрибуты
До C# 11 передача типа в атрибут требовала параметра типа Type и передачи значения через typeof
[MyAttr(typeof(string))] 

Теперь можно делать обобщённые атрибуты:
public class MyAttr<T> : Attribute { } 

[MyAttr<string>]

Единственное ограничение, что это должен быть полностью сконструированный тип. Попытка использовать в атрибуте параметр типа обобщённого класса приведёт к ошибке компиляции:
public class MyAttr<T> : Attribute { }

public class MyClass<T>
{
[MyAttr<T>] // Ошибка компиляции
public MyClass()
{
}
}

5. Шаблоны списков
Шаблоны списков позволяют сопоставлять шаблоны для элементов массива или списка. Здесь у нас есть несколько вариантов.

При явном указании значений массив должен будет строго соответствовать шаблону:
public bool Is_1_3_5(int[] numbers)
{
return numbers is [1, 3, 5];
// numbers должен быть длиной 3
// и иметь элементы 1, 3 и 5
}

Символ пустой переменной _ соответствует единичному элементу с любым значением:
numbers is [1, _, 5]; 
// numbers должен быть длиной 3
// и иметь элементы 1, <любое целое число> и 5

Две точки .. будут соответствовать 0 или более элементов:
numbers is [1, .., 5]; 
// numbers может быть любой длины
// должен начинаться с 1 и заканчиваться 5

Также можно указать, что значение может быть больше или меньше определённого:
numbers is [1, .., >=5]; 
// numbers может быть любой длины
// должен начинаться с 1
// и заканчиваться числом не меньше 5

Как видите, шаблоны дают нам множество вариантов проверки элементов списка или массива.

Источник: https://www.roundthecode.com/dotnet/c-sharp-11-preview-features-dotnet-7
👍13
День 1297. #Юмор #CodeReview
Обзор Кода: Как Нажить Себе Врагов
Иногда люди на работе раздражают вас, и вы чувствуете, что нужно отыграться. Если вы разрабатываете ПО, то способ есть – обзор кода! Это фантастический способ отомстить с помощью пассивно-агрессивных действий.

Проверяющий
1. Комментарии о стиле кода
У большинства компаний есть рекомендации по стилю кода. Изучите их! А затем начните просить об изменениях, которые явно не упомянуты. Если в рекомендациях по стилю кода что-то не упоминается, то это отличный шанс попросить внести бессмысленные изменения, которые просто заставят вашу жертву поработать:
- Правильно ли названы методы в классе модульного теста?
- Не слишком ли многословно названа переменная?
- Не используется синтаксис Йоды? Попросите изменить условия на противоположные.

2. Попросите об изменениях, которые не имеют смысла
Шаг 1 раздражает, но сам по себе он не смертелен. Нужно продолжать давление. Далее идут бессмысленные запросы изменений.
Если есть два способа сделать что-то, потребуйте, чтобы код был изменён, чтобы сделать по-вашему. Не слушайте доказательств о недостатках вашего варианта. Включитесь в длинный спор почему это следует изменить.
Если не хватает аргументов заставьте соперника сомневаться в своих знаниях с помощью фраз вроде: «Я не знаю, почему вы так в штыки воспринимаете эту просьбу. Так, как я сказал, будет работать. Пожалуйста измените. Спасибо.»
Заставьте соперника потратить время на переписывание кода, который отлично работает.

3. Долгие задержки
Не торопитесь отвечать. Выждите как минимум 24 часа перед проверкой кода. Говорите, что заняты другими делами. Цель здесь состоит в том, чтобы сделать пулл-реквест (PR) устаревшим. Открытые PR считаются техническим долгом, потому что они требуют работы для поддержания. Это утомительная работа. Таким образом, вам нужно заставить PR провисеть как можно дольше, чтобы человеку приходилось тратить время на исправление конфликтов слияния.
Хороший способ сделать это — отказаться работать с PR, в котором есть конфликты слияния, потому что код может выглядеть по-другому после исправления, и вы не хотите тратить время на его просмотр, чтобы затем снова просматривать его после разрешения конфликтов. Это отличная тактика. Если сопернику не пришлось исправлять конфликты слияния хотя бы 2-3 раза, вы слишком быстро ему отвечаете!

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

Проверяемый
1. Измените стиль кода в PR
Каждый PR, который вы отправляете на рассмотрение своему врагу, должен включать хотя бы 50% ненужных изменений стиля кода. Это сделает поиск фактических функциональных изменений настолько трудным, что он просто не глядя примет все ваши изменения.

2. Создавайте огромные PR
Ваша задача - заставить людей бояться обозревать ваш код. Это значит, что все PR должны содержать от 1000 изменений в как минимум 10 файлах.
Требуйте быстрого ответа. Это технический долг, и вы не хотите самостоятельно устранять конфликты слияния. Так что изводите всех, пока ваш PR не будет принят.

3. Игнорируйте комментарии
Отличный способ избежать негативных отзывов во время проверки кода — просто игнорировать их. Получили негативный комментарий? Попросите приятеля одобрить PR и слить его, не разбираясь с этим комментарием.

Итого
Если эти шаги повторять неоднократно и последовательно в течение нескольких месяцев, ваш враг пожалеет о том, что связался с вами!

Источник: https://repohealth.io/blog/code-review-how-to-make-enemies/
👍12
Hanselminutes #852 - Mark Techson
Scott Hanselman
День 1298. #Подкаст #Карьера
Сегодня предлагаю послушать эпизод подкаста Скотта Хансельмана Hanselminutes: Mark Thompson wants you to win.

Марк Томпсон, старший инженер по связям с разработчиками в Google, хочет, чтобы вы выиграли. Они со Скоттом поговорили том, почему «дефицит мест» это неправильный способ думать о карьере в сфере технологий. Ваш успех не означает неудачи кого-то другого, и наоборот. Аналогично, передача знаний вашим ученикам или младшим коллегам (помимо того, что приносит удовлетворение) не означает, что они однажды займут ваше место. Места хватит всем.

Также Марк и Скотт обсудили вариацию синдрома самозванца при взгляде на более успешных коллег. Некоторые люди генетически предрасположены добиваться успеха в определённых сферах. Но то, что существует Леброн Джеймс вовсе не означает, что остальным 600 игрокам нечего делать в НБА. Выиграть могут все. Точно проиграет лишь тот, кто не будет участвовать.

Эти и другие советы относительно карьеры в новой серии подкаста.

Источник
👍4
День 1299. #юмор
👍16
День 1300. #ЧтоНовенького
Транзитивные Зависимости в Visual Studio
Чтобы помочь отслеживать транзитивные зависимости и быстро устранять уязвимости в Visual Studio 17.3 добавлена экспериментальная функция, которая поможет вам просматривать и принимать меры в отношении транзитивных зависимостей.

Теперь в окне управления NuGet пакетами есть новый раздел зависимостей, помеченный как «транзитивные пакеты», который вы можете при желании свернуть или развернуть. Вы можете нажимать на зависимости так же, как и на зависимости верхнего уровня, и даже повышать любую транзитивную зависимость до зависимости верхнего уровня. Одной из таких причин может быть устранение уязвимости в транзитивной зависимости, которое ещё не было исправлено в пакете верхнего уровня.

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

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

Подробнее о том, как важно отслеживать зависимости в вашем проекте см. Рекомендации по Обеспечению Безопасности Проектов на GitHub

Источник: https://devblogs.microsoft.com/nuget/introducing-transitive-dependencies-in-visual-studio/
👍4
День 1301. #ЗаметкиНаПолях #AsyncTips
Внедрение Запросов на Отмену

Задача:
В коде присутствует уровень, который должен реагировать на запросы на отмену, а также выдавать собственные запросы на отмену на следующий уровень.

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

Следующий пример выполняет асинхронный запрос HTTP. Токен, переданный методу GetWithTimeoutAsync, представляет отмену, запрошенную конечным пользователем, а метод GetWithTimeoutAsync также применяет тайм-аут к запросу:
async Task<HttpResponseMessage> 
GetWithTimeoutAsync(
HttpClient client,
string url,
CancellationToken ct)
{
using var cts = CancellationTokenSource
.CreateLinkedTokenSource(ct);
cts.CancelAfter(TimeSpan.FromSeconds(2));

var combined = cts.Token;
return await client.GetAsync(url, combined);
}

Полученный токен combined отменяется либо когда пользователь отменяет существующий маркер ct, либо при отмене связанного источника вызовом CancelAfter.

Хотя в предыдущем примере используется только один источник CancellationToken, метод CreateLinkedTokenSource может получать любое количество токенов отмены в своих параметрах. Это позволяет создавать один объединённый токен, на базе которого можно реализовать собственную логическую отмену. Например, ASP.NET предоставляет токен отмены, представляющий отключение пользователя (HttpContext.RequestAborted); код обработчика может создать связанный токен, который реагирует либо на отключение пользователя, либо на свои причины отмены (например, тайм-аут).

Помните о сроке существования источника связанного токена отмены. Предыдущий пример является наиболее типичным: один или несколько токенов отмены передаются методу, который связывает их и передает как комбинированный токен. Также обратите внимание на то, что в примере используется команда using, которая гарантирует, что источник связанного токена отмены будет освобожден, когда операция будет завершена (а комбинированный токен перестанет использоваться). Подумайте, что произойдет, если код не освободит источник связанного токена отмены: может оказаться, что метод GetWithTimeoutAsync будет вызван несколько раз с одним (долгосрочным) существующим токеном; в этом случае код будет связывать новый источник токена при каждом вызове метода. Даже после того, как запросы HTTP завершатся (и ничто не будет использовать комбинированный токен), этот связанный источник всё ещё останется присоединённым к существующему токену. Чтобы предотвратить подобные утечки памяти, освобождайте источник связанного токена отмены, когда комбинированный токен перестаёт быть нужным.

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
👍8