Blazor Minimum Project Templates v11.0.100-preview.1 получили поддержку таргета net11.0.
Если хочется стартовать с максимально чистого Blazor-шаблона, это как раз тот случай: без JS, без CSS-библиотек, с упором на чистый C#.
Можно ставить и пробовать уже сейчас для .NET 11 preview.
https://github.com/jsakamoto/BlazorMinimumTemplates
👉 @KodBlog
Если хочется стартовать с максимально чистого Blazor-шаблона, это как раз тот случай: без JS, без CSS-библиотек, с упором на чистый C#.
Можно ставить и пробовать уже сейчас для .NET 11 preview.
https://github.com/jsakamoto/BlazorMinimumTemplates
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
Чувак сделал намеренно уязвимое dotnet приложение 👀
Многие советы по безопасности в .NET остаются слишком абстрактными, пока ты не увидишь баг прямо в коде.
Поэтому этот проект, где всё намеренно сделано неправильно. Это намеренно уязвимое .NET-приложение, в котором собрано более 50 распространённых реальных ошибок, которые могут проскочить в обычный бизнес-код.
Ссылка - https://github.com/AlexGoOn/the-most-vulnerable-dotnet-app
Некоторые из включённых вещей:
👉 @KodBlog
Многие советы по безопасности в .NET остаются слишком абстрактными, пока ты не увидишь баг прямо в коде.
Поэтому этот проект, где всё намеренно сделано неправильно. Это намеренно уязвимое .NET-приложение, в котором собрано более 50 распространённых реальных ошибок, которые могут проскочить в обычный бизнес-код.
Ссылка - https://github.com/AlexGoOn/the-most-vulnerable-dotnet-app
Некоторые из включённых вещей:
Инъекционные атаки (SQL, command, template, LDAP, XML, logs)
Cross-Site Scripting (stored, reflected, в атрибутах, в SVG)
Небезопасная загрузка файлов (path traversal, Zip Slip, произвольная запись файлов)
Проблемы с криптографией (hashing, ECB, предсказуемый random)
Сериализация (XXE, XML bomb, binary, YAML)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🤔1
8 лет опыта научили меня, что кидать исключения дорого.
Поэтому я начал делать так:
Раньше я бросал исключения, когда:
- пользователь не найден
- переданы невалидные параметры
- результат метода
И всю логику обработки я выносил на вызывающую сторону, которая теперь должна знать, какое именно исключение прилетело и как на него реагировать.
Но реальность такая: исключения отлично подходят для ошибок, с которыми ты не знаешь, что делать.
К счастью, большинство ошибок можно обработать, и вот как:
Паттерн Result.
Вместо того чтобы кидать исключения, методы возвращают объект
Ещё стоит подумать о своей кастомной
В своих проектах я люблю иметь две версии: не-дженерик (для
Я предпочитаю свою реализацию, но если тебе это не заходит, можно взять готовые библиотеки, например FluentResults.
👉 @KodBlog
Поэтому я начал делать так:
Раньше я бросал исключения, когда:
- пользователь не найден
- переданы невалидные параметры
- результат метода
nullИ всю логику обработки я выносил на вызывающую сторону, которая теперь должна знать, какое именно исключение прилетело и как на него реагировать.
Но реальность такая: исключения отлично подходят для ошибок, с которыми ты не знаешь, что делать.
К счастью, большинство ошибок можно обработать, и вот как:
Паттерн Result.
Вместо того чтобы кидать исключения, методы возвращают объект
Result, который явно показывает успех/провал и содержит либо успешное значение, либо информацию об ошибке.Ещё стоит подумать о своей кастомной
Error-модели, где ты будешь нормально, описательно расписывать все типы ошибок и использовать её внутри Result.В своих проектах я люблю иметь две версии: не-дженерик (для
void-методов) и дженерик (обёртка для конкретного результата). Так намерение кода читается сразу и без гаданий.Я предпочитаю свою реализацию, но если тебе это не заходит, можно взять готовые библиотеки, например FluentResults.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴12❤9👍7🤔3
Оператор LINQ FullJoin() появится в dotnet 11?
https://github.com/dotnet/runtime/issues/124787
👉 @KodBlog
https://github.com/dotnet/runtime/issues/124787
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Когда стоит использовать паттерн Outbox?
Паттерн Outbox хранит исходящие сообщения в таблице базы данных, а потом фоновый процесс публикует их в брокер сообщений.
Зачем вообще заморачиваться?
Потому что в распределённых системах всё ломается: падают downstream-сервисы, отваливается сеть и т.д.
Если публиковать сообщения прямо внутри обработки запроса, есть риск их потерять, когда что-то пойдёт не так.
Outbox опирается на атомарные транзакции БД:
✅ Сохранить состояние приложения
✅ Сохранить сообщение в Outbox (либо оба шага, либо ни один)
А дальше фоновый процесс уже безопасно доставляет сообщение.
Важно помнить: Outbox решает надёжность публикации.
А на стороне консюмера всё равно нужна идемпотентность, чтобы нормально переживать ретраи.
Хочешь глубже?
Полная статья тут: https://milanjovanovic.tech/blog/implementing-the-outbox-pattern
👉 @KodBlog
Паттерн Outbox хранит исходящие сообщения в таблице базы данных, а потом фоновый процесс публикует их в брокер сообщений.
Зачем вообще заморачиваться?
Потому что в распределённых системах всё ломается: падают downstream-сервисы, отваливается сеть и т.д.
Если публиковать сообщения прямо внутри обработки запроса, есть риск их потерять, когда что-то пойдёт не так.
Outbox опирается на атомарные транзакции БД:
А дальше фоновый процесс уже безопасно доставляет сообщение.
Важно помнить: Outbox решает надёжность публикации.
А на стороне консюмера всё равно нужна идемпотентность, чтобы нормально переживать ретраи.
Хочешь глубже?
Полная статья тут: https://milanjovanovic.tech/blog/implementing-the-outbox-pattern
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3
C# records как value objects?
Records по задумке иммутабельные, и у них структурное сравнение (равенство по значениям).
А именно это обычно и нужно от value object.
Плюс сверху получаем pattern matching, короткий синтаксис и deconstruction.
👉 @KodBlog
Records по задумке иммутабельные, и у них структурное сравнение (равенство по значениям).
А именно это обычно и нужно от value object.
Плюс сверху получаем pattern matching, короткий синтаксис и deconstruction.
public class Booking
{
public Address Address { get; init; }
public DateRange Period { get; init; }
}
public record Address(
string Street,
string City,
string State,
string Country,
string ZipCode);
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9😁1
Каждый раз, когда ты пишешь очередной новенький
ты на самом деле принимаешь решение по производительности.
Большинство разработчиков воспринимают структуры данных как контейнеры. А это не так. Это контракты по перформансу.
Вот как полезно думать о самых популярных структурах в .NET, по-практически:
Array
Бери, когда размер фиксирован и нужен честный O(1) доступ по индексу.
Самый быстрый вариант. Нет ресайза. Нет сюрпризов.
List<T>
Отличный дефолтный выбор, пока не упираешься в ресайз.
Под капотом при росте capacity копируется весь массив.
Dictionary<TKey, TValue>
В среднем O(1) на поиск.
Но плохое распределение хеша -> коллизии -> деградация скорости.
Stack<T>
Идеален для рекурсии, парсинга, undo/redo.
Но глубокая рекурсия? Привет, StackOverflow (сайт) или stack overflow (ошибка).
Queue<T>
FIFO. Отлично для фоновой обработки и пайплайнов.
Типа планирования задач, обработки сообщений.
Tree / Graph
Используются чаще, чем кажется:
роутинг, индексация, разрешение зависимостей, поиск.
Смысл не в том, чтобы заучивать Big-O.
Смысл понимать:
- как выделяется память
- как работает ресайз
- что происходит под нагрузкой
- на какой компромисс ты соглашаешься
Хорошие инженеры пишут код, который работает.
Классные инженеры знают, почему он работает и в какой момент перестанет.
👉 @KodBlog
List<>,ты на самом деле принимаешь решение по производительности.
Большинство разработчиков воспринимают структуры данных как контейнеры. А это не так. Это контракты по перформансу.
Вот как полезно думать о самых популярных структурах в .NET, по-практически:
Array
Бери, когда размер фиксирован и нужен честный O(1) доступ по индексу.
Самый быстрый вариант. Нет ресайза. Нет сюрпризов.
List<T>
Отличный дефолтный выбор, пока не упираешься в ресайз.
Под капотом при росте capacity копируется весь массив.
Dictionary<TKey, TValue>
В среднем O(1) на поиск.
Но плохое распределение хеша -> коллизии -> деградация скорости.
Stack<T>
Идеален для рекурсии, парсинга, undo/redo.
Но глубокая рекурсия? Привет, StackOverflow (сайт) или stack overflow (ошибка).
Queue<T>
FIFO. Отлично для фоновой обработки и пайплайнов.
Типа планирования задач, обработки сообщений.
Tree / Graph
Используются чаще, чем кажется:
роутинг, индексация, разрешение зависимостей, поиск.
Смысл не в том, чтобы заучивать Big-O.
Смысл понимать:
- как выделяется память
- как работает ресайз
- что происходит под нагрузкой
- на какой компромисс ты соглашаешься
Хорошие инженеры пишут код, который работает.
Классные инженеры знают, почему он работает и в какой момент перестанет.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤6
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🤯7🥴4❤3🔥1
Паттерн Builder в реальном мире на C#: полная реализация
Посмотрите, как паттерн Builder работает на практике, на полноценном реальном примере на C#. Пошаговая реализация конфигурационной системы, которая показывает поэтапную сборку объекта.
Статья здесь
👉 @KodBlog
Посмотрите, как паттерн Builder работает на практике, на полноценном реальном примере на C#. Пошаговая реализация конфигурационной системы, которая показывает поэтапную сборку объекта.
Статья здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
Dev Leader
Builder Pattern Real-World Example in C#: Complete Implementation
See Builder pattern in action with a complete real-world C# example. Step-by-step implementation of a configuration system demonstrating step-by-step object con
❤5
Как применять EF-миграции в продакшене?
Самый распространенный подход: накатывать их через CLI командой
Но я предпочитаю генерировать для миграций SQL-скрипты. Так можно проверить SQL-выражения и убедиться, что все ок.
Еще лучше, если у вас есть DBA.
👉 @KodBlog
Самый распространенный подход: накатывать их через CLI командой
Update-Database.Но я предпочитаю генерировать для миграций SQL-скрипты. Так можно проверить SQL-выражения и убедиться, что все ок.
Еще лучше, если у вас есть DBA.
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
START TRANSACTION;
CREATE TABLE "Products" (
"Id" integer GENERATED BY DEFAULT AS IDENTITY,
"Name" character varying(100) NOT NULL,
"Description" character varying(1000),
"Price" numeric(18,2) NOT NULL,
CONSTRAINT "PK_Products" PRIMARY KEY ("Id"),
CONSTRAINT "CK_Price_NotNegative" CHECK (Price > 0)
);
CREATE UNIQUE INDEX "IX_Products_Name" ON "Products" ("Name");
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20240516095344_Create_Database', '8.0.5');
COMMIT;
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴9🤔1
Отсутствие нейминг-конвенций в коде меня дико бесит.
Можешь с этим что-нибудь сделать?
Только без истерик в PR (так не надо).
Если вдруг не знал: довольно легко написать архитектурные тесты, которые проверяют нейминг-конвенции в твоём коде.
Вот пример для именования command handler-ов.
👉 @KodBlog
Можешь с этим что-нибудь сделать?
Только без истерик в PR (так не надо).
Если вдруг не знал: довольно легко написать архитектурные тесты, которые проверяют нейминг-конвенции в твоём коде.
Вот пример для именования command handler-ов.
[Fact]
public void CommandHandler_ShouldHave_NameEndingWith_CommandHandler()
{
Types.InAssembly(ApplicationAssembly)
.That()
.ImplementInterface(typeof(ICommandHandler<>))
.Or()
.ImplementInterface(typeof(ICommandHandler<,>))
.Should()
.HaveNameEndingWith("CommandHandler")
.GetResult()
.ShouldBeSuccessful();
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴7❤6👍4🤔1
Невозможно оставаться холодным и безразличным, когда речь про ИИ.
Так что эти ресурсы стоит чекнуть как можно скорее:
- https://github.com/AIDotNet/OpenDeepWiki
- https://github.com/shuyu-labs/AntSK
- https://github.com/AIDotNet/Thor
- https://github.com/AIDotNet/auto-prompt
👉 @KodBlog
Так что эти ресурсы стоит чекнуть как можно скорее:
- https://github.com/AIDotNet/OpenDeepWiki
- https://github.com/shuyu-labs/AntSK
- https://github.com/AIDotNet/Thor
- https://github.com/AIDotNet/auto-prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - AIDotNet/OpenDeepWiki: OpenDeepWiki is the open-source version of the DeepWiki project, aiming to provide a powerful knowledge…
OpenDeepWiki is the open-source version of the DeepWiki project, aiming to provide a powerful knowledge management and collaboration platform. The project is mainly developed using C# and TypeScrip...
👍1🤔1
Кто-то собрал вообще все туториалы в стиле сделай это с нуля со всего интернета в одном месте.
Называется build-your-own-x, и это самый популярный репозиторий в истории GitHub по числу звёзд.
466 000 звёзд. Больше, чем у React. Больше, чем у TensorFlow. Больше, чем у любого инструмента, который когда-либо делали.
И это не код. Это кураторская подборка пошаговых туториалов, которые учат пересобирать с нуля технологии, которыми ты пользуешься каждый день. С нуля.
Ричард Фейнман сказал: "Чего я не могу создать, того я не понимаю."
https://github.com/codecrafters-io/build-your-own-x
👉 @KodBlog
Называется build-your-own-x, и это самый популярный репозиторий в истории GitHub по числу звёзд.
466 000 звёзд. Больше, чем у React. Больше, чем у TensorFlow. Больше, чем у любого инструмента, который когда-либо делали.
И это не код. Это кураторская подборка пошаговых туториалов, которые учат пересобирать с нуля технологии, которыми ты пользуешься каждый день. С нуля.
Ричард Фейнман сказал: "Чего я не могу создать, того я не понимаю."
https://github.com/codecrafters-io/build-your-own-x
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤3🤔1
Как сделать ваши API-эндпоинты быстрее в 426 раз:
(подсказка: это не кэш)
Когда разработчики видят медленные API, первая реакция часто такая: лечить тормоза неправильным лекарством, кэшем.
Но это решение держится на ключевом заблуждении:
будто кэширование может исправить тормоза, вызванные плохими запросами к базе данных.
Поэтому первый шаг к более масштабируемым системам это починить именно запросы.
Чтобы это показать, проведем небольшой эксперимент.
Я сделал небольшой веб-API с одним эндпоинтом
До оптимизации:
- Количество обработанных запросов: 378
- Среднее запросов/сек: 11.01
- Средняя длительность запроса: примерно 4 секунды
После оптимизации:
- Количество обработанных запросов: 140,331
- Среднее запросов/сек: 4,689.36
- Средняя длительность запроса: 10.69 мс
Сначала исправляй доступ к данным.
А кэш используй потом, чтобы масштабироваться, а не выживать.
👉 @KodBlog
(подсказка: это не кэш)
Когда разработчики видят медленные API, первая реакция часто такая: лечить тормоза неправильным лекарством, кэшем.
Но это решение держится на ключевом заблуждении:
будто кэширование может исправить тормоза, вызванные плохими запросами к базе данных.
Поэтому первый шаг к более масштабируемым системам это починить именно запросы.
Чтобы это показать, проведем небольшой эксперимент.
Я сделал небольшой веб-API с одним эндпоинтом
/products.До оптимизации:
- Количество обработанных запросов: 378
- Среднее запросов/сек: 11.01
- Средняя длительность запроса: примерно 4 секунды
После оптимизации:
- Количество обработанных запросов: 140,331
- Среднее запросов/сек: 4,689.36
- Средняя длительность запроса: 10.69 мс
Сначала исправляй доступ к данным.
А кэш используй потом, чтобы масштабироваться, а не выживать.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2👎1🤔1
Поддержка 😍
Судя по всему, это должно приехать в EF 11 Preview 2.
👉 @KodBlog
MinBy / MaxBy скоро появится в Entity Framework Судя по всему, это должно приехать в EF 11 Preview 2.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥1🤔1
Жирный лайфхак: как бесплатно и за пару минут сделать сайт с документацией для любого репозитория на GitHub:
👉 @KodBlog
This media is not supported in your browser
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👎3🥴2❤1🤔1🤨1
У нас новости: нативная трассировка OpenTelemetry появится в ASP.NET 11 Preview 2! ✌️
ASP.NET Core теперь нативно добавляет атрибуты семантических конвенций OpenTelemetry в Activity HTTP-сервера, приводя это в соответствие со спецификацией OpenTelemetry HTTP server span. Все обязательные атрибуты теперь включены по умолчанию, то есть метаданные совпадают с теми, что раньше были доступны только через библиотеку
Чтобы собирать встроенные данные трассировки, подпишитесь на source
Никакая дополнительная библиотека инструментирования (например
👉 @KodBlog
ASP.NET Core теперь нативно добавляет атрибуты семантических конвенций OpenTelemetry в Activity HTTP-сервера, приводя это в соответствие со спецификацией OpenTelemetry HTTP server span. Все обязательные атрибуты теперь включены по умолчанию, то есть метаданные совпадают с теми, что раньше были доступны только через библиотеку
OpenTelemetry.Instrumentation.AspNetCore.Чтобы собирать встроенные данные трассировки, подпишитесь на source
Microsoft.AspNetCore в вашей конфигурации OpenTelemetry:builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("Microsoft.AspNetCore")
.AddConsoleExporter());
Никакая дополнительная библиотека инструментирования (например
OpenTelemetry.Instrumentation.AspNetCore) больше не нужна. Фреймворк теперь напрямую проставляет атрибуты семантических конвенций, такие как http.request.method, url.path, http.response.status_code и server.address, в Activity запроса.Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🤔1
Самый простой способ добавить валидацию в Options Pattern
Можно использовать data annotations, например атрибут
Также нужно обновить настройку DI и вызвать метод
Это включит валидацию при разрешении options из DI-контейнера.
👉 @KodBlog
Можно использовать data annotations, например атрибут
Required.Также нужно обновить настройку DI и вызвать метод
ValidateDataAnnotations.Это включит валидацию при разрешении options из DI-контейнера.
public class GitHubSettings
{
[Required]
public string AccessToken { get; init; }
[Required]
public string RepositoryName { get; init; }
}
builder.Services
.AddOptions<GitHubSettings>()
.BindConfiguration("GitHubSettings")
.ValidateDataAnnotations();
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤔2