.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
День четыреста семьдесят шестой. #юмор
Они всегда помогут)))
День четыреста семьдесят седьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
41. Межпроцессное взаимодействие влияет на время отклика приложения
Время отклика – одно из наиболее важных качеств ПО. Мало что так расстраивает, как ожидание реакции программы на действие пользователя, особенно если это действие приходится делать постоянно. Мы чувствуем, как программа тратит наше время и влияет на нашу производительность. Однако причины большого времени отклика неочевидны, особенно в современных приложениях. Большая часть литературы по управлению производительностью по-прежнему фокусируется на эффективных структурах данных и алгоритмах. Это может влиять в некоторых случаях, но крайне маловероятно это будет решающим фактором, влияющим на производительность в современных многоуровневых корпоративных приложениях.

Гораздо больше на время отклика приложения влияет количество межпроцессных взаимодействий (interprocess communications - IPC), производимых в ответ на действие пользователя. Хотя могут быть и другие локальные узкие места, этот фактор обычно доминирует. Каждое удалённое межпроцессное взаимодействие вносит некоторую незначительную задержку в общее время отклика, и эти отдельные задержки суммируются, особенно когда они происходят последовательно.

Ярким примером является ленивая загрузка или загрузка по частям - последовательное выполнение нескольких запросов к базе для получения данных. Когда клиент базы данных является сервером приложений, отображающим веб-страницу, эти запросы к БД обычно выполняются последовательно в одном потоке. Их индивидуальные задержки накапливаются, увеличивая общее время отклика. Даже если каждый запрос к базе данных занимает всего 10 миллисекунд, страница, требующая 1000 вызовов (что не редкость), будет отображаться не меньше 10 секунд. Другие примеры включают вызов веб-службы, HTTP-запросы из веб-браузера, вызов распределённого объекта и т.п. Чем больше удаленных вызовов необходимо для ответа на действие пользователя, тем больше будет время отклика.

Существует несколько относительно очевидных и общеизвестных стратегий по сокращению количества IPC:
1. Оптимизировать взаимодействие и максимально снизить объём пересылаемых между процессами данных (получение данных в JSON вместо полной HTML-разметки; применение фильтрации данных в запросе к БД вместо запроса всех данных и фильтрации в приложении и т.п.)
2. По возможности распараллеливать межпроцессное взаимодействие, чтобы общее время отклика определялось главным образом запросом с наибольшей задержкой.
3. Кэшировать результаты предыдущих запросов, чтобы можно было избежать повторных запросов тех же данных и вместо этого использовать локальный кэш.

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

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Randy Stafford
День четыреста семьдесят восьмой. #ЗаметкиНаПолях
ASP.NET Core. Тег-хелперы. Начало
В ASP.NET Core на смену помощникам HTML пришли тег-хелперы (теги-помощники). Они позволяют изменять, дополнять или полностью заменять содержимое НТМL-элементов. Распространённые случаи использования: генерирование URL для форм и ссылок, привязка модели к элементам форм, согласованная стилизация элементов и т.п. Тег-хелперы позволяют получать более чистый и читаемый код HTML. Сравните:
@Html.BeginForm("Search", "Home", FormMethod.Post))
и
<form asp-controller="Home" asp-action="Search" method="post">

1. Тег-хелперы для работы с элементом form (класс FormTagHelper):
asp-controller – контроллер для html-атрибута action формы (если не указан, используется текущий контроллер).
asp-action – метод действия для html-атрибута action формы (если не указан, используется текущий метод действия).
asp-route-* – дополнительные значения URL в атрибуте action (например, asp-route-id предоставляет системе маршрутизации значение сегмента id).
asp-route – имя маршрута, для генерации URL в атрибуте action.
asp-area – область в атрибуте action.
asp-antiforgery – управляет добавлением информации, противодействующей подделке.

Если элемент form не содержит явного html-атрибута action,
то FormTagHelper автоматически включает средство противостояния атакам CSRF. Когда значением атрибута asp-antiforgery является false, маркеры безопасности будут отключены.

