Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Uçtan Uca: Bookstore Sipariş Belgeleri — Fatura PDF'i, Onay E-postası ve Aylık Excel Raporunun Job Zinciri
Sipariş belgelerini Hangfire ile iki adımlı bir zincire bağla: fatura job'ı PDF'i storage'a yazar, continuation onay e-postasını outbox'a koyar; her adımın anahtarı yazdığı şeyin kendisi olduğu için tekrarlar zararsızdır. Bookstore'da storage kapalıyken yalnız fatura adımı tekrar denendi, aynı sipariş iki kez geldiğinde tek PDF ve tek e-posta çıktı; aylık rapor İstanbul saatiyle recurring job.
Dosya Depolama Abstraction'ı: Local Disk, Azure Blob Storage ve S3; Presigned/SAS URL ile Doğrudan Yükleme
Dosyaları tek bir IFileStore arkasında tut: local diskte path'i iki kez doğrula, Azure Blob ve S3'te indirme ve yükleme için birkaç dakikalık SAS ya da presigned URL ver ve yüklenen dosyayı ancak "tamamla" adımında kontrol et, çünkü storage boyuta ve içeriğe bakmıyor. Bookstore'un faturaları ve kapakları Azurite ve RustFS ile denendi; metadata veritabanında kalıyor.
.NET'te Görsel İşleme: ImageSharp ve SkiaSharp ile Resize, Format Dönüşümü, EXIF ve Güvenli İşleme
Yüklenen görseli önce ilk byte'larından ve piksel sayısından doğrula, sonra EXIF yönünü uygulayıp küçült ve metadata'sız WebP olarak kaydet. Bookstore'un kapak thumbnail'ları SkiaSharp (MIT) ile üretiliyor; ImageSharp 4 Release build'de lisans anahtarı istediği ve metadata'yı varsayılan olarak koruduğu için yalnız Debug örneğinde kaldı.
PDF Üretmek 2: HTML'den PDF (Playwright), PDF Okumak, Birleştirmek ve Hangisi Ne Zaman
Tasarımcının HTML ve CSS ile hazırladığı belgeyi Playwright'ın headless Chromium'u ile PDF'e çevir: browser'ı paylaş, her belgeye ayrı context aç, JavaScript'i kapat ve yalnız kendi font'larına izin ver. Bookstore'un kurumsal teklifi belge başına 38 milisaniyede çıkıyor; birleştirme ve okuma PdfPig ile, çünkü PDFsharp 6.5.0 ile AGPL'e geçti.
PDF Üretmek 1: QuestPDF ile Fatura ve Rapor, Font'lar ve Türkçe Karakterler
QuestPDF ile faturayı fluent layout'la kur, tablo başlığını her sayfada tekrarla, sayfa numarasını footer'a koy ve font'u uygulamayla dağıt: 2026.9'dan beri sistem font'ları varsayılan olarak kapalı ve eksik font ya da glyph exception fırlatıyor. Bookstore faturası paketteki Lato ile Türkçe karakterleri container'da da doğru basıyor; Community License satırı bir beyan, yıllık geliri 1 milyon USD altındaki şirketler için.
Excel Üretmek ve Okumak: ClosedXML ile Formatlı Rapor, Büyük Export'lar ve EPPlus Lisansı
Biçimlendirilmiş raporu ClosedXML ile üret; tarihi DateTime, ISBN'i metin, parayı number format ile yaz, dosyayı belleğe render edip Content-Disposition'daki filename* ile gönder. Büyük export'ta ClosedXML 100 bin satırda 368 MB, OpenXmlWriter 56 MB kullanıyor ama System.IO.Packaging yüzünden 1 milyonda 583 MB'a çıkıyor; sabit bellek için SpreadCheetah 8 MB'da kalıyor. EPPlus ise ticari kullanımda developer başına lisans istiyor.
E-posta Şablonları ve Güvenilir Gönderim: Razor HtmlRenderer, Inline CSS, Outbox, Retry ve Sağlayıcı API'leri
E-posta HTML'ini Razor component'i olarak yazıp HtmlRenderer ile string'e render et, CSS'i PreMailer.Net ile inline et, e-postayı iş verisiyle aynı transaction'da bir outbox satırına yaz ve 4xx'te takvimle tekrar dene, 5xx'te bırak. Bookstore'da onaylayıcıya giden TR/EN hatırlatma, Mailpit chaos'unun iki 451'inden sonra aynı Message-Id ile bir kez gidiyor; idempotency key ikinci çalıştırmayı engelliyor.
.NET'te E-posta Göndermek: MailKit ile SMTP, TLS ve Port'lar, Mailpit ile Local Test ve SmtpClient'ın Durumu
Yeni .NET projelerinde e-postayı System.Net.Mail.SmtpClient ile değil MailKit ile gönder: 587'de StartTls, 465'te SslOnConnect kullan, Auto'dan kaçın, bağlantıyı yeniden kullan ve parolayı secret'tan al. Bookstore'un sipariş onay e-postasını HTML, düz metin, inline logo ve ekli faturayla STARTTLS'li bir Mailpit'e gönderiyor, MIME yapısını ve 50 e-postada altı kata varan bağlantı farkını gerçek çıktılarla gösteriyoruz.
Backend'de Doküman ve Bildirim İşleri: Request İçinde mi Background Job'da mı, Kütüphane Lisansları ve Abstraction
Küçük ve hızlı dokümanı request içinde üretip stream et; yavaş, büyük ya da tekrar denenmesi gereken işi 202 Accepted ile kabul edip background job'a ver, hazır olunca e-postayla haber ver. Bookstore'da 8 saniyelik rapor senkron yolda 5 saniyede 504 dönüyor, asenkron yolda 16 ms'de 202; QuestPDF, EPPlus ve ImageSharp lisanslarını ve ImageSharp 4'ün Release build'i durduran lisans kontrolünü CI'da nuget-license ile takip ediyoruz.
.NET SDK'da .NET 6'dan 11'e Değişenler: Varsayılan Release Publish, Terminal Logger, .slnx, dnx, File-Based App'ler ve .NET 11 CLI
SDK'yı yükseltirken kırılan şey genellikle kod değil, sürümü tekrar eden yerlerdir: global.json'un errorMessage'ı, container image etiketleri ve CI adımları. .NET 6'dan 11'e SDK değişikliklerini tabloya döküyor, eski bir projeyi okumak için kontrol listesi veriyor, Bookstore'u net10.0'da tutarak SDK 11'e taşıyor ve MSBuild server'ın CI'daki etkisini ölçümlerle gösteriyoruz.
MSBuild'i Anlamak: Property, Item, Target, Task, Custom Target ve Binlog ile Build Hatası Ayıklamak
MSBuild bir projeyi iki fazda işler: evaluation'da property ve item'ları okur, execution'da target'ları çalıştırır; target'larda oluşan değerler evaluation'da görünmez. Bookstore'a commit ve yerel değişiklik bilgisini assembly'ye yazan, Angular istemcisini Inputs/Outputs ile incremental olarak publish'e ekleyen target'lar yazıyor, binlog ile bir property'nin nerede değiştiğini gerçek çıktılarla buluyoruz.
dotnet tool ve dotnet new Template'leri: Local Tool Manifest, dnx, Kendi Aracını ve Template'ini Paketlemek
Bir .NET aracını repoya bağlamanın yolu local tool manifest'tir: sürüm dotnet-tools.json'da commit'lenir ve CI dotnet tool restore ile başlar. bookstore-admin'i PackAsTool ile paketleyip şirket feed'inden Reporting'e kuruyor, dnx'in source mapping'e takılmasını, SDK 11'in NETSDK1235 uyarısını, bookstore-module template paketini ve #:include kullanan bir file-based script'i gerçek çıktılarla gösteriyoruz.