Comment créer des fichiers PDF en .NET en using IronPDF (Tutoriel C#)
Le problème avec les rapports récurrents manuels
Chaque organisation a une version du même rituel de lundi matin : un analyste ouvre la base de données de reporting, exécute les mêmes requêtes qu'il a exécutées la semaine dernière, colle les chiffres dans un modèle Excel, formate les tableaux, exporte au format PDF et l'envoie par e-mail à la liste de distribution des dirigeants, espérant que rien ne se casse et que le fichier soit envoyé avant la réunion de standup à 9 heures du matin. Quand cela fonctionne, c'est une taxe invisible sur la matinée de quelqu'un. Quand cela ne fonctionne pas, comme avec des données obsolètes laissées dans un onglet, une erreur de formule dans la ligne de synthèse, un rapport qui arrive à 10h30 au lieu de 7h00, c'est visible pour exactement le mauvais public.
Les outils de BI existants offrent une livraison programmée, mais généralement sous forme de captures d'écran de tableaux de bord ou de liens intégrés qui nécessitent une connexion. Un VP des ventes en trajet ne veut pas s'authentifier dans un outil de BI sur son téléphone, il veut un rapport PDF qu'il peut lire sur sa tablette, transférer à un prospect ou imprimer avant une réunion du conseil. Les abonnements programmés SSRS produisent des documents PDF autonomes, mais la sortie ressemble à un logiciel d'entreprise de 2010, et la mise à jour du modèle nécessite de naviguer dans un concepteur de rapports auquel la plupart des équipes .NET actuelles n'ont plus d'expertise.
Construire un pipeline personnalisé à partir de zéro est la bonne réponse architecturale, mais cela signifie connecter un planificateur, une couche de requêtes, un moteur de modèles et un expéditeur d'e-mails, chacun étant un point de défaillance potentiel qui réveille quelqu'un à 6 heures du matin lorsque le résumé hebdomadaire P&L du CFO n'arrive pas.
La solution : un pipeline programmé avec IronPDF comme étape de rendu
IronPDF est une bibliothèque PDF .NET qui agit comme moteur de rendu à l'intérieur d'un travail d'arrière-plan .NET programmé qui exécute des requêtes SQL sur la base de données de reporting, mappe les résultats sur un modèle HTML et CSS, et envoie le PDF finalisé à une liste de distribution selon un calendrier cron, pas d'étapes manuelles, pas d'analyste requis.
Hangfire, Quartz.NET, ou un BackgroundService déclenche le travail. ADO.NET ou Dapper extrait les chiffres. Le modèle HTML les transforme en un rapport de marque. ChromePdfRenderer produces the PDF. L'e-mail est envoyé avant que quelqu'un ouvre son ordinateur portable. Pas de captures d'écran d'outils de BI, pas de définitions de rapports SSRS, pas de frais d'API par rapport. Le rendu s'exécute à l'intérieur de l'application .NET existante, un package NuGet, pas de processus externes.
Comment ça marche en pratique
1. Le calendrier Cron déclenche le travail
Chaque rapport a son propre calendrier : le snapshot du pipeline de ventes s'exécute quotidiennement à 6h30, le résumé P&L s'exécute lundi à 6h00, le tableau de bord exécutif mensuel s'exécute le 1er. Le travail est enregistré avec son expression cron dans Hangfire ou Quartz.NET au démarrage de l'application, ou implémenté sous forme de BackgroundService temporisé pour des déploiements plus simples.
Lorsque le travail s'exécute, il ouvre une connexion à la base de données de reporting et exécute les requêtes SQL ou procédures stockées pertinentes pour la période, les chiffres de revenu et de dépense, les mesures KPI, les décomptes des étapes du pipeline, les taux de conversion, ou les statistiques de réalisation selon le type de rapport.
2. Les résultats des requêtes alimentent le modèle HTML
Les résultats des requêtes sont mappés dans un modèle ou un dictionnaire et injectés dans le modèle HTML. Le modèle définit tout sur l'apparence du rapport : l'en-tête de marque avec le logo de l'entreprise, une étiquette de période ("Semaine du 27 mars 2025"), des cartes de métriques de synthèse en haut, un ou plusieurs tableaux de données avec des couleurs de ligne alternées, et un pied de page avec l'horodatage de génération et un avis de confidentialité. Ce code exemple IronPDF créera des fichiers PDF qui démontrent exactement cela.
using Dapper;
using IronPdf;
using System.Data.SqlClient;
var reportData = new List<dynamic>();
using (var conn = new SqlConnection(_connectionString))
{
reportData = (await conn.QueryAsync(@"
SELECT Region, SUM(Revenue) AS Revenue, COUNT(OrderId) AS Orders
FROM SalesOrders
WHERE OrderDate >= @Start AND OrderDate < @End
GROUP BY Region ORDER BY Revenue DESC",
new { Start = weekStart, End = weekStart.AddDays(7) })).ToList();
}
var tableRows = string.Concat(reportData.Select(r =>
$"<tr><td>{r.Region}</td><td>{r.Revenue:C}</td><td>{r.Orders}</td></tr>"));
string html = (await File.ReadAllTextAsync("Templates/sales-weekly.html"))
.Replace("{{Period}}", $"Week of {weekStart:MMMM d, yyyy}")
.Replace("{{TotalRevenue}}", reportData.Sum(r => (decimal)r.Revenue).ToString("C"))
.Replace("{{TableRows}}", tableRows);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
PdfDocument report = renderer.RenderHtmlAsPdf(html);
using Dapper;
using IronPdf;
using System.Data.SqlClient;
var reportData = new List<dynamic>();
using (var conn = new SqlConnection(_connectionString))
{
reportData = (await conn.QueryAsync(@"
SELECT Region, SUM(Revenue) AS Revenue, COUNT(OrderId) AS Orders
FROM SalesOrders
WHERE OrderDate >= @Start AND OrderDate < @End
GROUP BY Region ORDER BY Revenue DESC",
new { Start = weekStart, End = weekStart.AddDays(7) })).ToList();
}
var tableRows = string.Concat(reportData.Select(r =>
$"<tr><td>{r.Region}</td><td>{r.Revenue:C}</td><td>{r.Orders}</td></tr>"));
string html = (await File.ReadAllTextAsync("Templates/sales-weekly.html"))
.Replace("{{Period}}", $"Week of {weekStart:MMMM d, yyyy}")
.Replace("{{TotalRevenue}}", reportData.Sum(r => (decimal)r.Revenue).ToString("C"))
.Replace("{{TableRows}}", tableRows);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
PdfDocument report = renderer.RenderHtmlAsPdf(html);
Imports Dapper
Imports IronPdf
Imports System.Data.SqlClient
Dim reportData As New List(Of Object)()
Using conn As New SqlConnection(_connectionString)
reportData = (Await conn.QueryAsync("
SELECT Region, SUM(Revenue) AS Revenue, COUNT(OrderId) AS Orders
FROM SalesOrders
WHERE OrderDate >= @Start AND OrderDate < @End
GROUP BY Region ORDER BY Revenue DESC",
New With {.Start = weekStart, .End = weekStart.AddDays(7)})).ToList()
End Using
Dim tableRows = String.Concat(reportData.Select(Function(r)
$"<tr><td>{r.Region}</td><td>{r.Revenue:C}</td><td>{r.Orders}</td></tr>"))
Dim html As String = (Await File.ReadAllTextAsync("Templates/sales-weekly.html")) _
.Replace("{{Period}}", $"Week of {weekStart:MMMM d, yyyy}") _
.Replace("{{TotalRevenue}}", reportData.Sum(Function(r) CType(r.Revenue, Decimal)).ToString("C")) _
.Replace("{{TableRows}}", tableRows)
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
Dim report As PdfDocument = renderer.RenderHtmlAsPdf(html)
Fichier PDF généré

3. Document PDF envoyé par e-mail et archivé
using System.Net.Mail;
using System.IO;
var recipients = await _configService.GetDistributionListAsync("sales-weekly");
string subject = $"Weekly Sales Report — {weekStart:MMM d, yyyy}";
using var stream = new MemoryStream(report.BinaryData);
using var attachment = new Attachment(stream, $"Sales-Report-{weekStart:yyyyMMdd}.pdf", "application/pdf");
var message = new MailMessage
{
From = new MailAddress("reports@yourcompany.com"),
Subject = subject,
Body = $"Please find the weekly sales report for the week of {weekStart:MMMM d, yyyy} attached."
};
foreach (var recipient in recipients)
message.To.Add(recipient);
message.Attachments.Add(attachment);
using var smtp = new SmtpClient("smtp.yourprovider.com");
await smtp.SendMailAsync(message);
// Archive to blob storage for historical access
string archivePath = $"reports/sales-weekly/{weekStart:yyyy/MM/dd}.pdf";
report.SaveAs(archivePath);
using System.Net.Mail;
using System.IO;
var recipients = await _configService.GetDistributionListAsync("sales-weekly");
string subject = $"Weekly Sales Report — {weekStart:MMM d, yyyy}";
using var stream = new MemoryStream(report.BinaryData);
using var attachment = new Attachment(stream, $"Sales-Report-{weekStart:yyyyMMdd}.pdf", "application/pdf");
var message = new MailMessage
{
From = new MailAddress("reports@yourcompany.com"),
Subject = subject,
Body = $"Please find the weekly sales report for the week of {weekStart:MMMM d, yyyy} attached."
};
foreach (var recipient in recipients)
message.To.Add(recipient);
message.Attachments.Add(attachment);
using var smtp = new SmtpClient("smtp.yourprovider.com");
await smtp.SendMailAsync(message);
// Archive to blob storage for historical access
string archivePath = $"reports/sales-weekly/{weekStart:yyyy/MM/dd}.pdf";
report.SaveAs(archivePath);
Imports System.Net.Mail
Imports System.IO
Dim recipients = Await _configService.GetDistributionListAsync("sales-weekly")
Dim subject As String = $"Weekly Sales Report — {weekStart:MMM d, yyyy}"
Using stream As New MemoryStream(report.BinaryData)
Using attachment As New Attachment(stream, $"Sales-Report-{weekStart:yyyyMMdd}.pdf", "application/pdf")
Dim message As New MailMessage With {
.From = New MailAddress("reports@yourcompany.com"),
.Subject = subject,
.Body = $"Please find the weekly sales report for the week of {weekStart:MMMM d, yyyy} attached."
}
For Each recipient In recipients
message.To.Add(recipient)
Next
message.Attachments.Add(attachment)
Using smtp As New SmtpClient("smtp.yourprovider.com")
Await smtp.SendMailAsync(message)
End Using
End Using
End Using
' Archive to blob storage for historical access
Dim archivePath As String = $"reports/sales-weekly/{weekStart:yyyy/MM/dd}.pdf"
report.SaveAs(archivePath)
Exemple d'e-mail avec PDF joint
Les listes de distribution sont extraites d'une table de configuration plutôt que codées en dur, donc ajouter un nouveau destinataire au rapport de ventes hebdomadaire ne nécessite pas de changement de code ni de redéploiement. Chaque PDF archivé est indexé par nom de rapport et date, construisant une bibliothèque de rapports passés accessibles depuis un lecteur partagé ou un portail interne.
Le travail enregistre son statut d'exécution — durée de la requête, temps de rendu, résultat de l'envoi d'e-mail, et toute erreur — dans un journal structuré. Une alerte se déclenche si le travail ne s'achève pas, pour que le premier signe d'un problème ne soit pas un dirigeant demandant pourquoi leur rapport n'est pas arrivé.
Avis Réels
Effort manuel nul. Les rapports se génèrent et se livrent eux-mêmes selon le calendrier. Aucun analyste n'exécute de requêtes le lundi matin, personne ne formate de tableau, personne n'oublie de cliquer sur 'envoyer'. Le processus est invisible quand cela fonctionne et alertable quand cela ne fonctionne pas.
Ponctualité. Le rapport arrive dans les boîtes de réception avant que la journée de travail ne commence. Un CFO consultant ses e-mails sur le chemin du bureau a les chiffres P&L avant que toute réunion ne les exige, pas après qu'un analyste ait fini son café.
Lisibilité hors ligne. Un PDF autonome que les dirigeants peuvent lire dans un avion, imprimer pour une réunion du conseil, ou transférer sans exiger que le destinataire se connecte à un système. Pas d'URL de tableau de bord, pas de mur d'authentification, pas de "ce lien ne fonctionne que sur le réseau de l'entreprise".
Consistance de marque. Chaque rapport produit par le pipeline utilise le même modèle HTML et CSS approuvé, le même positionnement de logo, typographie, style de tableau et langage de pied de page à travers chaque rapport hebdomadaire, quotidien et mensuel distribué par l'organisation.
Archive historique. Chaque PDF généré est stocké par date dans un chemin structuré. Six mois de rapports de ventes hebdomadaires sont à portée de navigation pour un examen de tendance ou une demande d'audit, pas besoin de requête d'outil de BI.
Aucun coût par rapport. Le rendu s'exécute en interne à l'intérieur de l'application .NET existante. Il n'y a pas de siège premium d'outil de BI requis pour la livraison programmée et pas de facturation API de reporting qui évolue avec le volume de rapports ou la taille de la liste de distribution.
Conclusion
Un rapport récurrent qui arrive de manière fiable avant le début de la journée de travail est un petit détail opérationnel qui affecte la façon dont les décisions sont prises. Des dirigeants qui ont les chiffres avant la réunion de standup du matin animent un type de réunion différent de ceux qui attendent qu'un analyste ait fini de formater une feuille de calcul.
Le pipeline pour y parvenir — planificateur, requête, modèle, rendu, e-mail — s'intègre confortablement dans un seul travail d'arrière-plan .NET. IronPDF gère le cycle de vie complet de la génération de PDF en C# sur ironpdf.com, depuis le rendu de modèles HTML jusqu'à l'enregistrement, le streaming et la manipulation de documents. Si vous êtes prêt à remplacer un processus de reporting manuel par un qui s'exécute tout seul, commencez votre essai gratuit de 30 jours, c'est assez de temps pour créer un pipeline programmé, le connecter à votre base de données, et confirmer que les bons PDFs arrivent dans les bonnes boîtes de réception à l'heure.