2. Аналогично можно использовать эти тег-хелперы для элементов ссылок (класс AnchorTagHelper). Также для ссылок можно указать:
asp-protocol – протокол
asp-host – имя хоста
asp-fragment – фрагмент URL (часть после символа #)

3. Тег-хелперы для работы с элементами input (класс InputTagHelper):
asp-for – свойство модели представления, которое представляет элемент input.
asp-format – формат отображения данных (например, {0:#,###} для отделения тысяч запятой).
asp-for автоматически устанавливает тип элемента input в зависимости от типа данных модели:
stringtype="text" (обычное текстовое поле).
byte, int, short, longtype="number" (числовое поле).
float, double, decimaltype="text" с дополнительной проверкой значения.
booltype="checkbox" (флажок).
DateTimetype="date" (элемент выбора даты).

Кроме того, контролировать тип элемента input можно с помощью атрибута свойств модели UIHint:
HiddenInput - type="hidden" (скрытое поле)
Password - type="password" (поле пароля)
PhoneNumber - type="tel" (телефон)
Url - type="url" (URL)
EmailAddress - type="email" (email)
Time - type="time" (формат времени)

Аналогично тег-хелпер asp-for можно использовать и для элементов label, textarea и select. Кроме того, для отображения списка элементов option элементу select можно задать коллекцию значений с помощью asp-items, передав в него экземпляр типа SelectList:
<select asp-for="Country" asp-items="@new SelectList(…)">

Продолжение следует…

Источник: Адам Фримен “Pro
ASP.NET Core MVC 2”. – Диалектика, 2019. Главы 24, 25.
День четыреста семьдесят девятый. #ЗаметкиНаПолях
ASP.NET Core. Тег-хелперы. Продолжение
4. Работа с файлами JS и CSS
Файлы JS и CSS на HTML страницу подключаются с помощью тегов <script> (класс ScriptTagHelper) и <link> (класс LinkTagHelper) соответственно. Внутри них можно использовать тег-хелперы:
asp-src-include и asp-src-exclude – включают/исключают файлы по шаблону локального пути. Таким образом можно включать, например, все файлы определённой библиотеки. В шаблонах можно использовать следующие знаки:
? – любой одиночный символ
* - любые символы, кроме / (внутри одной папки)
** - любые символы, включая / (включая подпапки)
Кроме того, можно использовать несколько шаблонов через запятую.
Аналогично для файлов CSS используются asp-href-include и asp-href-exclude. Например:
<link rel="stylesheet"
asp-href-include="/lib/bootstrap/dist/**/*.min.css"
asp-href-exclude="**/*-reboot*,**/*-grid*" />
Включит все файлы из всех подпапок папки /lib/bootstrap/dist, оканчивающиеся на .min.css, но исключит файлы, содержащие в имени "-reboot" или "-grid".

asp-append-version="true" применяется для добавления версии к статическим файлам. Браузер кеширует статические файлы, поэтому применение версий позволяет изменять URL для запроса статического файла, тем самым обновляя файл на стороне клиента. Система ASP.NET автоматически отслеживает файлы на сервере и меняет номер добавляемой к URL версии, когда они изменяются. Аналогично версию можно применить к элементам img.

Группа тег-хелперов asp-fallback применяется, когда используются файлы JS и CSS из внешнего источника, например, сети доставки контента (CDN). Если по каким-то причинам внешний файл не может быть получен, можно использовать локальный файл с помощью атрибута asp-fallback-src для JS и asp-fallback-href для CSS. Также можно использовать asp-fallback-*-include и asp-fallback-*-exclude аналогично описанным выше.
Для проверки, загрузился ли внешний файл, в JS используется тег-хелпер asp-fallback-test, содержащий JS код, например:
<script … asp-fallback-test="window.jQuery">
Если код вернёт ошибку, будет использован локальный файл.
Для CSS всё немного сложнее. Нужно использовать 3 свойства: имя класса CSS, свойство и значение. В разметку будет добавлен JS код, который проверит, соответствует ли значение заданного свойства заданного CSS-класса значению, указанному в тег-хелпере. Если нет (стили не были применены, т.к. файл не удалось загрузить), будет использован локальный файл. Например:
<link href="…" …
asp-fallback-test-class="btn"
asp-fallback-test-property="display"
asp-fallback-test-value="inline-block" />

5. Использование кэша
Отдельные части веб-страницы можно кешировать в памяти веб-сервера, заключив внутрь тегов <cache>…</cache>, чтобы снизить нагрузку на сервер и время отклика веб-страницы. Поскольку размер памяти веб-сервера ограничен, кешированием можно управлять с помощью тег-хелперов:
- enabled – используется ли кэширование (по умолчанию true)
- expires-* – группа тег-хелперов для указания времени истечения срока кэширования: абсолютное (expires-on), относительное (-after), после последнего запроса (-sliding).
- vary-by-* – группа тег-хелперов для указания вариативности кэша по маршруту (vary-by-route), строке запроса (-query), http-заголовку (-header), значению куки (-cookie), аутентифицированному пользователю (-user) и т.п.
- priority – относительный приоритет кэша (при нехватке памяти кэш с меньшим приоритетом удаляется в первую очередь).

Продолжение следует…

Источник: Адам Фримен “Pro
ASP.NET Core MVC 2”. – Диалектика, 2019. Глава 25.
День четыреста восьмидесятый. #ЗаметкиНаПолях
ASP.NET Core. Тег-хелперы. Окончание
6. Регистрация тег-хелперов
Чтобы тег-хелперы применялись в представлении, их нужно зарегистрировать с помощью Razor-выражения @addTagHelper либо в каждом отдельном представлении, либо в файле _ViewImports.cshtml. Выражение принимает 2 параметра: имя классов тег-хелперов (можно использовать групповой символ *) и имя сборки, где они определены:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Подключит все классы тег-хелперов из стандартной сборки Microsoft.

7. Создание тег-хелпера
Создать свой тег-хелпер можно, унаследовав от класса TagHelper из пространства имен Microsoft.AspNetCore.Razor.TagHelpers. Имя и свойства класса определяются соглашениями. Имя состоит из имени html-тега, к которому должен применяться тег-хелпер и суффикса TagHelper. Имена свойств в стиле CamelCase получают значения от соответствующих атрибутов html-тега в стандартном стиле с разделителями дефисами. Например:
public class ButtonTagHelper : TagHelper
public string BgStyle { get; set; }

}
Этот тег-хелпер будет применяться к элементам <button>, а свойству BgStyle будет установлено значение атрибута bg-style="…". Это поведение можно изменить.

Атрибут класса HtmlTargetElement определяет, к каким тегам применяется тег-хелпер. Параметры:
- первый параметр – имя тега (если опущено, применяется ко всем тегам).
- Attributes – атрибуты, которые должен иметь html-тег. Можно указывать через запятую или использовать групповой символ *.
- ParentTag – имя родительского тега.
- TagStructure – структура тега (имеет ли закрывающий тег).
Атрибут можно использовать несколько раз, чтобы тег-хелпер применялся к разным html-элементам. Следующий атрибут указывает, что тег-хелпер применяется к тегам button, имеющим атрибуты, начинающиеся на bs-button-, и расположенным внутри элемента form:
[HtmlTargetElement("button", Attributes = "bs-button-*", ParentTag = "form")]

Свойствам тег-хелпера можно:
- назначить имя html-атрибута для привязки с помощью атрибута HtmlAttributeName;
- запретить получать данные из html-атрибутов с помощью атрибута HtmlAttributesNotBound;
- установить контекст представления с помощью атрибута ViewContext (например, для получения данных о текущем контроллере или действии);
- привязать свойства модели, задав тип свойства ModelExpression и передав html-атрибуту имя свойства модели.

Логика преобразований html-тегов помещается в переопределённый метод Process, которому передаются:
1) контекст тег-хелпера (например, теги, к которым он применён).
2) объект TagHelperOutput, содержащий свойства для управления результатом вывода.

