📌 Как из HTML сгенерировать PDF в .NET с помощью PuppeteerSharp и Handlebars
Этот пример показывает, как взять HTML-шаблон, подставить данные через Handlebars и преобразовать его в PDF с помощью PuppeteerSharp.
- Читаем HTML-шаблон InvoiceTemplate.html и компилируем его в функцию.
- Подставляем данные, получаем готовый HTML.
- PuppeteerSharp скачивает Chromium.
- Открываем браузер в headless-режиме, создаём страницу, загружаем туда HTML.
- Сохраняем страницу как PDF в формате A4, с фоном и нужными отступами.
Код:
Таким образом можно автоматизировать генерацию счётов, отчётов или любых документов из HTML прямо в C#.
Этот пример показывает, как взять HTML-шаблон, подставить данные через Handlebars и преобразовать его в PDF с помощью PuppeteerSharp.
- Читаем HTML-шаблон InvoiceTemplate.html и компилируем его в функцию.
- Подставляем данные, получаем готовый HTML.
- PuppeteerSharp скачивает Chromium.
- Открываем браузер в headless-режиме, создаём страницу, загружаем туда HTML.
- Сохраняем страницу как PDF в формате A4, с фоном и нужными отступами.
Код:
var template = File.ReadAllText("Templates/InvoiceTemplate.html");
var compiled = Handlebars.Compile(template);
string html = compiled(data);
// Скачать Chromium
var fetcher = new BrowserFetcher();
await fetcher.DownloadAsync();
// Рендер в PDF
using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true });
using var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
byte[] pdf = await page.PdfDataAsync(new PdfOptions {
Format = PaperFormat.A4,
PrintBackground = true,
MarginOptions = new MarginOptions { Top = "50px", Right = "20px", Bottom = "50px", Left = "20px" }
});
Таким образом можно автоматизировать генерацию счётов, отчётов или любых документов из HTML прямо в C#.
Но это делает отладку в 10 раз проще.
Стандартный вид при отладке:
{Namespace.ObjectName}
Никакого контекста. Много путаницы.
Но всего одной строкой кода?
Теперь окно наблюдения показывает:
Order ORD-2025-002: Bob Evans - 89.50
Order ORD-2025-003: Maria Lee - 1200.00
В чём фишка?
Используйте
DebuggerDisplay
.Добавляете этот атрибут в начало класса, чтобы контролировать, как будет отображаться информация о классе при отладке.
В следующий раз, когда будете смотреть на
{Namespace.ObjectName}
, помните: так не обязательно должно быть.Please open Telegram to view this post
VIEW IN TELEGRAM
🔐 RBAC (Role-Based Access Control) в действии
Как работает RBAC:
- Роли получают набор разрешений
- Пользователи получают роли → а значит и разрешения
- Разрешения определяют, что пользователь может или не может делать
📌 Поток авторизации:
1. Пользователь проходит аутентификацию
2. Получает access token (JWT)
3. Делает API-запрос с токеном
4. Токен преобразуется в claims
5. Проверка прав (authorize)
6. Ответ API
⚡ Пример обработчика RBAC в C#:
}
Как работает RBAC:
- Роли получают набор разрешений
- Пользователи получают роли → а значит и разрешения
- Разрешения определяют, что пользователь может или не может делать
📌 Поток авторизации:
1. Пользователь проходит аутентификацию
2. Получает access token (JWT)
3. Делает API-запрос с токеном
4. Токен преобразуется в claims
5. Проверка прав (authorize)
6. Ответ API
⚡ Пример обработчика RBAC в C#:
internal sealed class PermissionAuthorizationHandler
: AuthorizationHandler<PermissionRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
HashSet<string> permissions = context.User.GetPermissions();
if (permissions.Contains(requirement.Permission))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
⚡ В EF Core чаще всего используют два подхода:
- Database-First — быстрое создание моделей из готовой БД
- Code-First — проектирование схемы через C# классы и миграции
Но оба могут тормозить разработку при сложных связях и настройках.
👉 Есть третий путь — Model-First.
Вы визуально проектируете модель, а она автоматически превращается в EF Core сущности и схему БД.
🛠 Один из лучших инструментов — Entity Developer от Devart:
- drag-and-drop интерфейс вместо ручного кода
- меньше рутины и ошибок в конфигурации
- точная генерация кода и SQL-скриптов
- быстрее дизайн → генерация → обновление моделей
Меньше кода ✍️, больше скорости 🚀.
#dotnet #efcore #csharp #devtools
- Database-First — быстрое создание моделей из готовой БД
- Code-First — проектирование схемы через C# классы и миграции
Но оба могут тормозить разработку при сложных связях и настройках.
👉 Есть третий путь — Model-First.
Вы визуально проектируете модель, а она автоматически превращается в EF Core сущности и схему БД.
🛠 Один из лучших инструментов — Entity Developer от Devart:
- drag-and-drop интерфейс вместо ручного кода
- меньше рутины и ошибок в конфигурации
- точная генерация кода и SQL-скриптов
- быстрее дизайн → генерация → обновление моделей
Меньше кода ✍️, больше скорости 🚀.
#dotnet #efcore #csharp #devtools
🔥 Хотите разобраться в ASP.NET Core на практике?
Репозиторий — это более 400+ римеров для всех версий ASP.NET Core (от 2.1 до 10 Preview).
Что внутри:
- Minimal API, Blazor, SignalR, gRPC
- Аутентификация, кэширование, health-checks
- Middleware, Razor Pages, HTMX и многое другое
Каждый пример запускается командой
⭐ Репо собрало уже 10k+ звёзд и считается одним из лучших ресурсов для изучения ASP.NET Core.
📌 Github
Репозиторий — это более 400+ римеров для всех версий ASP.NET Core (от 2.1 до 10 Preview).
Что внутри:
- Minimal API, Blazor, SignalR, gRPC
- Аутентификация, кэширование, health-checks
- Middleware, Razor Pages, HTMX и многое другое
Каждый пример запускается командой
dotnet watch run
и демонстрирует отдельную фичу. ⭐ Репо собрало уже 10k+ звёзд и считается одним из лучших ресурсов для изучения ASP.NET Core.
📌 Github
Forwarded from C# (C Sharp) programming
🔍 NetSonar — инструмент для сетевой диагностики от sn4k3
NetSonar — это лёгкая и кроссплатформенная утилита, которая помогает диагностировать сеть, визуализировать данные и управлять сетевыми интерфейсами.
🧰 Возможности:
• Многопротокольные пинги: ICMP, TCP, UDP и HTTP — проверка доступности и измерение задержек
• Управление интерфейсами: просмотр IP‑конфигураций, статистики и управление адаптерами в реальном времени
• Сканирование сети: обнаружение устройств, подсетей и открытых портов
• Современный UI: интерфейс на Avalonia + SukiUI с тёмной темой и графиками
• Кроссплатформенность: работает на Windows, macOS и Linux (на базе .NET)
• Открытый код: лицензия AGPL‑3.0 — можно адаптировать и дорабатывать
🛠 Установка:
🔹 Windows:
🖥 Github
NetSonar — это лёгкая и кроссплатформенная утилита, которая помогает диагностировать сеть, визуализировать данные и управлять сетевыми интерфейсами.
🧰 Возможности:
• Многопротокольные пинги: ICMP, TCP, UDP и HTTP — проверка доступности и измерение задержек
• Управление интерфейсами: просмотр IP‑конфигураций, статистики и управление адаптерами в реальном времени
• Сканирование сети: обнаружение устройств, подсетей и открытых портов
• Современный UI: интерфейс на Avalonia + SukiUI с тёмной темой и графиками
• Кроссплатформенность: работает на Windows, macOS и Linux (на базе .NET)
• Открытый код: лицензия AGPL‑3.0 — можно адаптировать и дорабатывать
🛠 Установка:
🔹 Windows:
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
⚖️ Monolith или microservices — не вопрос "что лучше".
Важно другое: каждая архитектура даёт свои плюсы и минусы.
Когда нужны микросервисы:
- независимые деплои
- разные технологии под сервисы
- гибкое масштабирование по частям
Все остальные выгоды можно получить и в монолите. Поэтому мой выбор чаще всего — modular monolith: проще, дешевле, без лишней сложности.
📖 Подробнее: https://milanjovanovic.tech/modular-monolith-architecture?utm_source=X&utm_medium=social&utm_campaign=01.09.2025
#Architecture #Monolith #Microservices #SoftwareEngineering
Важно другое: каждая архитектура даёт свои плюсы и минусы.
Когда нужны микросервисы:
- независимые деплои
- разные технологии под сервисы
- гибкое масштабирование по частям
Все остальные выгоды можно получить и в монолите. Поэтому мой выбор чаще всего — modular monolith: проще, дешевле, без лишней сложности.
📖 Подробнее: https://milanjovanovic.tech/modular-monolith-architecture?utm_source=X&utm_medium=social&utm_campaign=01.09.2025
#Architecture #Monolith #Microservices #SoftwareEngineering
🚫 EF Core + «репозитории» = лишний слой
Часто советуют заворачивать EF Core в Repository Pattern.
Но на практике это делает код только сложнее:
-
- Репозитории со временем превращаются в «монстров» с десятками методов
- Каждый новый фильтр = новая копипаста
В итоге — абстракция над абстракцией и трудности с поддержкой.
---
✅ Что вместо этого? Specification Pattern
Specification = маленький класс, описывающий правило или фильтр.
Вы комбинируете их и получаете сложные запросы без раздутых репозиториев.
Плюсы:
- 🧩 Простая композиция правил
- 🔍 Ясный и читаемый код
- ♻️ Повторное использование условий
- 🧪 Лёгкое тестирование
📌 Пример
💡 Итог:
EF Core = уже Repository + UoW
Репозитории поверх EF Core → лишняя абстракция
Specification Pattern → гибкость и читаемость без «метод-монстров»
Часто советуют заворачивать EF Core в Repository Pattern.
Но на практике это делает код только сложнее:
-
DbContext
уже реализует Repository и Unit of Work - Репозитории со временем превращаются в «монстров» с десятками методов
- Каждый новый фильтр = новая копипаста
В итоге — абстракция над абстракцией и трудности с поддержкой.
---
✅ Что вместо этого? Specification Pattern
Specification = маленький класс, описывающий правило или фильтр.
Вы комбинируете их и получаете сложные запросы без раздутых репозиториев.
Плюсы:
- 🧩 Простая композиция правил
- 🔍 Ясный и читаемый код
- ♻️ Повторное использование условий
- 🧪 Лёгкое тестирование
📌 Пример
// Бизнес-правило: активные клиенты с заказами за последние 30 дней
public sealed class ActiveCustomersSpec : Specification<Customer>
{
public ActiveCustomersSpec(DateTime since)
{
Criteria = c => c.IsActive && c.Orders.Any(o => o.CreatedAt >= since);
AddInclude(c => c.Orders);
}
}
// Применение
var spec = new ActiveCustomersSpec(DateTime.UtcNow.AddDays(-30));
var customers = await db.Set<Customer>().Apply(spec).ToListAsync();
💡 Итог:
EF Core = уже Repository + UoW
Репозитории поверх EF Core → лишняя абстракция
Specification Pattern → гибкость и читаемость без «метод-монстров»
🔥 Успех в IT = скорость + знания + окружение
Здесь ты найдёшь всё это — коротко, по делу и без воды.
Пока другие ищут, где “подглядеть решение”, ты уже используешь самые свежие инструменты!
AI: t.iss.one/ai_machinelearning_big_data
Python: t.iss.one/pythonl
Linux: t.iss.one/linuxacademiya
Собеседования DS: t.iss.one/machinelearning_interview
C++ t.iss.one/cpluspluc
Docker: t.iss.one/DevopsDocker
Хакинг: t.iss.one/linuxkalii
Devops: t.iss.one/DevOPSitsec
Data Science: t.iss.one/data_analysis_ml
Javascript: t.iss.one/javascriptv
C#: t.iss.one/csharp_1001_notes
Java: t.iss.one/java_library
Базы данных: t.iss.one/sqlhub
Python собеседования: t.iss.one/python_job_interview
Мобильная разработка: t.iss.one/mobdevelop
Golang: t.iss.one/Golang_google
React: t.iss.one/react_tg
Rust: t.iss.one/rust_code
ИИ: t.iss.one/vistehno
PHP: t.iss.one/phpshka
Android: t.iss.one/android_its
Frontend: t.iss.one/front
Big Data: t.iss.one/bigdatai
МАТЕМАТИКА: t.iss.one/data_math
Kubernets: t.iss.one/kubernetc
Разработка игр: https://t.iss.one/gamedev
Haskell: t.iss.one/haskell_tg
Физика: t.iss.one/fizmat
💼 Папка с вакансиями: t.iss.one/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: t.iss.one/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: t.iss.one/addlist/eEPya-HF6mkxMGIy
Папка ML: https://t.iss.one/addlist/2Ls-snqEeytkMDgy
Папка FRONTEND: https://t.iss.one/addlist/mzMMG3RPZhY2M2Iy
😆ИТ-Мемы: t.iss.one/memes_prog
🇬🇧Английский: t.iss.one/english_forprogrammers
🧠ИИ: t.iss.one/vistehno
🎓954ГБ ОПЕНСОРС КУРСОВ: @courses
📕Ит-книги бесплатно: https://t.iss.one/addlist/BkskQciUW_FhNjEy
Подпишись, если хочешь быть в числе тех, кого зовут в топовые проекты!
Здесь ты найдёшь всё это — коротко, по делу и без воды.
Пока другие ищут, где “подглядеть решение”, ты уже используешь самые свежие инструменты!
AI: t.iss.one/ai_machinelearning_big_data
Python: t.iss.one/pythonl
Linux: t.iss.one/linuxacademiya
Собеседования DS: t.iss.one/machinelearning_interview
C++ t.iss.one/cpluspluc
Docker: t.iss.one/DevopsDocker
Хакинг: t.iss.one/linuxkalii
Devops: t.iss.one/DevOPSitsec
Data Science: t.iss.one/data_analysis_ml
Javascript: t.iss.one/javascriptv
C#: t.iss.one/csharp_1001_notes
Java: t.iss.one/java_library
Базы данных: t.iss.one/sqlhub
Python собеседования: t.iss.one/python_job_interview
Мобильная разработка: t.iss.one/mobdevelop
Golang: t.iss.one/Golang_google
React: t.iss.one/react_tg
Rust: t.iss.one/rust_code
ИИ: t.iss.one/vistehno
PHP: t.iss.one/phpshka
Android: t.iss.one/android_its
Frontend: t.iss.one/front
Big Data: t.iss.one/bigdatai
МАТЕМАТИКА: t.iss.one/data_math
Kubernets: t.iss.one/kubernetc
Разработка игр: https://t.iss.one/gamedev
Haskell: t.iss.one/haskell_tg
Физика: t.iss.one/fizmat
💼 Папка с вакансиями: t.iss.one/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: t.iss.one/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: t.iss.one/addlist/eEPya-HF6mkxMGIy
Папка ML: https://t.iss.one/addlist/2Ls-snqEeytkMDgy
Папка FRONTEND: https://t.iss.one/addlist/mzMMG3RPZhY2M2Iy
😆ИТ-Мемы: t.iss.one/memes_prog
🇬🇧Английский: t.iss.one/english_forprogrammers
🧠ИИ: t.iss.one/vistehno
🎓954ГБ ОПЕНСОРС КУРСОВ: @courses
📕Ит-книги бесплатно: https://t.iss.one/addlist/BkskQciUW_FhNjEy
Подпишись, если хочешь быть в числе тех, кого зовут в топовые проекты!
⚡ C# полезный совет
Хотите ускорить работу со строками, когда нужно часто их конкатенировать?
Не используйте обычный
Вместо этого применяйте `StringBuilder`:
📌 Что это даёт:
- StringBuilder не создаёт новую строку при каждой операции
- Сильно экономит память и ускоряет код в циклах
- Особенно полезно при работе с большими логами или генерацией отчётов
Хотите ускорить работу со строками, когда нужно часто их конкатенировать?
Не используйте обычный
+
в цикле — это создаёт лишние объекты в памяти. Вместо этого применяйте `StringBuilder`:
using System.Text;
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
sb.Append("строка ").Append(i).AppendLine();
}
string result = sb.ToString();
Console.WriteLine(result);
📌 Что это даёт:
- StringBuilder не создаёт новую строку при каждой операции
- Сильно экономит память и ускоряет код в циклах
- Особенно полезно при работе с большими логами или генерацией отчётов
⚡ .NET Aspire позволяет запускать фронтенд прямо из Vite
В Community Toolkit появился пакет `Aspire.Hosting.NodeJS.Extensions`, который позволяет интегрировать Node.js-приложения в .NET Aspire.
🔥 Что он даёт:
- Запуск Vite-приложений напрямую из Aspire.
- Поддержка npm, Yarn и pnpm — выбирай свой пакетный менеджер.
- Автоустановка зависимостей перед стартом (`WithNpmPackageInstallation()`,
- Лёгкая интеграция фронтенда и бэкенда: всё управляется из одного места.
📌 Пример кода:
💡 Итог: теперь запуск React/Vue/Angular через Vite можно встроить прямо в Aspire, без лишних шагов и костылей.
📌 Подробнее
#dotnet #Aspire #NodeJS #Vite #Frontend
В Community Toolkit появился пакет `Aspire.Hosting.NodeJS.Extensions`, который позволяет интегрировать Node.js-приложения в .NET Aspire.
🔥 Что он даёт:
- Запуск Vite-приложений напрямую из Aspire.
- Поддержка npm, Yarn и pnpm — выбирай свой пакетный менеджер.
- Автоустановка зависимостей перед стартом (`WithNpmPackageInstallation()`,
WithYarnPackageInstallation()
, `WithPnpmPackageInstallation()`). - Лёгкая интеграция фронтенда и бэкенда: всё управляется из одного места.
📌 Пример кода:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddViteApp("vite-demo")
.WithExternalHttpEndpoints();
builder.AddViteApp("yarn-demo", packageManager: "yarn")
.WithExternalHttpEndpoints();
builder.AddViteApp("pnpm-demo", packageManager: "pnpm")
.WithExternalHttpEndpoints();
builder.Build().Run();
💡 Итог: теперь запуск React/Vue/Angular через Vite можно встроить прямо в Aspire, без лишних шагов и костылей.
📌 Подробнее
#dotnet #Aspire #NodeJS #Vite #Frontend
📌 Что это такое
- Приложение-пример на .NET, которое реализует веб-сайт электронной коммерции (eCommerce) с архитектурой, основанной на сервисах.
- Использует .NET 9.
- Код лицензирован по MIT.
📌 Как запустить
- Клонировать репозиторий.
- Установить .NET 9 SDK.
- Для Windows: можно использовать Visual Studio (2022 17.10+).
- Можно запустить через Docker Desktop.
- Через терминал:
```bash
dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj
📌 Особенности
Пример данных каталога хранится в catalog.json, описания продуктов и брендов — вымышленные.
Изображения продуктов сгенерированы с помощью DALL·E 3.
Есть версия приложения, подготовленная для деплоя в Azure.
📌 Почему полезно
- Подходит как учебный материал для изучения структуры реального .NET-приложения.
- Демонстрирует современные практики: архитектура, CI/CD, микросервисы.
- Можно использовать как стартовую точку для собственных проектов.
#dotnet #eCommerce #ReferenceApp #MIT #Architecture #SampleProject #Microservices
Репозиторий: https://github.com/dotnet/eShop
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥 Лучшая фича C# за последние годы? Pattern Matching
Зачем он нужен:
Pattern matching позволяет элегантно проверять объект на определённые свойства:
- ✅ Является
- ✅ Является объектом конкретного типа
- ✅ Имеет свойство с определённым значением
В связке со switch-выражениями и record-типами это превращает код в лаконичный и выразительный.
📌 Пример:
Зачем он нужен:
Pattern matching позволяет элегантно проверять объект на определённые свойства:
- ✅ Является
null
или не null
- ✅ Является объектом конкретного типа
- ✅ Имеет свойство с определённым значением
В связке со switch-выражениями и record-типами это превращает код в лаконичный и выразительный.
📌 Пример:
static string PrintShape(object shape) =>
shape switch
{
null => "Нет объекта",
Circle c => $"Круг с радиусом {c.Radius}",
Rectangle { Width: > 0, Height: > 0 } r => $"Прямоугольник {r.Width}x{r.Height}",
_ => "Неизвестная фигура"
};
В .NET 8 и выше есть библиотеки от Microsoft и обновлённый API Polly — популярной библиотеки для повышения надёжности и обработки сбоев.
С Polly можно легко настроить стратегии:
- повтор запросов (Retry)
- резервные сценарии (Fallback)
- ограничение времени (Timeout)
- контроль частоты (Rate-limiting)
- автоматическое отключение при сбоях (Circuit breaker)
Эти механизмы помогают облачным приложениям оставаться живыми даже в условиях ошибок и перегрузок.
Подробный разбор тут
Please open Telegram to view this post
VIEW IN TELEGRAM
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Что мне нравится в **.NET Aspire** 👇
👉 С ним невероятно просто запускать полезные сервисы. Всего в несколько строк кода можно поднять:
- базу данных
- Redis
- LLM
- reverse proxy
- message broker
Можно даже масштабировать сервисы, чтобы проверить сценарии с конкурентной нагрузкой.
Если вы ещё не пробовали построить своё первое Aspire-приложение — у меня есть подробный гайд о том, как я мигрировал свой .NET проект в Aspire.
🟠 Читать здесь: https://milanjovanovic.tech/blog/dotnet-aspire-a-game-changer-for-cloud-native-development
👉 С ним невероятно просто запускать полезные сервисы. Всего в несколько строк кода можно поднять:
- базу данных
- Redis
- LLM
- reverse proxy
- message broker
Можно даже масштабировать сервисы, чтобы проверить сценарии с конкурентной нагрузкой.
Если вы ещё не пробовали построить своё первое Aspire-приложение — у меня есть подробный гайд о том, как я мигрировал свой .NET проект в Aspire.
Please open Telegram to view this post
VIEW IN TELEGRAM