Generate Reports in C# Like Crystal Raporlar (.NET 10)
C# .NET'te IronPDF ile HTML'den PDF'ye rapor oluşturma, Crystal Raporlar'un tescilli .rpt tasarımcısını standart HTML, CSS ve Razor şablonlarıyla değiştirerek, .NET geliştiricilerinin sahip oldukları web geliştirme becerilerini kullanarak veri odaklı iş raporları oluşturmalarını sağlar. Bu, dinamik tablolar, JavaScript destekli grafikler, koşullu biçimlendirme, çoklu belge toplu işlem ve .NET çalıştıran herhangi bir ortamda çapraz platform dağıtımı için tam destek içerir.
Kısa-Özet: Hızlı Başlangıç Kılavuzu
Bu kılavuz, C# .NET içinde Crystal Raporlar'un yerini HTML'den PDF'e rapor oluşturma işlemi ile değiştirmeyi, temel şablonlardan toplu işlemeye ve planlı üretime kadar ele alır.
- Kimin İçindir: Crystal Raporlar'un yerini alan veya sıfırdan yeni raporlama sistemleri oluşturan .NET geliştiricileri.
- Ne Yapacaksınız: Üç tam rapor uygulaması (satış faturası, çalışan rehberi, envanter raporu) artı Chart.js görselleştirmeleri, markalı başlık/altlıklar, içindekiler tablosu oluşturma, alt rapor birleştirme ve paralel toplu işlem.
- Nerede Çalışır: .NET 10, .NET 8 LTS, .NET Framework 4.6.2+ ve .NET Standard 2.0. Sadece Windows'a özgü COM bağımlılıkları yok.
- Ne Zaman Bu Yaklaşımı Kullanmalı: Crystal Raporlar'un .NET Core desteği olmaması, Windows'a bağımlılık veya karmaşık lisanslama bir engel haline geldiğinde.
- Teknolojik Olarak Neden Önemli: HTML/CSS, platformlar arası aynı şekilde render alır, CI/CD entegrasyonu ile entegre olur ve grafikler için JavaScript'i çalıştırır, tüm bunları özel bir tasarımcı veya belge başına ücret olmadan yapar.
Kod örneklerini takip etmek için NuGet (Install-Package IronPdf) aracılığıyla IronPdf'yi yükleyin. İlk raporunuzu sadece birkaç satır kodla oluşturun:
-
IronPDF aşağıdaki NuGet Paket Yöneticisi ile yükleyin
PM > Install-Package IronPdf -
Bu kod parçacığını kopyalayın ve çalıştırın.
// Install-Package IronPdf var pdf = new IronPdf.ChromePdfRenderer() .RenderHtmlAsPdf("<h1>Sales Report</h1><table><tr><td>Q1</td><td>$50,000</td></tr></table>") .SaveAs("sales-report.pdf"); -
Canlı ortamınızda test için dağıtım yapın
Ücretsiz deneme ile bugün projenizde IronPDF kullanmaya başlayın
IronPDF'yi satın aldıktan veya 30 günlük denemeye kaydolduktan sonra, başvurunuzda lisans anahtarınızı ekleyin.
IronPdf.License.LicenseKey = "KEY";
IronPdf.License.LicenseKey = "KEY";
Imports IronPdf
IronPdf.License.LicenseKey = "KEY"
Bugün IronPDF ile projenizde ücretsiz bir deneme ile başlayın.
İçindekiler
- Özet: Hızlı Başlangıç Kılavuzu
- HTML Şablonlarından PDF Mimarisi
- Crystal Raporlar'u .NET Uygulamalarında Neden Değiştirmelisiniz
- NET 10'da C# Rapor Oluşturucu Kurulumu
- Veri Odaklı PDF Raporu Oluşturun C# ile
- IronPDF ile İleri Düzey C# Rapor Oluşturma
- Crystal Raporlar'tan IronPDF'e Geçiş
- Toplu Rapor Oluşturma ve .NET İçinde Planlama
- Tam Test Projesini İndirin
C# Report Generator: HTML Templates to PDF
HTML'den PDF'e dönüşüm, doğrusal bir mimari boru hattına dayanır. Özel bir dosya formatı yerine, uygulama standart veri modellerini populate etmek için Razor görünümleri veya HTML şablonları kullanır. Ortaya çıkan HTML dizesi daha sonra IronPdf gibi bir görüntüleme motoruna aktarılır ve bu motor görsel çıktıyı bir PDF belgesi olarak yakalar. Bu yaklaşım, rapor tasarımını barındırma ortamından bağımsız hale getirir ve aynı kodun .NET'i destekleyen herhangi bir platformda çalışmasına olanak tanır.
Bu iş akışı, standart web geliştirmesini yansıtır. Ön uç geliştiriciler, CSS kullanarak düzeni oluşturur ve bunu herhangi bir tarayıcıda hemen önizler. Arka uç geliştiriciler daha sonra veriyi C# kullanarak bağlar. Bu ayrım, ekiplerin raporlar için mevcut sürüm kontrolü, kod incelemesi ve sürekli dağıtım süreçlerini uygulamanın geri kalanında olduğu gibi kullanmalarına olanak tanır.
HTML, Crystal Raporlar'ta bulunmayan özellikler sunar: etkileşimli grafikler, duyarlı tablolar ve tutarlı markalama için paylaşılan stiller.
.NET Uygulamalarında Crystal Raporlar'u Neden Değiştirmelisiniz
Crystal Raporlar'tan uzaklaşma, tek bir büyük sorun veya SAP'nin ani terk edişi sonucu değildir. Bunun yerine, platformu yeni projeler için giderek daha zorlanır hale getiren ve mevcut çözümlerde bakımını zorlaştıran sürtünme noktalarının birikimidir. Bu acı noktalarının tanımlanması, birçok ekibin neden alternatifler aradığını ve alternatif seçenekleri değerlendirirken hangi ölçütlerin en önemli olduğunu netleştirir.
.NET 8 veya .NET Core Desteği Yok
Crystal Raporlar, .NET Core veya .NET 5-10'u desteklememektedir. SAP forumlarda destek eklemeyi planlamadıklarını belirtmiştir. SDK, çapraz platform .NET ile uyumsuz olan COM bileşenlerini kullanır. Modern .NET desteği, SAP'nin yapmayı reddettiği tam bir yeniden yazım gerektirir.
Sonuç olarak, yeni uygulamalarını mevcut .NET sürümlerinde oluşturan ekipler Crystal Raporlar'u kullanamaz. Standart hale gelmiş organizasyonlar .NET 8 veya .NET 10 üzerinde bunu entegre edemez. Mevcut uygulamalar için, modern bir .NET çalışma zamanı sürümüne geçmek, önce raporlama sistemini değiştirmeyi gerektirir.
Karmaşık Lisanslama ve Gizli Maliyetler
Crystal Raporlar lisanslaması, tasarımcı lisansları, çalıştırma lisansları, sunucu dağıtımları ve gömülü kullanım arasında ayrım yapar. Kurallar masaüstü, web ve terminal hizmetleri için değişir. Bir kurulumda uyum, diğerinde ek lisanslar gerektirebilir. Dağıtımdan sonra boşluklar ortaya çıkarsa, beklenmedik maliyetler oluşur. Birçok organizasyon, belirsizliğin daha net lisanslamaya sahip bir çözüm için geçiş yapmaktan daha kötü olduğuna karar verir.
Yalnızca Windows Bağımlılığı
Crystal Raporlar yalnızca Windows üzerinde ve eski.NET Framework ile çalışır. Bu uygulamaları Linux konteynerlerine, Linux üzerinde Azure App Service'e, AWS Lambda'ya veya Google Cloud Run'a dağıtamazsınız. Organizasyonlar konteyner tabanlı, platform-agno, ve sunucusuz sistemleri kullandıkça, bu kısıtlamalar daha önemli hale gelir.
Mikro hizmetler oluşturan geliştirme ekipleri ek zorluklarla karşı karşıya kalır. Dokuz hizmet hafif Linux konteynerlerinde çalışıyor ancak biri Crystal Raporlar için Windows'a ihtiyaç duyuyorsa, dağıtım daha karmaşık hale geliyor. Windows container görüntülerine, Windows uyumlu barındırmaya ve ayrı dağıtım ayarlarına ihtiyacınız var. Raporlama hizmeti bir istisna haline gelerek standartlaşmayı engeller.
Set Up a C# Report Generator in .NET 10
IronPDF ile başlamak basittir. Kütüphaneyi, diğer .NET bağımlılıkları gibi NuGet üzerinden yükleyin. Üretim sunucuları için indirilecek ekstra bir yazılım veya ayrı bir çalışma zamanı yükleyici yoktur.
Bir Şablon Yaklaşımı Seçin: Razor, HTML veya Hibrit
IronPDF, rapor şablonları oluşturmak için üç farklı yaklaşımı destekler. Her yaklaşım, ekip bileşimi, proje gereksinimleri ve uzun vadeli bakım düşünceleri gibi faktörlere bağlı olarak belirli avantajlar sunar.
Razor Görünümleri, halihazırda .NET ekosisteminde çalışan ekipler için en zengin geliştirme deneyimini sunar. Visual Studio ve VS Code'da tam IntelliSense desteği, derleme zamanı kontrolü ve döngüler, koşullar, null işlemleri ve dize biçimlendirme için tam C# gücü ile katı bir şekilde tipi belirtilmiş modeller mevcuttur. Razor'un sözdizimi, ASP.NET Core uygulamaları oluşturmuş olanlara aşinadır, böylece diğer ekosistemlerden gelen şablon motorlarıyla ilişkili öğrenme eğrisini ortadan kaldırır. Şablonlar, diğer kaynak dosyalarla paralel olarak projede yer alır, refaktörleme işlemlerine katılır ve normal derleme sürecinin bir parçası olarak derlenir.
Düz HTML ve Dize Interpolasyonu ile .NET kodundan tamamen ayrı tutmayı tercih eden ekipler veya daha basit raporlar için iyi çalışır. HTML şablonları, derlemeye derlenmiş gömülü kaynaklar, uygulama ile birlikte dağıtılan harici dosyalar olarak depolanabilir veya hatta çalışma zamanında bir veritabanından veya içerik yönetim sisteminden alınabilir. Temel veri bağlama, tekil değerler için string.Replace() kullanır veya daha gelişmiş senaryolar için Scriban veya Fluid gibi hafif şablon kütüphaneleri kullanır. Bu yaklaşım, taşınabilirliği en üst düzeye çıkarır, tasarımcıların yalnızca bir metin düzenleyici ve önizleme için bir web tarayıcısı kullanarak, her hangi bir .NET araç seti kurulu olmadan şablonları düzenlemesine olanak tanır.
Hibrit Yaklaşımlar, esneklik gerektiren senaryolar için her iki tekniği birleştirir. Örneğin, bir Razor görünümü, ana HTML yapısını oluşturmak için işlenebilir ve ardından görüş modeline uymayan dinamik elemanlar için ek dizi değişiklikleriyle sonradan işlenebilir. Alternatif olarak, bir geliştiricinin hazırlamadığı bir HTML şablonu yüklenebilir ve yalnızca karmaşık, veri odaklı bölümleri işlemek için Razor kısmi görünümleri kullanılabilir, ardından her şey birleştirilebilir. HTML'den PDF'ye dönüşüm, HTML kaynağına bağımsızdır ve her raporun ihtiyaçlarına göre yaklaşımları karıştırmanıza olanak tanır.
Bu seçenekler göz önüne alındığında, bu tutorial öncelikle Razor görünümlerine odaklanır çünkü bunlar tip güvenliği, bakım kolaylığı ve karakteristik zenginlik açısından tipik iş raporlama senaryoları için en iyi dengeyi sunar. Gelecekteki gereksinimler düz HTML şablonları ile çalışmayı içeriyorsa, her iki yöntem de HTML dizeleri ürettiğinden, beceriler doğrudan aktarılır.
Build a Data-Driven PDF Report in C
Bu bölüm, baştan sona bir satış faturası raporunun tamamlanmış oluşturulmasını gösterir. Örnek, tüm raporlar için temel deseni kapsar: verileri yapılandıran bir model tanımlayın, veriyi biçimlendirilmiş HTML'ye dönüştüren bir Razor şablonu oluşturun, o şablonu bir HTML dizisi olarak işleyin ve görüntüleme, e-posta gönderme veya arşivleme için hazır bir PDF belgesine dönüştürün.
HTML/CSS Rapor Şablonunu Oluşturun
İlk adım, veri modelini tanımlamaktır. Gerçek bir fatura, müşteri bilgileri, açıklamalar ve fiyatlandırma ile satır öğeleri, hesaplanan toplamlar, vergi işlemleri ve şirket tanıtım unsurlarını gerektirir. Model sınıfları, bu gruplaşmaları yansıtacak şekilde yapılandırılmalıdır:
// Invoice data model with customer, company, and line item details
public class InvoiceModel
{
public string InvoiceNumber { get; set; } = string.Empty;
public DateTime InvoiceDate { get; set; }
public DateTime DueDate { get; set; }
public CompanyInfo Company { get; set; } = new();
public CustomerInfo Customer { get; set; } = new();
public List<LineItem> Items { get; set; } = new();
// Computed totals - business logic stays in the model
public decimal Subtotal => Items.Sum(x => x.Total);
public decimal TaxRate { get; set; } = 0.08m;
public decimal TaxAmount => Subtotal * TaxRate;
public decimal GrandTotal => Subtotal + TaxAmount;
}
// Company details for invoice header
public class CompanyInfo
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string LogoPath { get; set; } = string.Empty;
}
// Customer billing information
public class CustomerInfo
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
// Individual invoice line item
public class LineItem
{
public string Description { get; set; } = string.Empty;
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Total => Quantity * UnitPrice;
}
// Invoice data model with customer, company, and line item details
public class InvoiceModel
{
public string InvoiceNumber { get; set; } = string.Empty;
public DateTime InvoiceDate { get; set; }
public DateTime DueDate { get; set; }
public CompanyInfo Company { get; set; } = new();
public CustomerInfo Customer { get; set; } = new();
public List<LineItem> Items { get; set; } = new();
// Computed totals - business logic stays in the model
public decimal Subtotal => Items.Sum(x => x.Total);
public decimal TaxRate { get; set; } = 0.08m;
public decimal TaxAmount => Subtotal * TaxRate;
public decimal GrandTotal => Subtotal + TaxAmount;
}
// Company details for invoice header
public class CompanyInfo
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string LogoPath { get; set; } = string.Empty;
}
// Customer billing information
public class CustomerInfo
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
// Individual invoice line item
public class LineItem
{
public string Description { get; set; } = string.Empty;
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Total => Quantity * UnitPrice;
}
Imports System
Imports System.Collections.Generic
Imports System.Linq
' Invoice data model with customer, company, and line item details
Public Class InvoiceModel
Public Property InvoiceNumber As String = String.Empty
Public Property InvoiceDate As DateTime
Public Property DueDate As DateTime
Public Property Company As New CompanyInfo()
Public Property Customer As New CustomerInfo()
Public Property Items As New List(Of LineItem)()
' Computed totals - business logic stays in the model
Public ReadOnly Property Subtotal As Decimal
Get
Return Items.Sum(Function(x) x.Total)
End Get
End Property
Public Property TaxRate As Decimal = 0.08D
Public ReadOnly Property TaxAmount As Decimal
Get
Return Subtotal * TaxRate
End Get
End Property
Public ReadOnly Property GrandTotal As Decimal
Get
Return Subtotal + TaxAmount
End Get
End Property
End Class
' Company details for invoice header
Public Class CompanyInfo
Public Property Name As String = String.Empty
Public Property Address As String = String.Empty
Public Property City As String = String.Empty
Public Property Phone As String = String.Empty
Public Property Email As String = String.Empty
Public Property LogoPath As String = String.Empty
End Class
' Customer billing information
Public Class CustomerInfo
Public Property Name As String = String.Empty
Public Property Address As String = String.Empty
Public Property City As String = String.Empty
Public Property Email As String = String.Empty
End Class
' Individual invoice line item
Public Class LineItem
Public Property Description As String = String.Empty
Public Property Quantity As Integer
Public Property UnitPrice As Decimal
Public ReadOnly Property Total As Decimal
Get
Return Quantity * UnitPrice
End Get
End Property
End Class
Subtotal, TaxAmount ve GrandTotal için hesaplanan özellikler modele dahil edilmiştir. Bu hesaplamalar modele ait olmalıdır, böylece Razor görünümleri sunuma odaklanırken model iş mantığını işler. Bu ayrım, bir HTML işlenmeden hesaplamaların doğrulanmasını sağlayarak birim testleri kolay yapar.
Şimdi bu modeli profesyonelce biçimlendirilmiş bir faturaya dönüştüren Razor görünümünü oluşturun. Bunu Views klasörünüzde InvoiceTemplate.cshtml olarak kaydedin:
@model InvoiceModel
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
/* Reset and base styles */
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 12px; color: #333; line-height: 1.5; }
.invoice-container { max-width: 800px; margin: 0 auto; padding: 40px; }
/* Header with company info and invoice title */
.header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 40px; padding-bottom: 20px; border-bottom: 2px solid #3498db; }
.company-info h1 { font-size: 24px; color: #2c3e50; margin-bottom: 10px; }
.company-info p { color: #7f8c8d; font-size: 11px; }
.invoice-title { text-align: right; }
.invoice-title h2 { font-size: 32px; color: #3498db; margin-bottom: 10px; }
.invoice-title p { font-size: 12px; color: #7f8c8d; }
/* Address blocks */
.addresses { display: flex; justify-content: space-between; margin-bottom: 30px; }
.address-block { width: 45%; }
.address-block h3 { font-size: 11px; text-transform: uppercase; color: #95a5a6; margin-bottom: 8px; letter-spacing: 1px; }
.address-block p { font-size: 12px; }
/* Line items table */
.items-table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }
.items-table th { background-color: #3498db; color: white; padding: 12px; text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }
.items-table th:last-child, .items-table td:last-child { text-align: right; }
.items-table td { padding: 12px; border-bottom: 1px solid #ecf0f1; }
.items-table tr:nth-child(even) { background-color: #f9f9f9; }
/* Totals section */
.totals { float: right; width: 300px; }
.totals-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #ecf0f1; }
.totals-row.grand-total { border-bottom: none; border-top: 2px solid #3498db; font-size: 16px; font-weight: bold; color: #2c3e50; padding-top: 12px; }
/* Footer */
.footer { clear: both; margin-top: 60px; padding-top: 20px; border-top: 1px solid #ecf0f1; text-align: center; color: #95a5a6; font-size: 10px; }
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<div class="company-info">
<h1>@Model.Company.Name</h1>
<p>@Model.Company.Address</p>
<p>@Model.Company.City</p>
<p>@Model.Company.Phone | @Model.Company.Email</p>
</div>
<div class="invoice-title">
<h2>INVOICE</h2>
<p>Invoice #: @Model.InvoiceNumber</p>
<p>Date: @Model.InvoiceDate.ToString("MMMM dd, yyyy")</p>
<p>Due Date: @Model.DueDate.ToString("MMMM dd, yyyy")</p>
</div>
</div>
<div class="addresses">
<div class="address-block">
<h3>Bill To</h3>
<p>@Model.Customer.Name</p>
<p>@Model.Customer.Address</p>
<p>@Model.Customer.City</p>
<p>@Model.Customer.Email</p>
</div>
</div>
<table class="items-table">
<thead>
<tr><th>Description</th><th>Quantity</th><th>Unit Price</th><th>Total</th></tr>
</thead>
<tbody>
@foreach (var item in Model.Items)
{
<tr>
<td>@item.Description</td>
<td>@item.Quantity</td>
<td>@item.UnitPrice.ToString("C")</td>
<td>@item.Total.ToString("C")</td>
</tr>
}
</tbody>
</table>
<div class="totals">
<div class="totals-row"><span>Subtotal:</span><span>@Model.Subtotal.ToString("C")</span></div>
<div class="totals-row"><span>Tax (@(Model.TaxRate * 100)%):</span><span>@Model.TaxAmount.ToString("C")</span></div>
<div class="totals-row grand-total"><span>Total Due:</span><span>@Model.GrandTotal.ToString("C")</span></div>
</div>
<div class="footer">
<p>Thank you for your business!</p>
<p>Payment is due within 30 days. Please include invoice number with your payment.</p>
</div>
</div>
</body>
</html>
@model InvoiceModel
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
/* Reset and base styles */
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 12px; color: #333; line-height: 1.5; }
.invoice-container { max-width: 800px; margin: 0 auto; padding: 40px; }
/* Header with company info and invoice title */
.header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 40px; padding-bottom: 20px; border-bottom: 2px solid #3498db; }
.company-info h1 { font-size: 24px; color: #2c3e50; margin-bottom: 10px; }
.company-info p { color: #7f8c8d; font-size: 11px; }
.invoice-title { text-align: right; }
.invoice-title h2 { font-size: 32px; color: #3498db; margin-bottom: 10px; }
.invoice-title p { font-size: 12px; color: #7f8c8d; }
/* Address blocks */
.addresses { display: flex; justify-content: space-between; margin-bottom: 30px; }
.address-block { width: 45%; }
.address-block h3 { font-size: 11px; text-transform: uppercase; color: #95a5a6; margin-bottom: 8px; letter-spacing: 1px; }
.address-block p { font-size: 12px; }
/* Line items table */
.items-table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }
.items-table th { background-color: #3498db; color: white; padding: 12px; text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }
.items-table th:last-child, .items-table td:last-child { text-align: right; }
.items-table td { padding: 12px; border-bottom: 1px solid #ecf0f1; }
.items-table tr:nth-child(even) { background-color: #f9f9f9; }
/* Totals section */
.totals { float: right; width: 300px; }
.totals-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #ecf0f1; }
.totals-row.grand-total { border-bottom: none; border-top: 2px solid #3498db; font-size: 16px; font-weight: bold; color: #2c3e50; padding-top: 12px; }
/* Footer */
.footer { clear: both; margin-top: 60px; padding-top: 20px; border-top: 1px solid #ecf0f1; text-align: center; color: #95a5a6; font-size: 10px; }
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<div class="company-info">
<h1>@Model.Company.Name</h1>
<p>@Model.Company.Address</p>
<p>@Model.Company.City</p>
<p>@Model.Company.Phone | @Model.Company.Email</p>
</div>
<div class="invoice-title">
<h2>INVOICE</h2>
<p>Invoice #: @Model.InvoiceNumber</p>
<p>Date: @Model.InvoiceDate.ToString("MMMM dd, yyyy")</p>
<p>Due Date: @Model.DueDate.ToString("MMMM dd, yyyy")</p>
</div>
</div>
<div class="addresses">
<div class="address-block">
<h3>Bill To</h3>
<p>@Model.Customer.Name</p>
<p>@Model.Customer.Address</p>
<p>@Model.Customer.City</p>
<p>@Model.Customer.Email</p>
</div>
</div>
<table class="items-table">
<thead>
<tr><th>Description</th><th>Quantity</th><th>Unit Price</th><th>Total</th></tr>
</thead>
<tbody>
@foreach (var item in Model.Items)
{
<tr>
<td>@item.Description</td>
<td>@item.Quantity</td>
<td>@item.UnitPrice.ToString("C")</td>
<td>@item.Total.ToString("C")</td>
</tr>
}
</tbody>
</table>
<div class="totals">
<div class="totals-row"><span>Subtotal:</span><span>@Model.Subtotal.ToString("C")</span></div>
<div class="totals-row"><span>Tax (@(Model.TaxRate * 100)%):</span><span>@Model.TaxAmount.ToString("C")</span></div>
<div class="totals-row grand-total"><span>Total Due:</span><span>@Model.GrandTotal.ToString("C")</span></div>
</div>
<div class="footer">
<p>Thank you for your business!</p>
<p>Payment is due within 30 days. Please include invoice number with your payment.</p>
</div>
</div>
</body>
</html>
Bu şablonda gömülü CSS, renkler, yazı tipleri, boşluklar ve tablo biçimlendirmesi gibi tüm görsel stilleri yönetir. IronPDF ayrıca flexbox, grid düzenleri ve CSS değişkenleri gibi modern CSS özelliklerini de destekler. Oluşturulan PDF, Chrome'un yazdırma önizlemesi ile tam olarak eşleşir, bu da hata ayıklamayı kolaylaştırır: PDF'de yanlış görünen bir şey varsa, HTML'yi bir tarayıcıda açın ve stilleri incelemek ve ayarlamak için geliştirici araçlarını kullanın.
Verileri Şablona Bağlayın
Model ve şablon hazır olduğunda, PDF'yi oluşturmak için bunları IronPDF'nin ChromePdfRenderer aracılığıyla birbirine bağlamak gerekir. Anahtar adım, Razor görünümünü bir HTML dizisine dönüştürmek ve ardından bu diziyi işlemciye geçirmektir:
using IronPdf;
// Service class for generating invoice PDFs from Razor views
public class InvoiceReportService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public InvoiceReportService(
IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
// Generate PDF from invoice model
public async Task<byte[]> GenerateInvoicePdfAsync(InvoiceModel invoice)
{
// Render Razor view to HTML string
string html = await RenderViewToStringAsync("InvoiceTemplate", invoice);
// Configure PDF renderer with margins and paper size
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
// Convert HTML to PDF and return bytes
var pdfDocument = renderer.RenderHtmlAsPdf(html);
return pdfDocument.BinaryData;
}
// Helper method to render a Razor view to string
private async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
{
var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using var stringWriter = new StringWriter();
var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
if (!viewResult.Success)
throw new InvalidOperationException($"View '{viewName}' not found.");
var viewDictionary = new ViewDataDictionary<TModel>(
new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model };
var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary,
new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
stringWriter, new HtmlHelperOptions());
await viewResult.View.RenderAsync(viewContext);
return stringWriter.ToString();
}
}
using IronPdf;
// Service class for generating invoice PDFs from Razor views
public class InvoiceReportService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public InvoiceReportService(
IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
// Generate PDF from invoice model
public async Task<byte[]> GenerateInvoicePdfAsync(InvoiceModel invoice)
{
// Render Razor view to HTML string
string html = await RenderViewToStringAsync("InvoiceTemplate", invoice);
// Configure PDF renderer with margins and paper size
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
// Convert HTML to PDF and return bytes
var pdfDocument = renderer.RenderHtmlAsPdf(html);
return pdfDocument.BinaryData;
}
// Helper method to render a Razor view to string
private async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
{
var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using var stringWriter = new StringWriter();
var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
if (!viewResult.Success)
throw new InvalidOperationException($"View '{viewName}' not found.");
var viewDictionary = new ViewDataDictionary<TModel>(
new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model };
var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary,
new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
stringWriter, new HtmlHelperOptions());
await viewResult.View.RenderAsync(viewContext);
return stringWriter.ToString();
}
}
Imports IronPdf
Imports Microsoft.AspNetCore.Mvc.Razor
Imports Microsoft.AspNetCore.Mvc.ViewFeatures
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.AspNetCore.Http
Imports Microsoft.AspNetCore.Mvc
Imports Microsoft.AspNetCore.Routing
Imports System.IO
Imports System.Threading.Tasks
' Service class for generating invoice PDFs from Razor views
Public Class InvoiceReportService
Private ReadOnly _razorViewEngine As IRazorViewEngine
Private ReadOnly _tempDataProvider As ITempDataProvider
Private ReadOnly _serviceProvider As IServiceProvider
Public Sub New(razorViewEngine As IRazorViewEngine, tempDataProvider As ITempDataProvider, serviceProvider As IServiceProvider)
_razorViewEngine = razorViewEngine
_tempDataProvider = tempDataProvider
_serviceProvider = serviceProvider
End Sub
' Generate PDF from invoice model
Public Async Function GenerateInvoicePdfAsync(invoice As InvoiceModel) As Task(Of Byte())
' Render Razor view to HTML string
Dim html As String = Await RenderViewToStringAsync("InvoiceTemplate", invoice)
' Configure PDF renderer with margins and paper size
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter
' Convert HTML to PDF and return bytes
Dim pdfDocument = renderer.RenderHtmlAsPdf(html)
Return pdfDocument.BinaryData
End Function
' Helper method to render a Razor view to string
Private Async Function RenderViewToStringAsync(Of TModel)(viewName As String, model As TModel) As Task(Of String)
Dim httpContext As New DefaultHttpContext With {.RequestServices = _serviceProvider}
Dim actionContext As New ActionContext(httpContext, New RouteData(), New ActionDescriptor())
Using stringWriter As New StringWriter()
Dim viewResult = _razorViewEngine.FindView(actionContext, viewName, False)
If Not viewResult.Success Then
Throw New InvalidOperationException($"View '{viewName}' not found.")
End If
Dim viewDictionary As New ViewDataDictionary(Of TModel)(
New EmptyModelMetadataProvider(), New ModelStateDictionary()) With {.Model = model}
Dim viewContext As New ViewContext(actionContext, viewResult.View, viewDictionary,
New TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
stringWriter, New HtmlHelperOptions())
Await viewResult.View.RenderAsync(viewContext)
Return stringWriter.ToString()
End Using
End Function
End Class
Konsol uygulaması veya arka plan hizmeti gibi, tam .NET Core MVC kurulumuna ihtiyaç duymadığınız daha basit senaryolarda, dinamik kısımlar için interpolasyonlu HTML dizeleri ve StringBuilder kullanabilirsiniz.
Örnek Çıktı
Başlık, Alt Bilgi ve Sayfa Numaraları Ekle
Profesyonel raporlar genellikle şirket tanıtımı, belge başlıkları, oluşturma tarihleri ve sayfa numaraları gösteren tutarlı başlıklar ve alt bilgiler içerir. IronPDF, bu unsurların uygulanması için iki yaklaşım sunar: minimal format gerektiren basit içerikler için metin tabanlı başlıklar ve logolar ve özel düzenlerle tam stil kontrolü için HTML başlıkları.
Text-based headers work well for basic information and render faster since they don't require additional HTML parsing:
:path=/static-assets/pdf/content-code-examples/tutorials/crystal-reports-alternative-csharp/text-headers-footers.cs
using IronPdf;
using IronSoftware.Drawing;
// Configure text-based headers and footers
var renderer = new ChromePdfRenderer();
// Set starting page number
renderer.RenderingOptions.FirstPageNumber = 1;
// Add centered header with divider line
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
CenterText = "CONFIDENTIAL - Internal Use Only",
DrawDividerLine = true,
Font = FontTypes.Arial,
FontSize = 10
};
// Add footer with date on left, page numbers on right
renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
LeftText = "{date} {time}",
RightText = "Page {page} of {total-pages}",
DrawDividerLine = true,
Font = FontTypes.Arial,
FontSize = 9
};
// Set margins to accommodate header/footer
renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 20;
Imports IronPdf
Imports IronSoftware.Drawing
' Configure text-based headers and footers
Dim renderer As New ChromePdfRenderer()
' Set starting page number
renderer.RenderingOptions.FirstPageNumber = 1
' Add centered header with divider line
renderer.RenderingOptions.TextHeader = New TextHeaderFooter With {
.CenterText = "CONFIDENTIAL - Internal Use Only",
.DrawDividerLine = True,
.Font = FontTypes.Arial,
.FontSize = 10
}
' Add footer with date on left, page numbers on right
renderer.RenderingOptions.TextFooter = New TextHeaderFooter With {
.LeftText = "{date} {time}",
.RightText = "Page {page} of {total-pages}",
.DrawDividerLine = True,
.Font = FontTypes.Arial,
.FontSize = 9
}
' Set margins to accommodate header/footer
renderer.RenderingOptions.MarginTop = 25
renderer.RenderingOptions.MarginBottom = 20
Kullanılabilir birleştirme alanları arasında geçerli sayfa numarası için {page}, belgenin toplam sayfa sayısı için {total-pages}, oluşturma zaman damgaları için {date} ve {time}, web sayfasından görüntüleniyorsa kaynak URL için {url} bir web sayfasından görüntüleniyorsa kaynak URL'si için ve {html-title} ile {pdf-title} belge başlıkları içindir. Bu yer tutucular, işleme sırasında otomatik olarak değiştirilir.
Logolar, özel yazı tipleri veya karmaşık çok sütunlu düzenler içeren başlıklar için tam CSS stil desteği sunan HTML başlıklarını kullanın:
:path=/static-assets/pdf/content-code-examples/tutorials/crystal-reports-alternative-csharp/html-headers-footers.cs
using IronPdf;
using System;
var renderer = new ChromePdfRenderer();
// Configure HTML header with logo and custom layout
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
MaxHeight = 30,
HtmlFragment = @"
<div style='display: flex; justify-content: space-between; align-items: center;
width: 100%; font-family: Arial; font-size: 10px; color: #666;'>
<img src='logo.png' style='height: 25px;'>
<span>Company Name Inc.</span>
<span>Invoice Report</span>
</div>",
BaseUrl = new Uri(@"C:\assets\images\").AbsoluteUri
};
// Configure HTML footer with page info and generation date
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
MaxHeight = 20,
HtmlFragment = @"
<div style='text-align: center; font-size: 9px; color: #999;
border-top: 1px solid #ddd; padding-top: 5px;'>
Page {page} of {total-pages} | Generated on {date}
</div>",
DrawDividerLine = false
};
Imports IronPdf
Imports System
Dim renderer As New ChromePdfRenderer()
' Configure HTML header with logo and custom layout
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.MaxHeight = 30,
.HtmlFragment = "
<div style='display: flex; justify-content: space-between; align-items: center;
width: 100%; font-family: Arial; font-size: 10px; color: #666;'>
<img src='logo.png' style='height: 25px;'>
<span>Company Name Inc.</span>
<span>Invoice Report</span>
</div>",
.BaseUrl = New Uri("C:\assets\images\").AbsoluteUri
}
' Configure HTML footer with page info and generation date
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.MaxHeight = 20,
.HtmlFragment = "
<div style='text-align: center; font-size: 9px; color: #999;
border-top: 1px solid #ddd; padding-top: 5px;'>
Page {page} of {total-pages} | Generated on {date}
</div>",
.DrawDividerLine = False
}
Örnek Çıktı
Dinamik Tablolar ve Tekrarlayan Bölümler Oluşturun
Raporlar genellikle birden çok sayfaya yayılmış veri koleksiyonlarını göstermelidir. Razor'un döngü yapıları, koleksiyonlar üzerinde yineleme yaparak ve her öğe için tablo satırları veya kart elemanları oluşturarak bu durumu doğal olarak ele alır.
İşte, departman bölümleriyle gruplandırılmış veri sunumunu gösteren eksiksiz bir Çalışan Dizini örneği:
// Employee directory data models
public class EmployeeDirectoryModel
{
public List<Department> Departments { get; set; } = new();
public DateTime GeneratedDate { get; set; } = DateTime.Now;
}
// Department grouping with manager info
public class Department
{
public string Name { get; set; } = string.Empty;
public string ManagerName { get; set; } = string.Empty;
public List<Employee> Employees { get; set; } = new();
}
// Individual employee details
public class Employee
{
public string Name { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string PhotoUrl { get; set; } = string.Empty;
public DateTime HireDate { get; set; }
}
// Employee directory data models
public class EmployeeDirectoryModel
{
public List<Department> Departments { get; set; } = new();
public DateTime GeneratedDate { get; set; } = DateTime.Now;
}
// Department grouping with manager info
public class Department
{
public string Name { get; set; } = string.Empty;
public string ManagerName { get; set; } = string.Empty;
public List<Employee> Employees { get; set; } = new();
}
// Individual employee details
public class Employee
{
public string Name { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string PhotoUrl { get; set; } = string.Empty;
public DateTime HireDate { get; set; }
}
' Employee directory data models
Public Class EmployeeDirectoryModel
Public Property Departments As List(Of Department) = New List(Of Department)()
Public Property GeneratedDate As DateTime = DateTime.Now
End Class
' Department grouping with manager info
Public Class Department
Public Property Name As String = String.Empty
Public Property ManagerName As String = String.Empty
Public Property Employees As List(Of Employee) = New List(Of Employee)()
End Class
' Individual employee details
Public Class Employee
Public Property Name As String = String.Empty
Public Property Title As String = String.Empty
Public Property Email As String = String.Empty
Public Property Phone As String = String.Empty
Public Property PhotoUrl As String = String.Empty
Public Property HireDate As DateTime
End Class
Department sınıfındaki page-break-inside: avoid CSS özelliği, PDF oluşturucuya mümkün olduğunda departman bölümlerini tek bir sayfada bir arada tutmasını söyler. Eğer bir departmanın içeriği bölümler arası bir sayfa kırılmasına neden olursa, işlemci tüm bölümü bir sonraki sayfaya taşır. .department:not(:first-child) seçici ile page-break-before: always, ilk bölümden sonraki her bölümün yeni bir sayfada başlamasını sağlar ve dizin genelinde net bölüm ayrımı oluşturur.
Örnek Çıktı
Advanced C# Report Generation With IronPDF
İş raporları sıklıkla statik tablolar ve metinlerin ötesinde yetenekler gerektirir. Grafikler, tablolaşmış haliyle anlaması zor olabilecek eğilimleri görselleştirir. Koşullu biçimlendirme, müdahale gerektiren öğelere dikkat çeker. Alt raporlar, birden fazla kaynaktan gelen verileri tutarlı belgeler içinde birleştirir. Bu bölüm, her bir özelliğin IronPDF'in Chromium işleme motoru kullanılarak nasıl uygulanacağını kapsar.
Grafik ve Tablo Ekleyin PDF Raporlarına
JavaScript render sırasında çalıştığından, raporlarınızda doğrudan görseller oluşturmak için herhangi bir istemci tarafı grafik kitaplığını kullanabilirsiniz. Grafik, sayfanın bir parçası olarak raster birleştirilir ve ekranda nasıl görünüyorsa nihai PDF'de de aynı şekilde görünür. Chart.js, çoğu raporlama ihtiyacı için sadelik, yetenek ve dökümantasyonun mükemmel bir dengesini sunar.
Bir CDN'den Chart.js'i dahil edin ve C# modelinizden serileştirilmiş verilerle grafiğinizi yapılandırın:
@model SalesReportModel
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<canvas id="salesChart"></canvas>
<script>
// Initialize bar chart with data from C# model
const ctx = document.getElementById('salesChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
// Serialize model data to JavaScript arrays
labels: @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.MonthLabels)),
datasets: [{
label: 'Monthly Sales',
data: @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.MonthlySales)),
backgroundColor: 'rgba(52, 152, 219, 0.7)'
}]
}
});
</script>
@model SalesReportModel
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<canvas id="salesChart"></canvas>
<script>
// Initialize bar chart with data from C# model
const ctx = document.getElementById('salesChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
// Serialize model data to JavaScript arrays
labels: @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.MonthLabels)),
datasets: [{
label: 'Monthly Sales',
data: @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.MonthlySales)),
backgroundColor: 'rgba(52, 152, 219, 0.7)'
}]
}
});
</script>
JavaScript ile üretilmiş içerik içeren sayfalar render edilirken, sayfanın yakalanmasından önce betiklerin tam yürütülmesini beklemesi için işlemciyi yapılandırın:
:path=/static-assets/pdf/content-code-examples/tutorials/crystal-reports-alternative-csharp/javascript-wait-rendering.cs
using IronPdf;
string html = "<h1>Report</h1>";
// Configure renderer to wait for JavaScript execution
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.WaitFor.JavaScript(500); // Wait 500ms for JS to complete
var pdf = renderer.RenderHtmlAsPdf(html);
Imports IronPdf
Dim html As String = "<h1>Report</h1>"
' Configure renderer to wait for JavaScript execution
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.WaitFor.JavaScript(500) ' Wait 500ms for JS to complete
Dim pdf = renderer.RenderHtmlAsPdf(html)
Örnek Çıktı
Koşullu Biçimlendirme ve İş Mantığı Uygulayın
Stok raporları, müdahale gerektiren öğelere hemen dikkat çeken görsel göstergelerden yararlanır. Kullanıcıların sorunları bulmak için yüzlerce satır arasında gezinmeye zorlamak yerine, koşullu biçimlendirme istisnaları görsel olarak belirgin hale getirir. Veri değerlere dayalı olarak CSS sınıflarını uygulamak için Razor's inline ifadelerini kullanın:
@foreach (var item in Model.Items.OrderBy(x => x.Quantity))
{
// Apply CSS class based on stock level thresholds
var rowClass = item.Quantity <= Model.CriticalStockThreshold ? "stock-critical" :
item.Quantity <= Model.LowStockThreshold ? "stock-low" : "";
<tr class="@rowClass">
<td>@item.SKU</td>
<td>@item.ProductName</td>
<td class="text-right">
<span class="quantity-badge @(item.Quantity <= 5 ? "badge-critical" : "badge-ok")">
@item.Quantity
</span>
</td>
</tr>
}
@foreach (var item in Model.Items.OrderBy(x => x.Quantity))
{
// Apply CSS class based on stock level thresholds
var rowClass = item.Quantity <= Model.CriticalStockThreshold ? "stock-critical" :
item.Quantity <= Model.LowStockThreshold ? "stock-low" : "";
<tr class="@rowClass">
<td>@item.SKU</td>
<td>@item.ProductName</td>
<td class="text-right">
<span class="quantity-badge @(item.Quantity <= 5 ? "badge-critical" : "badge-ok")">
@item.Quantity
</span>
</td>
</tr>
}
Örnek Çıktı
Alt Raporlar ve Bölüm Araçları Oluşturun
Bağımsız olarak oluşturulmuş raporları tek belge içinde birleştirmek için IronPDF'in birleştirme işlevselliğini kullanın:
using IronPdf;
// Combine multiple reports into a single PDF document
public byte[] GenerateCombinedReport(SalesReportModel sales, InventoryReportModel inventory)
{
var renderer = new ChromePdfRenderer();
// Render each report section separately
var salesPdf = renderer.RenderHtmlAsPdf(RenderSalesReport(sales));
var inventoryPdf = renderer.RenderHtmlAsPdf(RenderInventoryReport(inventory));
// Merge PDFs into one document
var combined = PdfDocument.Merge(salesPdf, inventoryPdf);
return combined.BinaryData;
}
using IronPdf;
// Combine multiple reports into a single PDF document
public byte[] GenerateCombinedReport(SalesReportModel sales, InventoryReportModel inventory)
{
var renderer = new ChromePdfRenderer();
// Render each report section separately
var salesPdf = renderer.RenderHtmlAsPdf(RenderSalesReport(sales));
var inventoryPdf = renderer.RenderHtmlAsPdf(RenderInventoryReport(inventory));
// Merge PDFs into one document
var combined = PdfDocument.Merge(salesPdf, inventoryPdf);
return combined.BinaryData;
}
Imports IronPdf
' Combine multiple reports into a single PDF document
Public Function GenerateCombinedReport(sales As SalesReportModel, inventory As InventoryReportModel) As Byte()
Dim renderer As New ChromePdfRenderer()
' Render each report section separately
Dim salesPdf = renderer.RenderHtmlAsPdf(RenderSalesReport(sales))
Dim inventoryPdf = renderer.RenderHtmlAsPdf(RenderInventoryReport(inventory))
' Merge PDFs into one document
Dim combined = PdfDocument.Merge(salesPdf, inventoryPdf)
Return combined.BinaryData
End Function
Örnek Çıktı
İçindekiler Tablosu Oluşturun
IronPDF HTML'deki başlık ögelerine dayanarak otomatik olarak bir içindekiler tablosu oluşturabilir:
:path=/static-assets/pdf/content-code-examples/tutorials/crystal-reports-alternative-csharp/table-of-contents.cs
using IronPdf;
// Generate PDF with automatic table of contents
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.TableOfContents = TableOfContentsTypes.WithPageNumbers;
var pdf = renderer.RenderHtmlFileAsPdf("report.html");
Imports IronPdf
' Generate PDF with automatic table of contents
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.TableOfContents = TableOfContentsTypes.WithPageNumbers
Dim pdf = renderer.RenderHtmlFileAsPdf("report.html")
Crystal Raporlarından IronPDF'e Geçiş
Oluşmuş bir raporlama sistemiyle çalışma, kesintiyi minimize ederken modernleştirme ve basitleştirme fırsatını yakalamak için dikkatli planlama gerektirir. Orijinal raporların her özelliğini birebir kopyalamak veya tüm tuhaflıkları korumaya çalışmak yerine, Crystal Raporlar kavramlarının HTML tabanlı yaklaşıma nasıl eşlendiğini anlamanın daha hızlı hareket etmenizi sağlar.
Crystal Rapor Kavramlarını IronPDF'e Haritalama
Kavramsal haritalandırma, mevcut raporların sistematik olarak çevrilmesine yardımcı olur:
| Crystal Raporlar | IronPDF Eşdeğeri |
|---|---|
| Rapor bölümleri | CSS sayfa kırılma özelliklerine sahip HTML divs |
| Parametre alanları | Razor görünümlerine geçirilen model özellikleri |
| Formül alanları | Model sınıflarındaki C# hesaplanmış özellikler |
| Koşumlar toplamı | LINQ toplama işlemleri |
| Alt raporlar | Kısmi görünümler veya birleştirilmiş PDF belgeleri |
| Gruplama / sıralama | LINQ işlemleri şablona veri geçirmeden önce |
| Çapraz sekme raporları | İç içe döngüleri kullanan HTML tablolar |
| Koşullu biçimlendirme | CSS sınıfları ile Razor @if blokları |
.rpt Şablonlarını Dönüştürmek için En İyi Strateji
.rpt dosyalarını programatik olarak çözümlemeye çalışmayın. Bunun yerine, mevcut PDF çıktıları görsel spesifikasyonlar olarak değerlendirin ve mantığı dört adımlı sistematik bir strateji kullanarak yeniden oluşturun:
-
Stok: Amacı, veri kaynakları ve kullanim sıklığı ile tüm .rpt dosyalarını kataloğa alın. Dönüşüm kapsamını azaltmak için kullanılmayan raporları kaldırın.
-
Önceliklendirin: Yüksek sıklığa sahip raporları ilk önce çevirin. Basit düzenli veya sürekli bakım sorunları olan raporları hedefleyin.
-
Referans: Mevcut Crystal Raporlar PDF olarak dışa aktarın. Bu görsel spesifikasyonları oluşturulmuş raporlarla eşleştirmek için kullanın.
- Doğrulama: Üretim veri hacimleriyle test edin. Anında 10 satır ile işlenen şablonlar 10.000 satır ile yavaşlayabilir.
.NET'te Yığın Rapor Üretimi ve Zamanlama
Üretim sistemleri genellikle birden fazla raporu aynı anda oluşturmak veya rapor işleri zamanlamasına çalışmak zorundadır. IronPDF'in iş parçacığı güvenli tasarımı her iki senaryoyu da verimli bir şekilde destekler.
Paralel Olarak Birden Fazla Rapor Üretin
Toplu işleme için Parallel.ForEachAsync veya Task.WhenAll ile asenkron kalıpları kullanın:
using IronPdf;
using System.Collections.Concurrent;
// Generate multiple invoices in parallel using async processing
public async Task<List<ReportResult>> GenerateInvoiceBatchAsync(List<InvoiceModel> invoices)
{
var results = new ConcurrentBag<ReportResult>();
// Process invoices concurrently with controlled parallelism
await Parallel.ForEachAsync(invoices,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
async (invoice, token) =>
{
// Each thread gets its own renderer instance
var renderer = new ChromePdfRenderer();
string html = BuildInvoiceHtml(invoice);
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
// Save individual invoice PDF
string filename = $"Invoice_{invoice.InvoiceNumber}.pdf";
await pdf.SaveAsAsync(filename);
results.Add(new ReportResult { InvoiceNumber = invoice.InvoiceNumber, Success = true });
});
return results.ToList();
}
using IronPdf;
using System.Collections.Concurrent;
// Generate multiple invoices in parallel using async processing
public async Task<List<ReportResult>> GenerateInvoiceBatchAsync(List<InvoiceModel> invoices)
{
var results = new ConcurrentBag<ReportResult>();
// Process invoices concurrently with controlled parallelism
await Parallel.ForEachAsync(invoices,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
async (invoice, token) =>
{
// Each thread gets its own renderer instance
var renderer = new ChromePdfRenderer();
string html = BuildInvoiceHtml(invoice);
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
// Save individual invoice PDF
string filename = $"Invoice_{invoice.InvoiceNumber}.pdf";
await pdf.SaveAsAsync(filename);
results.Add(new ReportResult { InvoiceNumber = invoice.InvoiceNumber, Success = true });
});
return results.ToList();
}
Imports IronPdf
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
' Generate multiple invoices in parallel using async processing
Public Async Function GenerateInvoiceBatchAsync(invoices As List(Of InvoiceModel)) As Task(Of List(Of ReportResult))
Dim results As New ConcurrentBag(Of ReportResult)()
' Process invoices concurrently with controlled parallelism
Await Task.Run(Async Function()
Await Parallel.ForEachAsync(invoices,
New ParallelOptions With {.MaxDegreeOfParallelism = Environment.ProcessorCount},
Async Function(invoice, token)
' Each thread gets its own renderer instance
Dim renderer As New ChromePdfRenderer()
Dim html As String = BuildInvoiceHtml(invoice)
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
' Save individual invoice PDF
Dim filename As String = $"Invoice_{invoice.InvoiceNumber}.pdf"
Await pdf.SaveAsAsync(filename)
results.Add(New ReportResult With {.InvoiceNumber = invoice.InvoiceNumber, .Success = True})
End Function)
End Function)
Return results.ToList()
End Function
Örnek Çıktı
Yığın işleme örneği paralel olarak birden fazla faturayı üretir. İşte üretilen yığın faturalardan biri:
Rapor Üretimini ASP.NET Core Backround Hizmetleriyle Entegre Edin
Zamanlanmış rapor üretimi ASP.NET Core'un barındırılan hizmet altyapısına doğal olarak sığar:
// Background service for scheduled report generation
public class DailyReportService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Calculate next run time (6 AM daily)
var nextRun = DateTime.Now.Date.AddDays(1).AddHours(6);
await Task.Delay(nextRun - DateTime.Now, stoppingToken);
// Create scoped service for report generation
using var scope = _serviceProvider.CreateScope();
var reportService = scope.ServiceProvider.GetRequiredService<IReportGenerationService>();
// Generate and distribute daily report
var salesReport = await reportService.GenerateDailySalesSummaryAsync();
// Email or save reports as needed
}
}
}
// Background service for scheduled report generation
public class DailyReportService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Calculate next run time (6 AM daily)
var nextRun = DateTime.Now.Date.AddDays(1).AddHours(6);
await Task.Delay(nextRun - DateTime.Now, stoppingToken);
// Create scoped service for report generation
using var scope = _serviceProvider.CreateScope();
var reportService = scope.ServiceProvider.GetRequiredService<IReportGenerationService>();
// Generate and distribute daily report
var salesReport = await reportService.GenerateDailySalesSummaryAsync();
// Email or save reports as needed
}
}
}
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Imports Microsoft.Extensions.DependencyInjection
' Background service for scheduled report generation
Public Class DailyReportService
Inherits BackgroundService
Private ReadOnly _serviceProvider As IServiceProvider
Protected Overrides Async Function ExecuteAsync(stoppingToken As CancellationToken) As Task
While Not stoppingToken.IsCancellationRequested
' Calculate next run time (6 AM daily)
Dim nextRun = DateTime.Now.Date.AddDays(1).AddHours(6)
Await Task.Delay(nextRun - DateTime.Now, stoppingToken)
' Create scoped service for report generation
Using scope = _serviceProvider.CreateScope()
Dim reportService = scope.ServiceProvider.GetRequiredService(Of IReportGenerationService)()
' Generate and distribute daily report
Dim salesReport = Await reportService.GenerateDailySalesSummaryAsync()
' Email or save reports as needed
End Using
End While
End Function
End Class
Tam Test Projesini İndirin
Bu öğreticinin tüm kod örnekleri, çalışmaya hazır bir .NET 10 test projesinde mevcuttur. indirme, üstte belirtilen tüm örnek PDF'leri üreten tam kaynak kodunu, veri modellerini, HTML şablonlarını ve bir test çalıştırıcısını içermektedir.
Sonraki Adımlar
Bu kılavuz boyunca yer alan örnekler, IronPDF'in iş raporlama ihtiyaçlarının tamamını nasıl karşıladığını göstermektedir: satır öğeleri ve toplamları içeren basit faturalar, gruplandırılmış veriler ve fotoğraflar içeren karmaşık çalışan dizinleri, koşullu biçimlendirme ve grafiklerle stok raporları, paralel binlerce belge işlemleriyle yığın işleme ve arka plan hizmetleri üzerinden zamanlanmış üretim.
Mevcut bir Crystal Raporlar uygulamasına alternatifler değerlendiriyorsanız, tek bir yüksek değerli raporla başlayın. Burada gösterilen HTML'den PDF'ye desenleri kullanarak yeniden oluşturun, geliştirme deneyimi ve çıktı kalitesini karşılaştırın, ardından buradan genişleyin. Birçok ekip, ilk dönüştürülen raporlarının, desenler ve temel şablonlar oluşturdukları için birkaç saat sürdüğünü, ancak sonraki raporların Razor şablonları ve stil düzenlerini tekrar kullanarak yalnızca birkaç dakika sürdüğünü fark etmektedir. Yerleşim hassasiyeti için, piksel mükemmel render dersi, CSS ile Crystal Raporlar çıktısını tam olarak eşleştirmenin nasıl yapılacağını ele alır.
İşe başlamaya hazır mısınız? IronPDF'i İndirin ve ücretsiz bir deneme ile deneyin. Aynı kütüphane, tekli rapor oluşturma işlemlerinden yüksek hacimli yığın oluşturma işlemlerine kadar tüm .NET ortamlarında işlevsellik sunar. Raporları taşımak ya da mimari rehberlik ile ilgili sorularınız varsa, lütfen mühendislik destek ekibimize ulaşın.
Sıkça Sorulan Sorular
IronPDF nedir?
IronPDF, geliştiricilere PDF belgeleri oluşturma, düzenleme ve programatik olarak oluşturma imkanı tanıyan bir C# kütüphanesidir, geleneksel raporlama araçlarına modern bir alternatif sunar.
IronPDF, Crystal Reports'un yerini nasıl alır?
IronPDF, geliştiricilere HTML/CSS şablonlarını kullanma imkanı tanıyarak daha esnek ve modern bir raporlama yaklaşımı sunar, bu da daha katı bir yapı sunan Crystal Reports'a göre daha kolay stilize edilebilir ve değiştirilebilir.
IronPDF kullanarak faturalar oluşturabilir miyim?
Evet, IronPDF ile HTML/CSS şablonlarını kullanarak detaylandırılmış ve özelleştirilmiş faturalar oluşturabilirsiniz ve bu sayede profesyonel görünen belgeler tasarlamak kolaylaşır.
IronPDF ile çalışan dizinleri oluşturmak mümkün mü?
Kesinlikle. IronPDF, dinamik veri ve HTML/CSS kullanarak kapsamlı çalışan dizinleri oluşturmanıza olanak tanır ve bu da net ve düzenli bir sunum sağlar.
DemirPDF envanter raporlarına nasıl yardımcı olabilir?
IronPDF, HTML/CSS şablonlarını kullanarak envanter raporu oluşturmayı kolaylaştırır, bu sayede veri dinamik bir şekilde doldurulabilir ve güncel, görsel olarak çekici raporlar sağlanabilir.
IronPDF'de HTML/CSS şablonlarının kullanılmasının avantajları nelerdir?
IronPDF'de HTML/CSS şablonları kullanmak, tasarımda esneklik, güncellemelerde kolaylık ve web teknolojileriyle uyumluluk sunar, bu da rapor düzenlerinin bakımını ve geliştirilmesini kolaylaştırır.
IronPDF .NET 10'u destekliyor mu?
Evet, IronPDF .NET 10 ile uyumludur ve geliştiricilerin en son .NET özelliklerinden ve geliştirmelerinden faydalanabilmesini sağlar.
IronPDF rapor oluşturma hızını nasıl artırır?
IronPDF, performans için optimize edilmiştir ve HTML/CSS'yi verimli bir şekilde işleyip yüksek kaliteli PDF belgelerine dönüştürerek raporları hızlı bir şekilde oluşturur.