Следующий тег-хелпер:
public class ButtonTagHelper : TagHelper
public string BtnType { get; set; }

public override void Process(
TagHelperContext context,
TagHelperOutput output)
{
output.TagName = "button";
output.TagMode = TagMode.StartTagAndEndTag;
output.Attributes.SetAttribute(
"class", "btn btn-primary");
output.Attributes.SetAttribute(
"type", BtnType.ToLower());

output.Content.SetContent(BtnType);
}
}
будет применён ко всем тегам button. Например:
<button btn-type="Submit" />
Преобразуется в:
<button class="btn btn-primary" type="submit">Submit</button>

Источник: Адам Фримен “Pro ASP.NET Core MVC 2”. – Диалектика, 2019. Глава 23.
День четыреста восемьдесят первый. #ЧтоНовенького
Топ Новостей с Конференции Microsoft Build 2020
1. Поддержка ASP.NET Blazor Web Assembly
Теперь есть возможность разрабатывать клиентские приложения, используя C#. Отпала необходимость в плагине, потому что эта технология теперь использует стандарт WebAssembly, позволяющий выполнять нативный код .NET прямо в браузере.

2. Мульти-платформенный UI Приложений (.NET MAUI)
Вместе с .NET 6. Microsoft представит технологию создания UI приложений для любого устройства (как настольного, так и мобильного) и любых операционных систем из единой кодовой базы. Превью ожидаются в конце года.

3. Превью C# 9 и .NET 5
Выпуск .NET 5 запланирован на ноябрь 2020 года. Все новые функции C# 9 будут также выпущены с .NET 5!

4. Улучшения в Visual Studio Live Share
Visual Studio Live Share теперь поддерживает текст, голосовой чат, а также предоставляет доступ к запущенным приложениям. Это позволит разработчикам сотрудничать без необходимости использования внешних приложений для совместного использования экрана.

5. Выпущен Windows Terminal
Windows Terminal позволяет запускать любое приложение командной строки внутри вкладок и панелей, а также имеет множество других возможностей кастомизации.

6. Представлена Project Reunion
Единая, более гибкая, современная и открытая платформа для разработчиков под Windows.

7. Learn TV
Learn TV объединяет контент из разных каналов Microsoft в единое пространство. Это место, где можно найти актуальный контент, чтобы всегда быть в курсе последних объявлений, функций и продуктов корпорации Майкрософт.

8. Множество Обновлений Azure
- Возможность встроить сценарии развертывания (powershell или bash) в шаблоны ARM для сквозной настройки среды.
- Новые возможности для баз данных PostgreSQL и MySQL.
- Более эффективное использование Cosmos DB.
- Поддержка Azure Kubernetes Service (AKS) для контейнеров Windows Server и многое другое.

Источник: https://www.productivecsharp.com/2020/05/top-csharp-news-microsoft-build-2020/
День четыреста восемьдесят второй. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
42. Держите Сборки в Чистоте
Вы периодически поглядываете на список предупреждений компилятора длиной в небольшой роман о плохом программировании и думаете: «Да, надо бы действительно что-то с этим сделать… но сейчас нет времени»? Или вы исправляете первое же предупреждение, которое появилось в сборке?

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

Чтобы предупреждения снова стали полезными, я стараюсь использовать политику нулевой терпимости к предупреждениям в сборке. Даже если предупреждение не важно, я разбираюсь с ним. Если оно не критично, но актуально, я исправлю его. Если компилятор предупреждает о возможной пустой ссылке, я устраняю причину, даже если я «знаю», что проблема никогда не проявится при работе. Если во встроенной документации упоминаются параметры, которые были удалены или переименованы, я чищу документацию.

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

Поддержание чистой сборки помогает в том, что не приходится решать, имеет ли смысл каждое предупреждение, с которым я сталкиваюсь. Игнорирование чего-либо – это тоже умственная работа. Нужно избавляться от всей ненужной умственной работы, насколько это возможно. Чистая сборка также помогает тому, кто будет работать с моим кодом. Если я оставлю предупреждения, этому человеку также придётся разбираться, что актуально, а что нет. Но скорее всего этот человек просто проигнорирует все предупреждения, в том числе важные.

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

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Johannes Brodwall
День четыреста восемьдесят третий. #юмор
День четыреста восемьдесят четвёртый. #MoreEffectiveCSharp
12. Ограничивайте Видимость Ваших Типов
Не каждый ваш тип должен быть публичным. Типам нужно давать наименьшую необходимую видимость для достижения вашей цели. Часто меньшую, чем кажется. Внутренние или приватные классы могут реализовывать публичные интерфейсы. Все клиенты могут получать доступ к функциональности, определённой в открытых интерфейсах и реализованной в закрытом типе. Обычно большинство программистов постоянно создают открытые классы, не задумываясь об альтернативах. Это очень просто, но лучше тщательно продумать, где будет использоваться новый тип. Он предназначен для всех клиентов или в основном используется внутри этой сборки? Многим классам достаточно быть внутренними, защищёнными, закрытыми или вложенными в другой класс. Чем меньше видимость, тем меньше мест, откуда можно получить доступ к коду, и меньше мест, которые потребуется изменить при обновлении системы.

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

