Планирование в Visual Studio теперь доступно в публичной превью-версии
Это обновление добавляет новый способ, с помощью которого Copilot может разруливать сложные, многошаговые задачи. Благодаря Planning Copilot теперь может изучать твой код, разбивать большие задачи на подзадачи и выполнять их пошагово, в итоге ты получаешь более предсказуемые результаты и лучше понимаешь, что именно он делает.
Попробуй в Visual Studio 2022 версии 17.14:
зайди в Tools → Options → Copilot → Enable Planning и включи функцию.
После этого расскажи, что думаешь.
👉 @KodBlog
Это обновление добавляет новый способ, с помощью которого Copilot может разруливать сложные, многошаговые задачи. Благодаря Planning Copilot теперь может изучать твой код, разбивать большие задачи на подзадачи и выполнять их пошагово, в итоге ты получаешь более предсказуемые результаты и лучше понимаешь, что именно он делает.
Мы уже видим обнадёживающие результаты: улучшилась успешность и стабильность работы разных моделей. Но это только начало
Попробуй в Visual Studio 2022 версии 17.14:
зайди в Tools → Options → Copilot → Enable Planning и включи функцию.
После этого расскажи, что думаешь.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1🥴1
6 Шагов для Правильной Настройки Нового .NET-проекта
1. Задай единый стиль кода
Первое, что я добавляю в проект — файл .editorconfig.
Он заставляет всех в команде придерживаться одинакового форматирования и соглашений об именах, чтобы не было разношерстных отступов и случайных неймингов.
Создать его можно прямо в Visual Studio.
Стандартная конфигурация - хороший старт, но можно подстроить под вкусы команды.
Положи файл в корень решения, чтобы все проекты следовали тем же правилам. При желании можно переопределить настройки в отдельных подпапках, добавив туда свой .editorconfig.
Вот два примера .editorconfig, которые можно использовать:
- из репозитория .NET runtime
- вариант для обычных .NET-проектов
2. Централизуй настройки сборки
Дальше я добавляю файл Directory.Build.props в корень решения. Он позволяет задавать настройки сборки, общие для всех проектов.
Пример:
Так .csproj файлы остаются чистыми и единообразными, поэтому не нужно повторять эти свойства в каждом проекте.
Если потом захочешь подключить статические анализаторы или поменять параметры сборки, то делается это в одном месте.
Фишка в том, что .csproj файлы становятся почти пустыми, кроме ссылок на NuGet-пакеты.
3. Централизуй управление пакетами
Когда решение разрастается, версии NuGet-пакетов в разных проектах начинают расходиться и чёрт, это превращается в кошмар😬
Тут помогает централизованное управление пакетами.
Создай в корне файл Directory.Packages.props:
Теперь, когда подключаешь пакет в проекте, указываешь только имя, без версии:
Все версии хранятся централизованно. Обновлять зависимости становится проще, а рассинхрон версий между проектами исчезает.
Если нужно, можно переопределить версию в конкретном проекте.
4. Подключи статический анализ кода
Статический анализ помогает ловить потенциальные баги и следить за качеством кода. В .NET уже есть встроенные анализаторы, но я обычно добавляю SonarAnalyzer.CSharp, ведь он делает проверку глубже.
Установи пакет:
И добавь его как глобальную зависимость в Directory.Build.props:
Дополнительно настрой сборку:
Теперь билд упадет, если будут серьезные проблемы с качеством кода = неплохая страховка.
Если какие-то правила не подходят, можно понизить их уровень до none в .editorconfig.
5. Настрой локальную оркестрацию
Чтобы у всех разработчиков среда была одинаковой, стоит настроить контейнерную оркестрацию.
Один из вариантов это .NET Aspire
.NET Aspire добавляет сервис-дискавери, телеметрию и упрощает конфигурацию. Все это встроено прямо в .NET-проекты.
Пример добавления проекта и Postgres-ресурса:
Aspire под капотом использует Docker, но разработчику с ним работать приятнее.
В любом случае цель одна.
6. Автоматизируй сборку через CI
В конце я настраиваю простой workflow в GitHub Actions, чтобы проверять каждый коммит.
👉 @KodBlog
1. Задай единый стиль кода
Первое, что я добавляю в проект — файл .editorconfig.
Он заставляет всех в команде придерживаться одинакового форматирования и соглашений об именах, чтобы не было разношерстных отступов и случайных неймингов.
Создать его можно прямо в Visual Studio.
Стандартная конфигурация - хороший старт, но можно подстроить под вкусы команды.
Положи файл в корень решения, чтобы все проекты следовали тем же правилам. При желании можно переопределить настройки в отдельных подпапках, добавив туда свой .editorconfig.
Вот два примера .editorconfig, которые можно использовать:
- из репозитория .NET runtime
- вариант для обычных .NET-проектов
2. Централизуй настройки сборки
Дальше я добавляю файл Directory.Build.props в корень решения. Он позволяет задавать настройки сборки, общие для всех проектов.
Пример:
<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>
Так .csproj файлы остаются чистыми и единообразными, поэтому не нужно повторять эти свойства в каждом проекте.
Если потом захочешь подключить статические анализаторы или поменять параметры сборки, то делается это в одном месте.
Фишка в том, что .csproj файлы становятся почти пустыми, кроме ссылок на NuGet-пакеты.
3. Централизуй управление пакетами
Когда решение разрастается, версии NuGet-пакетов в разных проектах начинают расходиться и чёрт, это превращается в кошмар
Тут помогает централизованное управление пакетами.
Создай в корне файл Directory.Packages.props:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.15.0.120848" />
</ItemGroup>
</Project>
Теперь, когда подключаешь пакет в проекте, указываешь только имя, без версии:
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
Все версии хранятся централизованно. Обновлять зависимости становится проще, а рассинхрон версий между проектами исчезает.
Если нужно, можно переопределить версию в конкретном проекте.
4. Подключи статический анализ кода
Статический анализ помогает ловить потенциальные баги и следить за качеством кода. В .NET уже есть встроенные анализаторы, но я обычно добавляю SonarAnalyzer.CSharp, ведь он делает проверку глубже.
Установи пакет:
Install-Package SonarAnalyzer.CSharpИ добавь его как глобальную зависимость в Directory.Build.props:
<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" />
</ItemGroup>
Дополнительно настрой сборку:
<Project>
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AnalysisLevel>latest</AnalysisLevel>
<AnalysisMode>All</AnalysisMode>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>
</Project>
Теперь билд упадет, если будут серьезные проблемы с качеством кода = неплохая страховка.
Если какие-то правила не подходят, можно понизить их уровень до none в .editorconfig.
5. Настрой локальную оркестрацию
Чтобы у всех разработчиков среда была одинаковой, стоит настроить контейнерную оркестрацию.
Один из вариантов это .NET Aspire
.NET Aspire добавляет сервис-дискавери, телеметрию и упрощает конфигурацию. Все это встроено прямо в .NET-проекты.
Пример добавления проекта и Postgres-ресурса:
var postgres = builder.AddPostgres("demo-db");
builder.AddProject<WebApi>("webapi")
.WithReference(postgres)
.WaitFor(postgres);
builder.Build().Run();Aspire под капотом использует Docker, но разработчику с ним работать приятнее.
В любом случае цель одна.
6. Автоматизируй сборку через CI
В конце я настраиваю простой workflow в GitHub Actions, чтобы проверять каждый коммит.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤10❤🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9
Многие приложения сильно завязаны на реляционные базы данных. Твое приложение, скорее всего, использует сложные запросы, ограничения на данные и прочие приятные фишки реляционных баз. А значит, большая часть поведения твоего приложения напрямую зависит от того, как именно ведет себя база данных.
Поэтому я стараюсь тестировать код на настоящей базе, а не на какой-нибудь подделке. Раньше это было проблемой — большинство СУБД сложно поднимать и автоматизировать. Сейчас всё проще. Используй TestContainers🙄
TestContainers — это библиотека, которая поднимает Docker-контейнеры для тестов. Более того, в ней уже есть готовые конфигурации для популярных баз данных.
Сначала ставим библиотеку через NuGet. Потом настраиваем первый контейнер. Например, для Microsoft SQL Server:
Этот код скачает Docker-образ Microsoft SQL Server и запустит контейнер. Потом ты можешь запросить строку подключения и гонять тесты против реальной базы. В примере ниже создается таблица Dogs, вставляется запись и читается обратно. Тест, как ни странно, упадет. Почему? Подсказка в конце поста
Очистка контейнера:
Контейнеры автоматически очищаются
Интересный момент: если ты убьешь процесс, который гоняет тесты, что станет с контейнерами?
Запусти тест, потом посмотри, какие контейнеры сейчас активны:
Результат будет примерно такой:
Как видно, поднялось два контейнера. Потом можно убить тестовый процесс и наблюдать за docker ps — контейнеры вскоре исчезнут.
Это и есть сила TestContainers. Контейнер testcontainers/ryuk следит за всеми тестовыми контейнерами и убивает их (вместе с собой), если теряет связь с тестовым процессом.
У TestContainers уже есть готовая поддержка множества баз данных. Можно поискать наследников класса TestcontainerDatabase. Аналогично для систем обмена сообщениями — они наследуются от TestcontainerMessageBroker. Полный список есть в документации.
Если готовые конфиги тебе не подходят, можно поднять любой образ вручную:
Есть и стратегии ожидания, чтобы убедиться, что контейнер полностью запущен и готов к работе.
P.S. Почему упал Assert? Потому что тип datetime в SQL Server имеет странные правила округления. Он может незаметно подправить значение даты. Так что снова повторим, тестируй на настоящей базе!
👉 @KodBlog
Поэтому я стараюсь тестировать код на настоящей базе, а не на какой-нибудь подделке. Раньше это было проблемой — большинство СУБД сложно поднимать и автоматизировать. Сейчас всё проще. Используй TestContainers
TestContainers — это библиотека, которая поднимает Docker-контейнеры для тестов. Более того, в ней уже есть готовые конфигурации для популярных баз данных.
Сначала ставим библиотеку через NuGet. Потом настраиваем первый контейнер. Например, для Microsoft SQL Server:
// Конфигурируем базу, которую хотим поднять
var dbConfig = new MsSqlTestcontainerConfiguration
{
Password = "Test1234",
Database = "TestDB"
};
// Создаем контейнер с этой конфигурацией
var testContainer = new TestcontainersBuilder<MsSqlTestcontainer>()
.WithDatabase(dbConfig)
// Если не указать образ, MsSqlTestcontainerConfiguration выберет дефолтный
.WithImage("mcr.microsoft.com/mssql/server:2022-latest")
.Build();
// Запускаем контейнер
testContainer.StartAsync().Wait();
Этот код скачает Docker-образ Microsoft SQL Server и запустит контейнер. Потом ты можешь запросить строку подключения и гонять тесты против реальной базы. В примере ниже создается таблица Dogs, вставляется запись и читается обратно. Тест, как ни странно, упадет. Почему? Подсказка в конце поста
class Dog
{
public DateTime BirthDate { get; set; }
public string Name { get; set; }
}
using (var db = new SqlConnection(testContainer.ConnectionString))
{
// Для примера я использую Dapper
db.Execute(@"CREATE TABLE Dogs(
BirthDate DATETIME NOT NULL,
Name VARCHAR(MAX) NOT NULL
)");
var bornAt = new DateTime(2022, 12, 22, 12, 59, 59, 999);
db.Execute(@"INSERT Dogs(BirthDate,Name) VALUES(@BirthDate, @Name)", new
{
BirthDate = bornAt,
Name = "Joe"
});
var dog = db.Query<Dog>(@"SELECT * FROM Dogs").First();
// Этот assert упадет. Почему? Именно поэтому нужно тестировать на реальной базе.
Assert.AreEqual(bornAt, dog.BirthDate);
}
Очистка контейнера:
// Чистим за собой
testContainer.DisposeAsync();
Контейнеры автоматически очищаются
Интересный момент: если ты убьешь процесс, который гоняет тесты, что станет с контейнерами?
Запусти тест, потом посмотри, какие контейнеры сейчас активны:
docker psРезультат будет примерно такой:
roman@gamlor /tmp> docker ps
CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES
86a1da367f12 mcr.microsoft.com/mssql/server:2017... "/opt/mssql/bi..." Up 6s 49180->1433/tcp busy_bohr
5cec99b15206 testcontainers/ryuk:0.3.4 "/app" Up 7s 49179->8080/tcp
testcontainers-ryuk...
Как видно, поднялось два контейнера. Потом можно убить тестовый процесс и наблюдать за docker ps — контейнеры вскоре исчезнут.
Это и есть сила TestContainers. Контейнер testcontainers/ryuk следит за всеми тестовыми контейнерами и убивает их (вместе с собой), если теряет связь с тестовым процессом.
У TestContainers уже есть готовая поддержка множества баз данных. Можно поискать наследников класса TestcontainerDatabase. Аналогично для систем обмена сообщениями — они наследуются от TestcontainerMessageBroker. Полный список есть в документации.
Если готовые конфиги тебе не подходят, можно поднять любой образ вручную:
var someContainer = new TestcontainersBuilder<TestcontainersContainer>()
.WithImage("some-image")
.WithEnvironment("USER", "test-user")
.WithCommand("-flag-one -flag-two")
.Build();
Есть и стратегии ожидания, чтобы убедиться, что контейнер полностью запущен и готов к работе.
P.S. Почему упал Assert? Потому что тип datetime в SQL Server имеет странные правила округления. Он может незаметно подправить значение даты. Так что снова повторим, тестируй на настоящей базе!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👏1
Каждое приложение, которое ты используешь, общается с сервером через API.
Много лет стандартом был REST:
- роуты, которые представляют ресурсы (/users, /posts)
- классические методы: GET, POST, PUT, DELETE
Работает отлично, но когда приложение разрастается, начинаются проблемы:
Overfetching — сервер отдает больше данных, чем нужно. (Ты просишь имя, а получаешь весь профиль).
Underfetching — чтобы отобразить один экран, приходится делать несколько запросов. (Ты запрашиваешь посты, а комментарии приходят отдельно).
Жесткость — если меняется UI, приходится менять и бэкенд.
Главная проблема в подходе:
фронтенд мыслит экранами, а бэкенд — ресурсами.
Именно поэтому появился GraphQL — язык, который описывает, как клиент может запрашивать и структурировать данные с сервера.
Он решает три ключевые задачи:
1. Один endpoint — меньше связности между фронтендом и бэкендом.
2 Гибкий запрос — клиент сам определяет, какие данные ему нужны.
3. Типизированная схема — валидация, автодополнение и автогенерация документации.
На практике REST отлично подходит для стабильных эндпоинтов, а GraphQL для динамических вьюх и составных данных.
👉 @KodBlog
Много лет стандартом был REST:
- роуты, которые представляют ресурсы (/users, /posts)
- классические методы: GET, POST, PUT, DELETE
Работает отлично, но когда приложение разрастается, начинаются проблемы:
Overfetching — сервер отдает больше данных, чем нужно. (Ты просишь имя, а получаешь весь профиль).
Underfetching — чтобы отобразить один экран, приходится делать несколько запросов. (Ты запрашиваешь посты, а комментарии приходят отдельно).
Жесткость — если меняется UI, приходится менять и бэкенд.
Главная проблема в подходе:
фронтенд мыслит экранами, а бэкенд — ресурсами.
Именно поэтому появился GraphQL — язык, который описывает, как клиент может запрашивать и структурировать данные с сервера.
Он решает три ключевые задачи:
1. Один endpoint — меньше связности между фронтендом и бэкендом.
2 Гибкий запрос — клиент сам определяет, какие данные ему нужны.
3. Типизированная схема — валидация, автодополнение и автогенерация документации.
На практике REST отлично подходит для стабильных эндпоинтов, а GraphQL для динамических вьюх и составных данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4
Если ты вытягиваешь очень длинную строку типа NVARCHAR(MAX) через await ToListAsync(), Entity Framework начинает творить дичь = запрос становится медленным, а потребление памяти взлетает. Хотя, если быть точным, дело не в самом EF — основная работа ложится на Microsoft.Data.SqlClient. Проблема в том, что он неправильно использует SqlDataReader, из-за чего происходят лишние аллокации и запрос тормозит.
Апдейт: речь в основном про реализацию для SQL Server, так как она использует пакет Microsoft.Data.SqlClient. Чтобы понять, зацепила ли тебя эта проблема, просто глянь зависимости в проекте, есть ли там именно этот пакет.
Вот бенчмарк от Wraith2:
Источник: https://github.com/dotnet/SqlClient/pull/3161
Он пофиксил эту проблему серией PR-ов, растянувшихся почти на пять лет. Это и круто, и немного безумно. Конечно, не пять лет подряд, но всё равно впечатляет.
Последние релиз-ноты можно почитать тут:
https://github.com/dotnet/SqlClient/blob/main/release-notes/6.1/6.1.0-preview1.md
Результаты такие:
Остаётся примерно 20% разницы по аллокациям, но разрыв уже почти закрыт. Отличная работа от Wraith2 и всей команды. Можно протестировать новую версию пакета даже если ты работаешь через EF — прямые зависимости перекрывают транзитивные. Или просто подожди следующий релиз EF, где уже будет обновлённый Microsoft.Data.SqlClient.
Финальный стабильный релиз 6.1 уже совсем близко.
👉 @KodBlog
Апдейт: речь в основном про реализацию для SQL Server, так как она использует пакет Microsoft.Data.SqlClient. Чтобы понять, зацепила ли тебя эта проблема, просто глянь зависимости в проекте, есть ли там именно этот пакет.
Вот бенчмарк от Wraith2:
BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.2314)
.NET SDK 9.0.200
[Host] : .NET 8.0.13 (8.0.1325.6609), X64 RyuJIT
DefaultJob : .NET 8.0.13 (8.0.1325.6609), X64 RyuJIT
| Method | UseContinue | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|--------|--------------|----------:|----------:|----------:|----------:|----------:|----------:|----------:|
| Async | False | 757.51 ms | 15.053 ms | 36.642 ms | 2000.0000 | 1000.0000 | - | 101.49 MB |
| Sync | False | 39.40 ms | 0.543 ms | 0.508 ms | 2000.0000 | 888.8889 | 777.7778 | 80.14 MB |
Источник: https://github.com/dotnet/SqlClient/pull/3161
Он пофиксил эту проблему серией PR-ов, растянувшихся почти на пять лет. Это и круто, и немного безумно. Конечно, не пять лет подряд, но всё равно впечатляет.
Последние релиз-ноты можно почитать тут:
https://github.com/dotnet/SqlClient/blob/main/release-notes/6.1/6.1.0-preview1.md
Результаты такие:
| Method | UseContinue | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|--------|--------------|----------:|----------:|----------:|----------:|----------:|----------:|----------:|
| Async | True | 49.45 ms | 0.901 ms | 1.376 ms | 4333.3333 | 3555.5556 | 1111.1111 | 101.51 MB |
| Sync | True | 40.09 ms | 0.476 ms | 0.445 ms | 2000.0000 | 888.8889 | 777.7778 | 80.14 MB |
Остаётся примерно 20% разницы по аллокациям, но разрыв уже почти закрыт. Отличная работа от Wraith2 и всей команды. Можно протестировать новую версию пакета даже если ты работаешь через EF — прямые зависимости перекрывают транзитивные. Или просто подожди следующий релиз EF, где уже будет обновлённый Microsoft.Data.SqlClient.
Финальный стабильный релиз 6.1 уже совсем близко.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🤯6🔥4
C# Portal | Программирование
Каждое приложение, которое ты используешь, общается с сервером через API. Много лет стандартом был REST: - роуты, которые представляют ресурсы (/users, /posts) - классические методы: GET, POST, PUT, DELETE Работает отлично, но когда приложение разрастается…
Что происходит под капотом GraphQL-запроса
1) Клиент делает запрос
→ приложение отправляет запрос (HTTP POST) на эндпоинт
→ это один вызов, в котором клиент точно указывает, какие данные ему нужны
2) Сервер интерпретирует запрос
→ GraphQL парсит запрос и сверяет его со своей схемой — картой данных и связей между ними
→ если запрос не соответствует схеме (например, клиент запрашивает поле, которого бэкенд не отдает), запрос падает с ошибкой
3) Выполняются резолверы
→ у каждого поля в запросе есть функция, которая знает, как получить нужные данные
• user → ищет пользователя в базе данных
• posts → достает посты этого пользователя
→ GraphQL выполняет все эти функции и собирает результат в один ответ
4) Возврат ответа
→ сервер возвращает объект с той же структурой, что и исходный запрос
→ клиент получает ровно те данные, которые запросил, ничего лишнего
Клиент сам описывает, что ему нужно, а сервер знает, как это отдать
Вот это и есть GraphQL
На 2 иллюстрации хорошо видно, как GraphQL связывает всё воедино:
→ схема определяет, какие данные существуют и как они связаны
→ резолверы знают, откуда эти данные брать (база данных, API)
→ сервер собирает всё вместе и отдает клиенту единый ответ
👉 @KodBlog
1) Клиент делает запрос
→ приложение отправляет запрос (HTTP POST) на эндпоинт
/graphql→ это один вызов, в котором клиент точно указывает, какие данные ему нужны
2) Сервер интерпретирует запрос
→ GraphQL парсит запрос и сверяет его со своей схемой — картой данных и связей между ними
→ если запрос не соответствует схеме (например, клиент запрашивает поле, которого бэкенд не отдает), запрос падает с ошибкой
3) Выполняются резолверы
→ у каждого поля в запросе есть функция, которая знает, как получить нужные данные
• user → ищет пользователя в базе данных
• posts → достает посты этого пользователя
→ GraphQL выполняет все эти функции и собирает результат в один ответ
4) Возврат ответа
→ сервер возвращает объект с той же структурой, что и исходный запрос
→ клиент получает ровно те данные, которые запросил, ничего лишнего
Клиент сам описывает, что ему нужно, а сервер знает, как это отдать
Вот это и есть GraphQL
На 2 иллюстрации хорошо видно, как GraphQL связывает всё воедино:
→ схема определяет, какие данные существуют и как они связаны
→ резолверы знают, откуда эти данные брать (база данных, API)
→ сервер собирает всё вместе и отдает клиенту единый ответ
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Идемпотентность не зависит от HTTP-статусов. Она относится только к состоянию сервера.
Это довольно частое заблуждение у разработчиков: операция может оставаться идемпотентной, даже если сервер возвращает разные коды ответов. Главное, чтобы повторные запросы не меняли состояние системы.
Пример:
Даже если второй запрос возвращает 404 (потому что ресурса уже нет), операция всё равно идемпотентна, при условии, что повторное удаление не вызывает новых побочных эффектов.
👉 @KodBlog
Это довольно частое заблуждение у разработчиков: операция может оставаться идемпотентной, даже если сервер возвращает разные коды ответов. Главное, чтобы повторные запросы не меняли состояние системы.
Пример:
Запрос Ответ
DELETE /products/123 204
DELETE /products/123 404
Даже если второй запрос возвращает 404 (потому что ресурса уже нет), операция всё равно идемпотентна, при условии, что повторное удаление не вызывает новых побочных эффектов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14
This media is not supported in your browser
VIEW IN TELEGRAM
Странный техно-эксперимент:
Парень использовал RayLib C# для генерации визуала, запускал всё в
Получилось что-то вроде стриминга гипермедиа-приложения или игры — без WebGL, без видео, чисто поток div-ов.
Безумие? Да. Гениально? Тоже да.
👉 @KodBlog
Парень использовал RayLib C# для генерации визуала, запускал всё в
ASP.NET webhost, снимал пиксельные кадры, превращал их в HTML-div-ы как пиксели, и слал эти div-ы в браузер через Server-Sent Events.Получилось что-то вроде стриминга гипермедиа-приложения или игры — без WebGL, без видео, чисто поток div-ов.
Безумие? Да. Гениально? Тоже да.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🥴7🔥3
Не выкатывай приложение, работающее с Kafka, в прод, без нагрузочного тестирования
Если твой Kafka-пайплайн не прогонялся под реальной нагрузкой, мелкие баги очень быстро превратятся в крупные на проде.
А такие проблемы с производительностью в продакшене обходятся дорого, и по деньгам, и по репутации.
Kafka-пайплайн может работать идеально в девелоперской среде, где трафик минимальный.
Но в проде неожиданные пики нагрузки легко вскрывают скрытые проблемы:
• проблемы с конкурентным доступом;
• неверные настройки для обработки backpressure;
• узкие места в I/O или сериализации при обработке сообщений;
• неправильное партиционирование, из-за которого нагрузка на консьюмеров распределяется неравномерно;
• неверно рассчитанное масштабирование числа консьюмеров под ожидаемую нагрузку;
• некорректное использование Kafka-транзакций, требующих координации;
• задержки commit-ack от нод.
В зависимости от твоего кейса, объёма данных, формата сообщений, сетевых условий, железа, конфигурации и качества кода, при работе с Kafka могут возникать разные проблемы:
• потеря или дублирование сообщений;
• перегрузка или падение брокеров;
• уязвимости или нарушения требований безопасности и комплаенса.
Для многих компаний скорость Kafka-пайплайна критична - особенно если она влияет на SLA.
Когда задаются SLO или SLA, латентность конкретных потоков должна оставаться стабильной, что делает задачу по обеспечению скорости и эффективности пайплайна ещё сложнее.
NBomber - мощный инструмент для симуляции реальной нагрузки на Kafka в .NET-приложениях.
Он позволяет тестировать продюсеров, консьюмеров и end-to-end флоу с помощью сценариев, написанных на C# или F#.
С NBomber можно:
• измерять полную латентность между продюсером и консьюмером;
• отслеживать, как меняется throughput при росте нагрузки;
• определять момент, когда консьюмер начинает отставать от продюсера.
Я использовал NBomber для нагрузочного тестирования боевого Kafka-пайплайна системы Fraud Detection, построенной на микросервисах.
👉 @KodBlog
Если твой Kafka-пайплайн не прогонялся под реальной нагрузкой, мелкие баги очень быстро превратятся в крупные на проде.
А такие проблемы с производительностью в продакшене обходятся дорого, и по деньгам, и по репутации.
Kafka-пайплайн может работать идеально в девелоперской среде, где трафик минимальный.
Но в проде неожиданные пики нагрузки легко вскрывают скрытые проблемы:
• проблемы с конкурентным доступом;
• неверные настройки для обработки backpressure;
• узкие места в I/O или сериализации при обработке сообщений;
• неправильное партиционирование, из-за которого нагрузка на консьюмеров распределяется неравномерно;
• неверно рассчитанное масштабирование числа консьюмеров под ожидаемую нагрузку;
• некорректное использование Kafka-транзакций, требующих координации;
• задержки commit-ack от нод.
В зависимости от твоего кейса, объёма данных, формата сообщений, сетевых условий, железа, конфигурации и качества кода, при работе с Kafka могут возникать разные проблемы:
• потеря или дублирование сообщений;
• перегрузка или падение брокеров;
• уязвимости или нарушения требований безопасности и комплаенса.
Для многих компаний скорость Kafka-пайплайна критична - особенно если она влияет на SLA.
Когда задаются SLO или SLA, латентность конкретных потоков должна оставаться стабильной, что делает задачу по обеспечению скорости и эффективности пайплайна ещё сложнее.
NBomber - мощный инструмент для симуляции реальной нагрузки на Kafka в .NET-приложениях.
Он позволяет тестировать продюсеров, консьюмеров и end-to-end флоу с помощью сценариев, написанных на C# или F#.
С NBomber можно:
• измерять полную латентность между продюсером и консьюмером;
• отслеживать, как меняется throughput при росте нагрузки;
• определять момент, когда консьюмер начинает отставать от продюсера.
Я использовал NBomber для нагрузочного тестирования боевого Kafka-пайплайна системы Fraud Detection, построенной на микросервисах.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Я как кодер довольно щепетилен в разнице между цифрой 0 и буквой O.
В конце созвона саппорт продиктовал мне номер тикета:
четыре, один, восемь, T, A, два, «ОУ»
Зная, что обычные люди вечно путают, я уточнил:
«Это ноль, цифра? Или O, буква?»
(долгая пауза)
«Это ноль, буква.»
👉 @KodBlog
В конце созвона саппорт продиктовал мне номер тикета:
четыре, один, восемь, T, A, два, «ОУ»
Зная, что обычные люди вечно путают, я уточнил:
«Это ноль, цифра? Или O, буква?»
(долгая пауза)
«Это ноль, буква.»
Please open Telegram to view this post
VIEW IN TELEGRAM
😁36🤯25🔥2
Разбор самой жёсткой уязвимости в .NET. Request smuggling и CVE-2025-55315
https://andrewlock.net/understanding-the-worst-dotnet-vulnerability-request-smuggling-and-cve-2025-55315/
В статье объяснили, что такое request smuggling, разбирают свежую дыру в AspNetCore с критичностью 9.9 и показывают, как атакеры могут это дело использовать.
👉 @KodBlog
https://andrewlock.net/understanding-the-worst-dotnet-vulnerability-request-smuggling-and-cve-2025-55315/
В статье объяснили, что такое request smuggling, разбирают свежую дыру в AspNetCore с критичностью 9.9 и показывают, как атакеры могут это дело использовать.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
image_2025-10-29_09-13-40.png
2 MB
Проект на выходных: змейка на C#
Код получился кривоватый. Уверен, есть тысяча способов сделать это лучше. Я просто пытался сам допереть, как всё работает.
Немного олдскульной ностальгии по Nokia.
👉 @KodBlog
Код получился кривоватый. Уверен, есть тысяча способов сделать это лучше. Я просто пытался сам допереть, как всё работает.
Немного олдскульной ностальгии по Nokia.
Please open Telegram to view this post
VIEW IN TELEGRAM
👏14🥴7❤2👍2
Media is too big
VIEW IN TELEGRAM
Только что вышел Minecraftonia — воксельный движок на C# 13/.NET 9 и Avalonia. В проекте экспериментируют с кастомным воксельным рейтрейсингом, процедурной генерацией террейна и отзывчивым десктопным интерфейсом, при этом всё полностью кроссплатформенно.
Ссылка на релиз: https://github.com/wieslawsoltes/Minecraftonia/releases/tag/v0.1.0
👉 @KodBlog
Ссылка на релиз: https://github.com/wieslawsoltes/Minecraftonia/releases/tag/v0.1.0
Please open Telegram to view this post
VIEW IN TELEGRAM
😁15🔥14🥴3
В Entity Framework Core ToDictionaryAsync (и синхронный ToDictionary) вытягивают из базы весь объект целиком.
Если глянуть на сигнатуру ToDictionaryAsync:
Аргументы тут обычные лямбды (Func<TSource, ...>), а не выражения (Expression<Func<...>>). Значит, вычисление этих селекторов происходит на клиенте.
Допустим, у нас есть такой класс:
И вот такой запрос:
Звучит красиво, но по факту EF притащит не только Author и Title, а вообще все поля, например, и Content тоже. На это есть issue, и я случайно наткнулся и офигел.
Как обойти проблему: сначала спроецировать данные через Select, это уже выполнится на стороне сервера:
👉 @KodBlog
Если глянуть на сигнатуру ToDictionaryAsync:
public static Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TSource, TKey, TElement>(
this IQueryable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
CancellationToken cancellationToken = default)
where TKey : notnull
=> ToDictionaryAsync(source, keySelector, elementSelector, comparer: null, cancellationToken);
Аргументы тут обычные лямбды (Func<TSource, ...>), а не выражения (Expression<Func<...>>). Значит, вычисление этих селекторов происходит на клиенте.
Допустим, у нас есть такой класс:
public class BlogPost
{
public int Id { get; set; }
public required string Title { get; set; }
public required string Description { get; set; }
public required string Content { get; set; }
public required string Author { get; set; }
}
И вот такой запрос:
return await dbContext.BlogPosts
.Where(...)
.ToDictionaryAsync(k => k.Author, v => v.Title);
Звучит красиво, но по факту EF притащит не только Author и Title, а вообще все поля, например, и Content тоже. На это есть issue, и я случайно наткнулся и офигел.
Как обойти проблему: сначала спроецировать данные через Select, это уже выполнится на стороне сервера:
return await dbContext.BlogPosts
.Where(...)
.Select(s => new { Author = s.Author, Title = s.Title })
.ToDictionaryAsync(k => k.Author, v => v.Title);
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17🔥7🤔2
Мне очень нравится, что в C# 14 убрали лишнюю возню, связанную с полями, лежащими в основе свойств.
Особенно круто для таких штук, как INotifyPropertyChanged, потому что больше не нужен отдельный приватный field только ради вызова уведомления.
Ссылка: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#the-field-keyword
👉 @KodBlog
Особенно круто для таких штук, как INotifyPropertyChanged, потому что больше не нужен отдельный приватный field только ради вызова уведомления.
Ссылка: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#the-field-keyword
Please open Telegram to view this post
VIEW IN TELEGRAM
❤15🔥12🥰2👍1
Перемещение Файлов и Папок в Корзину в .NET
При работе с файлами и папками в .NET-приложениях на Windows иногда нужно отправлять объекты в корзину, а не удалять их насовсем (File.Delete, Directory.Delete). Это позволяет пользователю восстановить случайно удалённые данные. Вот как сделать это через Windows Shell API:
Этот метод подходит и для файлов, и для каталогов:
👉 @KodBlog
При работе с файлами и папками в .NET-приложениях на Windows иногда нужно отправлять объекты в корзину, а не удалять их насовсем (File.Delete, Directory.Delete). Это позволяет пользователю восстановить случайно удалённые данные. Вот как сделать это через Windows Shell API:
static void MoveToRecycleBin(string path)
{
var shellType = Type.GetTypeFromProgID("Shell.Application", throwOnError: true)!;
dynamic shellApp = Activator.CreateInstance(shellType)!;
// https://learn.microsoft.com/en-us/windows/win32/api/shldisp/ne-shldisp-shellspecialfolderconstants?WT.mc_id=DT-MVP-5003978
var recycleBin = shellApp.Namespace(0xa);
// https://learn.microsoft.com/en-us/windows/win32/shell/folder-movehere?WT.mc_id=DT-MVP-5003978
recycleBin.MoveHere(path);
}
Этот метод подходит и для файлов, и для каталогов:
MoveToRecycleBin(@"C:\path\to\file.txt");
MoveToRecycleBin(@"C:\path\to\directory");
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤3🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
От чат‑бота к агентам: Microsoft Agent Framework в .NET
Microsoft опубликовала руководство по переходу с обычных чат-ботов на AI-агентов в .NET. В примерах показывают, как подключить Microsoft Agent Framework к AI-шаблонам, зарегистрировать агента в Program.cs, вынести поиск в инструмент через
Есть упоминание расширений, мультиягентов, кастомного middleware и развёртывания в Azure с рабочими примерами. Агент уже не болтает, а самостоятельно решает задачи.
👉 @KodBlog
Microsoft опубликовала руководство по переходу с обычных чат-ботов на AI-агентов в .NET. В примерах показывают, как подключить Microsoft Agent Framework к AI-шаблонам, зарегистрировать агента в Program.cs, вынести поиск в инструмент через
SearchAsync, настроить Azure OpenAI и векторное хранилище, а также включить телеметрию через OpenTelemetry и тестирование в .NET Aspire. Есть упоминание расширений, мультиягентов, кастомного middleware и развёртывания в Azure с рабочими примерами. Агент уже не болтает, а самостоятельно решает задачи.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🥴6🤨2👍1
Это может быть первым шагом при написании юнит-тестов.
Не всегда понятно, с чего начать. Но шаблон AAA почти всегда выручает.
// act ... код, который тестируем
// ДОЛЖЕН БЫТЬ ОДИН КОНКРЕТНЫЙ ВЫЗОВ
// arrange ... моки и подготовка окружения для act
// assert ... проверки результата act
И вот — у вас уже есть юнит-тест.
Дальше можно:
a) дублировать Test01 и менять под следующий кейс
b) параметризовать Test01, чтобы прогонять сразу несколько вариантов
В конце просто переименовать Test01..TestN во что-то осмысленное.
👉 @KodBlog
Не всегда понятно, с чего начать. Но шаблон AAA почти всегда выручает.
// act ... код, который тестируем
// ДОЛЖЕН БЫТЬ ОДИН КОНКРЕТНЫЙ ВЫЗОВ
// arrange ... моки и подготовка окружения для act
// assert ... проверки результата act
И вот — у вас уже есть юнит-тест.
Дальше можно:
a) дублировать Test01 и менять под следующий кейс
b) параметризовать Test01, чтобы прогонять сразу несколько вариантов
В конце просто переименовать Test01..TestN во что-то осмысленное.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15