Рассмотрим класс, который проверяет формат номера телефона (8(xxx)xxx-xx-xx):
public class PhoneValidator {
public bool Validate(PhoneNumber ph) { … }
}
Всё работает хорошо, но спустя некоторое время требуется, чтобы проверялись и международные номера с кодом страны (+x(xxx)-xxx-xx-xx).
Вместо того, чтобы добавлять функциональность в этот класс, и использовать его напрямую, лучше уменьшить связанность между классами. Создадим интерфейс для проверки любого телефонного номера:
public interface IPhoneValidator {
bool Validate(PhoneNumber ph);
}
Затем создадим внутренние классы для проверки местных и международных номеров, реализующие этот интерфейс:
internal class LocalPhoneValidator : IPhoneValidator {…}
internal class InternationalPhoneValidator : IPhoneValidator {…}

Наконец нужен фабричный метод для создания нужного класса в зависимости от типа номера телефона:
public static IPhoneValidator CreateValidator(PhoneTypes type) {
switch (type) {
case PhoneTypes.Local:
return new LocalPhoneValidator();
case PhoneTypes.International:
default:
return new InternationalPhoneValidator();
}
}
Общую функциональность проверки можно поместить в абстрактный базовый класс.

Преимущества:
- Вне сборки виден только интерфейс, специфические классы видны только внутри сборки.
- Можно добавлять и изменять классы проверки, не ломая другие сборки в системе.
- Чем меньше открытых типов, тем меньше открытых методов, для которых нужно писать тесты.
- Под открытый API интерфейса можно создавать mock-объекты для тестирования.

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

Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 13.
День четыреста восемьдесят пятый. #PerformanceTips
Лучшие Практики по Производительности в C#. Начало
Недавно нашёл статью со списком «шаблонов кода, которых следует избегать, потому что они плохо работают в смысле производительности». Автор пишет, что все пункты в списке так или иначе вызывали проблемы с производительностью. Хотя, стоит оговориться, что не все советы могут работать во всех случаях.

1. Синхронное ожидание асинхронного кода
Не ожидайте синхронно незавершённых задач. Включая, но не ограничиваясь: Task.Wait, Task.Result, Task.GetAwaiter().GetResult(), Task.WaitAny, Task.WaitAll. Более общий совет: любая синхронная зависимость между двумя потоками пула может вызвать истощение пула потоков.

2. ConfigureAwait
Если ваш код может быть исполнен без захвата контекста синхронизации, используйте ConfigureAwait(false) для каждого вызова await. Однако обратите внимание, что ConfigureAwait имеет смысл только при использовании ключевого слова await. Например, этот код не имеет смысла:
var result = ProcessAsync().ConfigureAwait(false).GetAwaiter().GetResult();
Подробнее о ConfigureAwait в серии постов с тегом #AsyncAwaitFAQ

3. async void
Никогда не используйте async void. Исключение, выброшенное в таком методе, распространяется в контекст синхронизации и обычно приводит к сбою всего приложения. Если вы не можете вернуть задачу в свой метод (например, потому что вы реализуете интерфейс), переместите асинхронный код метод-обёртку и вызовите его:
interface IInterface {
void DoSomething();
}
class Implementation : IInterface {
public void DoSomething() {
_ = DoSomethingAsync();
}
private async Task DoSomethingAsync() {
await Task.Delay(100);
}
}

4. По возможности избегайте слова async
По привычке вы можете написать:
public async Task CallAsync() {
var client = new Client();
return await client.GetAsync();
}
Хотя код семантически корректен, использование ключевого слова async здесь не требуется и может привести к значительным накладным расходам в «горячих путях». Попробуйте удалить его, если это возможно:
public Task CallAsync() {
var client = new Client();
return client.GetAsync();
}
Однако имейте в виду, что вы не можете использовать эту оптимизацию, когда ваш код упакован в блоки (например, try/catch или using):
public async Task Correct() {
using (var client = new Client()) {
return await client.GetAsync();
}
}
public Task Incorrect() {
using (var client = new Client()) {
return client.GetAsync();
}
}
В методе Incorrect, поскольку задача не ожидается внутри блока using, клиент может быть удален до завершения вызова GetAsync.

Продолжение следует…

Источник:
https://medium.com/@kevingosse/performance-best-practices-in-c-b85a47bdd93a
День четыреста восемьдесят шестой. #PerformanceTips
Лучшие Практики по Производительности в C#. Продолжение
5. Сравнения Строк Чувствительные к Культуре
Если у вас нет причин использовать чувствительные к культуре сравнения строк, всегда используйте нечувствительные сравнения (с параметром StringComparison.Ordinal). Хотя это и не имеет большого значения для латиницы из-за внутренних оптимизаций, сравнение происходит на порядок медленнее для других культур (до 2 порядков в Linux). Поскольку сравнение строк является частой операцией в большинстве приложений, такие мелкие задержки быстро накапливаются.

6. ConcurrentBag<T>
Не используйте ConcurrentBag<T> без тестирования производительности. Эта коллекция была разработана для очень специфических случаев использования (когда большую часть времени элемент извлекается из контейнера добавившим его потоком) и страдает от проблем с производительностью, если используется иначе. Если вам нужна конкурентная коллекция, рассмотрите ConcurrentQueue<T>. Подробнее о потокобезопасных коллекциях.

7. ReaderWriterLock<T>/ReaderWriterLockSlim<T>
Не используйте ReaderWriterLock<T>/ReaderWriterLockSlim<T> без тестирования производительности. Стоимость их использования намного выше, чем у простого монитора (используемого с ключевым словом lock). Если количество читателей критического блока не очень велико, уровня параллелизма будет недостаточно для амортизации возросших издержек, и код будет работать хуже.

8. Используйте Лямбда-Выражения Вместо Чистого Предиката
Рассмотрим следующий код:
private static bool Filter(int i) {
return i % 2 == 0;
}
И два варианта вызова:
list.Where(i => Filter(i));
и
list.Where(Filter);
Второй вариант приводит к выделению памяти в куче при каждом вызове, компилируясь в следующую конструкцию:
list.Where(new Func<int,bool>(Filter));
Лямбда-выражение использует оптимизацию компилятора и кэширует делегат в статическое поле.
*Примечание: я быстренько протестировал оба варианта в консольном приложении на предмет быстродействия и использования памяти и не нашёл никаких отличий ни в Framework, ни в Core. Поэтому есть подозрение, что оптимизация происходит в любом случае, а этот совет либо устарел, либо не проверялся автором.

Продолжение следует…

Источник:
https://medium.com/@kevingosse/performance-best-practices-in-c-b85a47bdd93a
День четыреста восемьдесят седьмой. #PerformanceTips
Лучшие Практики по Производительности в C#. Продолжение
9. Преобразование Перечислений в Строку
Вызов Enum.ToString в .Net является дорогостоящим, поскольку для преобразования используется рефлексия, а вызов виртуального метода структуры приводит к боксингу. Этого следует по возможности избегать. Часто перечисления могут быть заменены константами:
public enum Numbers {
One, Two, …
}
public static class Numbers {
public const string One = "One";
public const string Two = "Two";

}
В обоих случаях можно использовать Numbers.One, Numbers.Two,…

10. Сравнения Перечислений
Примечание: это поведение оптимизировано, начиная с .Net Core 2.1
При использовании перечислений в качестве флагов может возникнуть соблазн использовать метод Enum.HasFlag:
[Flags]
public enum Options {
Opt1 = 1, Opt2 = 2, Opt3 = 4
}

private Options option;
public bool IsOpt2() => option.HasFlag(Options.Opt2);
Этот код приводит к боксингу для преобразования Options.Opt2 в Enum и для виртуального вызова HasFlag на структуре, делает код необоснованно дорогим. Вместо этого можно использовать бинарные операторы:
public bool IsOpt2() => (option & Options.Opt2 == Options.Opt2);
Подробнее про битовые флаги

11. Реализуйте Проверку на Равенство для Структур
При использовании struct в сравнениях (например, при использовании в качестве ключа для словаря) необходимо переопределить методы Equals и GetHashCode. Реализация по умолчанию использует рефлексию и очень медленная. Подробнее

12. Избегайте Ненужного Боксинга при Использовании Структур с Интерфейсами
Рассмотрим следующий код:
public class IntValue : IValue {}

public void SendValue(IValue value) {…}
public void LogValue(IValue value) {…}

public void DoStuff() {
var value = new IntValue();
LogValue(value);
SendValue(value);
}
Соблазнительно сделать IntValue структурой, чтобы избежать выделения памяти в куче. Но поскольку AddValue и SendValue принимают интерфейс, а интерфейсы имеют ссылочную семантику, значение будет упаковываться при каждом вызове, сводя на нет преимущества «оптимизации». На самом деле, производительность может быть даже хуже, чем если бы IntValue был классом. Если же вы создаёте API, которому может быть передана структура, попробуйте использовать обобщённые методы:
public void SendValue<T>(T value) where T : IValue {…}
public void LogValue<T>(T value) where T : IValue {…}
Хотя на первый взгляд создание таких методов выглядит бесполезным, на самом деле это позволяет избежать боксинга, когда IntValue является структурой.

Продолжение следует…

Источник:
https://medium.com/@kevingosse/performance-best-practices-in-c-b85a47bdd93a
День четыреста восемьдесят восьмой. #PerformanceTips
Лучшие Практики по Производительности в C#. Окончание
13. Код Подписчиков CancellationToken Всегда Встраивается
Когда вы отменяете задачу через CancellationTokenSource, код всех подписчиков будет выполняться в текущем потоке. Это может привести к незапланированным паузам или даже неочевидным взаимным блокировкам:
var cts = new CancellationTokenSource ();
cts.Token.Register (() => Thread.Sleep (5000));
cts.Cancel (); // Это вызов заблокируется на 5 секунд
Вы не можете отказаться от этого поведения. Поэтому, при отмене через CancellationTokenSource, спросите себя, можете ли вы позволить текущему потоку исполнять другой код. Если нет, оберните вызов Cancel в Task.Run, чтобы выполнить его в пуле потоков. Подробнее о CancellationToken.

14. Код Продолжений TaskCompletionSource Часто Встраивается
Код продолжений TaskCompletionSource также часто встраивается. Это хорошая оптимизация, но она может быть причиной неочевидных ошибок. Их можно избежать, передав параметру TaskCompletionSource параметр TaskCreationOptions.RunContinuationsAsynchronously.
Если у вас нет веских причин этого не делать, всегда используйте этот параметр при создании TaskCompletionSource.
Внимание: код также скомпилируется, если вы используете TaskContinuationOptions.RunContinuationsAsynchronously. Но этот параметр будет проигнорирован, и продолжения будут оставаться встроенными. Это удивительно распространенная ошибка, потому что TaskContinuationOptions предшествует TaskCreationOptions при автозаполнении.

15. Task.Run / Task.Factory.StartNew
Если у вас нет причин использовать Task.Factory.StartNew, отдавайте предпочтение Task.Run для запуска фоновой задачи. Task.Run использует более безопасные значения по умолчанию, и, что более важно автоматически разворачивает возвращаемую задачу, что может предотвратить ошибки в асинхронных методах:
class Program {
public static async Task ProcessAsync() {
await Task.Delay(2000);
Console.WriteLine("Processing done");
}
static async Task Main(string[] args) {
await Task.Factory.StartNew(ProcessAsync);
Console.WriteLine("End of program");
Console.ReadLine();
}
}
Из кода это не очевидно, но "End of program" будет выведено раньше, чем "Processing done", потому что Task.Factory.StartNew вернёт Task<Task>, а код ожидает завершения только внешней задачи. Исправить это можно, используя либо
await Task.Factory.StartNew(ProcessAsync).Unwrap();
либо
await Task.Run(ProcessAsync);
Task.Factory.StartNew лучше использовать в следующих случаях:
- Запуск задачи в другом планировщике
- Выполнение задачи в выделенном потоке (с помощью TaskCreationOptions.LongRunning)
- Постановка задачи в глобальную очередь пула потоков (с помощью TaskCreationOptions.PreferFairness)

Источник: https://medium.com/@kevingosse/performance-best-practices-in-c-b85a47bdd93a
День четыреста восемьдесят девятый.
Давненько на канале не было ссылок на видосики. Вот наткнулся на канал Raw Coding и посмотрел видео In/Out Middleware Explained соответственно про Middleware (Промежуточное ПО). Немножко путано, но вполне толково автор объясняет суть пайплайна обработки, который используется как в Asp.net Core, так и в Angular и т.п.
И что хотелось бы отметить, начинает он с самых азов, создавая пайплайн с нуля и объясняя и решая проблемы, которые встречаются на пути, а только потом переходит к тому, как пайплайн используется.
Не сильно заморачивайтесь насчёт кода, там в качестве примера автор использует редактор LinqPad и некоторый его внутренний функционал, вроде функции Dump(). Важно понять общую концепцию, чтобы потом видеть паттерн в самых разных системах (что автор объясняет в конце).
День четыреста девяностый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
43. Знайте, Как Использовать Инструменты Командной Строки
Сегодня многие инструменты разработки ПО реализованы в виде интегрированных сред разработки (IDE). Microsoft Visual Studio и Eclipse - два популярных примера, хотя есть и много других. В IDE много приятных вещей. Они не только просты в использовании, но и помогают программисту не заботиться о мелких деталях, связанных с процессом сборки.

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

Работая с инструментами сборки из командной строки, вы узнаете намного больше о том, что делают инструменты во время сборки вашего проекта. Написание собственных настроек сборки поможет вам понять все этапы (компиляция, сборка, компоновка и т.д.), которые используются для создания исполняемого файла. Экспериментировать с множеством параметров командной строки также полезно в образовательных целях. Вы можете использовать инструменты командной строки, такие как msbuild, GCC или те, которые поставляются с вашей IDE. В конце концов, хорошо разработанная IDE - это просто графическая оболочка для набора инструментов командной строки.

Помимо улучшения понимания процесса сборки, есть некоторые задачи, которые можно выполнить проще или эффективнее с помощью инструментов командной строки, чем с помощью IDE. Например, возможности поиска и замены, предоставляемые утилитами grep и sed, часто более мощные, чем в IDE. Инструменты командной строки поддерживают сценарии, что позволяет автоматизировать такие задачи, как создание запланированных ежедневных сборок, создание нескольких версий проекта и запуск набора тестов. В IDE этот вид автоматизации может быть более сложным (если не невозможным), поскольку параметры сборки обычно задаются с помощью диалоговых окон GUI, а процесс сборки вызывается щелчком мыши. Если вы никогда не выходили за пределы IDE, вы можете даже не осознавать, что такие виды автоматических задач возможны.

Но подождите. Разве IDE не существуют для облегчения разработки и повышения производительности труда программиста? Да. Этот совет не означает, что вам следует прекратить использование IDE. Совет в том, что нужно «заглянуть под капот» и понять, что ваша IDE делает для вас. Лучший способ сделать это - научиться использовать инструменты командной строки. Затем, когда вы вернётесь к использованию IDE, у вас будет гораздо лучшее понимание того, что делает IDE и как вы можете контролировать процесс сборки. С другой стороны, как только вы освоите использование инструментов командной строки и почувствуете мощь и гибкость, которые они предлагают, вы можете обнаружить, что в некоторых случаях командная строка предпочтительнее IDE.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Carroll Robinson
День четыреста девяносто первый. #ЧтоНовенького
Ещё одно интересное видео. Я уже писал на канале о новых функциях языка:
- Обнуляемые Ссылочные Типы в C#8
- Номинальное создание объектов и записи в C#9.
Но вряд ли кто-то лучше может рассказать об этом, чем непосредственно создатель языка. Mads Torgersen на конференции NDC Conferences рассказал о будущем языка C# https://www.youtube.com/watch?v=WBos6gH-Opk.
В моих постах эти функции описаны довольно кратко (ограничивает размер поста), а Mads рассказывает, как создатели языка пришли к идее реализации каждой из этих функций.
В двух словах: язык движется в сторону широкой поддержки использования неизменяемых типов. Записи (records) – это не какая-то функция в вакууме, а скорее совокупность изменений (аналогично LINQ):
- Введение init-only свойств позволит использовать инициализаторы для создания неизменяемых объектов.
- Метод/оператор with позволит создавать копии объектов с несколькими изменёнными свойствами.
- Планируется ввести некоторое обозначение обязательности инициализации свойства (пока инициализатор не проверяет этого).
- Предполагается ввести новую конструкцию - «валидатор»:
public class Person {
public string FirstName { get; init; }
public string LastName { get; init; }
Person {
if (FirstName.Length + LastName.Length > 32)
throw new Exception(“Name too long”);
}
}
Это блок кода, проверяющий целостность данных всего класса (нескольких свойств) на этапе после выполнения инициализатора, но до присваивания созданного объекта переменной (аналогично валидации в конструкторе).

Записи будут по умолчанию реализовывать все эти функции. Также предполагается, что они будут реализовывать равенство по значению. То есть оператор равенства двух записей будет проверять не равенство ссылок, а равенство значений полей двух записей, как у структур.
Это пока на стадии обсуждения, но рассматривается возможность «сокращённой записи» создания записей:
public record class Person { string FirstName; string LastName };
или даже
public record class Person(string FirstName, string LastName);
При этом будут созданы два открытых init-only свойства.

Помимо вышеупомянутых функций Mads рассказывает о проектах функций “десятой” версии языка:
- Статические члены интерфейса позволят обобщённым интерфейсам описывать статические члены для реализующих их типов (обязать тип реализовать статический метод или переопределять оператор).
- Роли позволят рассматривать элементы типа как имеющие дополнительные члены или как другие типы, не изменяя их представления во время выполнения.
- Расширения типов позволят рассматривать типы как имеющие дополнительные члены внутри области определения расширения.
Фактически последние две функции - это методы расширения на стеройдах.
This media is not supported in your browser
VIEW IN TELEGRAM
День четыреста девяносто второй. #ЧтоНовенького
Превью 2 Visual Studio 2019 v16.7
В превью новой версии Visual Studio 2019 улучшена работа с Git в части разрешения конфликтов. Новая жёлтая панель вверху сообщит о конфликтах слияния, которые необходимо разрешить вручную. Нажатие на ней откроет улучшенный редактор слияния. Различия стало легче анализировать, т.к. редактор автоматически выравнивает совпадающие строки, можно включать/отключать выделение различий и различия в пробелах. Также вы можете отключить неконфликтующие различия, чтобы сосредоточиться только на конфликтах. Также добавлены флажки рядом с отличиями, чтобы в один клик выбрать ту или иную строку.
Попробовать новые функции можно, включив функцию Предварительного Просмотра для обновлённого Git в меню Инструменты > Параметры (Tools > Options > Preview Features).
День четыреста девяносто третий.
Blazor
В настоящее время JavaScript является наиболее популярным языком для одностраничных браузерных приложений (Single Page Application), а до недавнего времени это был единственный язык, работавший внутри браузера. Blazor - новая технология Microsoft, которая позволяет разработчикам писать клиентский код на C#.

Blazor - это основанная на .NET инфраструктура SPA для веб и мобильных приложений, а также часть веб-инфраструктуры ASP.NET Core. Blazor использует существующую объектную модель документа HTML (Document Object Model) и CSS для представления и обработки компонентов UI. Однако вместо JavaScript Blazor использует C#, поэтому разработчики могут иметь общий код между платформами.

Обработка происходит в среде выполнения .NET на сервере или на стороне клиента. В первом случае HTML DOM генерируется на сервере, а затем отправляется в браузер с помощью Signal-R (используется полноценный .NET Core). На стороне клиента в браузере используется WebAssembly и Mono. Mono в WebAssembly скоро будет обновлён до .NET 5. WebAssembly открывает все возможности .NET без необходимости рендеринга на стороне сервера или дополнительных плагинов для браузера.

Особенности Blazor
- Создание веб-интерфейсов на C# вместо JavaScript или TypeScript
- Создание прогрессивных веб-приложений (PWA)
- Создание повторно используемых компонентов на C#
- Поддержка отладки на стороне сервера (полная) и на стороне клиента (с некоторыми ограничениями)
- Двусторонняя привязка данных к HTML DOM (с ограничениями)
- Совместное использование кода C# между клиентом и сервером
- Работает во всех современных веб-браузерах, включая мобильные
- Та же песочница безопасности, что и у JavaScript
- Возможность взаимодействия с JavaScript для вызова фреймворков и библиотек

WebAssembly
WebAssembly (сокращенно WASM) — это новый открытый формат байт-кода, исполняемого современными браузерами. Он позволяет переносить код, написанный на таких языках как C, C++, Rust, Go, C# и других в низкоуровневые ассемблерные инструкции и использовать его в сети. Формат имеет компактные размеры, высокую производительность, близкую к нативной, и может работать совместно с JavaScript.

По сути, WASM позволяет компилировать код для веб-браузера. В прошлом такие технологии, как Adobe Flash или Microsoft Silverlight, достигали этого, заставляя пользователя устанавливать плагины. Этого больше не требуется, и среды выполнения, такие как .NET, теперь могут работать поверх WebAssembly.

Продолжение следует…

Источник:
https://christianfindlay.com/2020/06/04/blazor-vs-react-angular-vue-js/
День четыреста девяносто четвёртый.
Blazor vs React vs Angular vs Vue.js
1. React
React - это основанная на JavaScript UI-библиотека, принадлежащая и поддерживаемая Facebook. React не пытается предоставить разработчику все инструменты, необходимые для создания современного веб-приложения. Вместо этого он фокусируется на пользовательском интерфейсе и позволяет разработчикам выбирать лучшие компоненты для других аспектов разработки.

Особенности React
- Создание веб UI с помощью JavaScript или TypeScript
- Создание прогрессивных веб-приложений (PWA)
- Поддержка отладки в IDE, таких как VS Code

Blazor или React
JavaScript непрост для изучения C#-разработчиками и не является статически типизированным языком. Часто приходится нанимать отдельных разработчиков для бэкэнда и фронтэнда. Blazor лишён этого недостатка, но он ещё не так совершенен, как React. Пока главным недостатком является отсутствие полноценной отладки на стороне клиента. Поэтому, если готовое SPA нужно прямо сейчас, то React будет лучшим выбором. Но, если в команде в основном C# разработчики, есть большая вероятность, что Blazor будет более удобен для поддержки с течением времени.

2. Angular
Angular - это популярная веб-платформа на основе TypeScript и мобильный SPA-фреймворк, написанный и поддерживаемый Google. TypeScript является статически типизированным языком и транслируется в JavaScript. Более поздние версии Angular также поддерживают рендеринг на стороне сервера аналогично Blazor. Шаблонный синтаксис позволяет разработчикам объявлять компоненты UI с привязкой данных аналогично синтаксису Razor.

Особенности
- Создание веб-интерфейсов с помощью TypeScript
- Создание прогрессивных веб-приложений (PWA)
- Двустороннее связывание данных с HTML DOM
- Поддержка отладки в IDE, таких как VS Code
- Полный набор встроенных API для стандартных задач приложения

Blazor или Angular
Многие из сказанного о React верно и для Angular. Однако Angular реализует парадигму TypeScript, которая более естественна для C# разработчиков, чем для JavaScript. Angular гораздо более всеобъемлющий, чем React, и не просто предоставляет компоненты UI. Он побуждает разработчиков использовать компоненты «из коробки», поэтому код становится более единообразным.

3. Vue.js
Vue – это что-то среднее между React и Angular. Разработчики могут использовать TypeScript, но основное внимание уделяется JavaScript.

Особенности
- Создание веб-интерфейсов с помощью JavaScript или TypeScript
- Создание прогрессивных веб-приложений (PWA)
- Двустороннее связывание данных с HTML DOM
- Поддержка отладки в IDE, таких как VS Code
- Полный набор встроенных API для стандартных задач приложения

Blazor или Vue.js
Vue.js может быть удачным компромиссом для разработчиков, которые хотят больше, чем просто UI-библиотеку, но без тяжести полноценной платформы Angular. Vue.js может быть ещё одним хорошим выбором для команд, которым необходимо разработать SPA прямо сейчас.

Итого
Blazor переносит знакомый HTML DOM на C# и предоставляет веб-разработчикам возможность использовать C# на стороне клиента. У него есть потенциал для создания полноценных настольных и мобильных приложений, и он пользуется популярностью в сообществе разработчиков Microsoft. Рассмотрите его при выборе технологии для вашего следующего SPA.

Источник: https://christianfindlay.com/2020/06/04/blazor-vs-react-angular-vue-js/
День четыреста девяносто пятый.
Я недавно выкладывал ссылку на видео канала Raw Coding про Middleware, и в нашем чате посоветовали посмотреть другие их видео. На этот раз пост не про одно видео, а про целый плейлист ASP.NET Core - Authentication & Authorization Tutorial https://www.youtube.com/playlist?list=PLOeFnOV9YBa7dnrjpOG6lMpcyd7Wn7E8V
Подробнейший рассказ про аутентификацию и авторизацию в ASP.NET Core, чего, кстати, очень не хватает той же книге Фримена (там вся огромная система коротко и скомкано описана в паре глав).

Мне понравился подход автора. Обычно рассказ начинают с простой авторизации, потом переходят к ролям, а потом к заявкам (утверждениям, клеймам, объектам claim, - куча названий в разных источниках). На самом деле, тут можно понять путаницу в названиях, потому что одним словом перевести слово claim на русский невозможно. Наверное, утверждение, будет лучшим вариантом, хотя, я бы в контексте авторизации назвал это «притязанием» (предъявлением своих прав на что-нибудь). Если смотрели Игру Престолов, то там все постоянно спорили, у кого бОльшие притязания на трон (по праву рождения, по старшинству и т.п). Вот это именно claims – набор утверждений о пользователе, дающий или не дающий ему право на что-либо.

Так вот, автор начинает рассказ именно с описания утверждений: где они находятся в системе авторизации и как они выдаются той или иной службой авторизации (на примере бабушки, рассказывающей о том, что её внук хороший)) ). И, удивительно, но, если вот так «начать с конца», а не с ролей, как обычно, всё прекрасно встаёт на свои места:
1. приложение определяет политику,
2. политика содержит требования,
3. требования проверяют наличие необходимых утверждений/притязаний.
А при авторизации с помощью ролей, роль – это просто частный случай утверждения.

Дальше там и про OAuth, и про Identity Server, я пока до туда не дошёл)))

В общем, не пожалейте 14,5 часов (да, я посчитал общую продолжительность плейлиста) на просмотр. Оно того несомненно стоит.