All checks were successful
		
		
	
	Build and Deploy / remote-build-and-deploy (push) Successful in 28m23s
				
			
		
			
				
	
	
		
			98 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Microsoft.Extensions.Hosting;
 | |
| using Microsoft.Extensions.Logging;
 | |
| using PuppeteerSharp;
 | |
| using PuppeteerSharp.Media;
 | |
| using RazorLight;
 | |
| using System;
 | |
| using System.Threading.Tasks;
 | |
| 
 | |
| namespace GestionIntegral.Api.Services.Pdf
 | |
| {
 | |
|     public class PuppeteerPdfGenerator : IPdfGeneratorService
 | |
|     {
 | |
|         private readonly IRazorLightEngine _razorEngine;
 | |
|         private readonly ILogger<PuppeteerPdfGenerator> _logger;
 | |
| 
 | |
|         public PuppeteerPdfGenerator(IHostEnvironment hostEnvironment, ILogger<PuppeteerPdfGenerator> logger)
 | |
|         {
 | |
|             _logger = logger;
 | |
|             var rootPath = hostEnvironment.ContentRootPath;
 | |
|             _razorEngine = new RazorLightEngineBuilder()
 | |
|                 .UseFileSystemProject(rootPath)
 | |
|                 .UseMemoryCachingProvider()
 | |
|                 .Build();
 | |
| 
 | |
|             _logger.LogInformation("Verificando caché de Chromium…");
 | |
|             new BrowserFetcher().DownloadAsync().Wait();
 | |
|             _logger.LogInformation("Chromium listo en caché.");
 | |
|         }
 | |
| 
 | |
|         public async Task<byte[]> GeneratePdfFromRazorTemplateAsync<T>(string templatePath, T model, PdfGenerationOptions? options = null)
 | |
|         {
 | |
|             if (string.IsNullOrEmpty(templatePath))
 | |
|                 throw new ArgumentNullException(nameof(templatePath), "La ruta de la plantilla no puede ser nula o vacía.");
 | |
| 
 | |
|             if (model == null)
 | |
|                 throw new ArgumentNullException(nameof(model), "El modelo de datos no puede ser nulo.");
 | |
| 
 | |
|             options ??= new PdfGenerationOptions();
 | |
| 
 | |
|             string htmlContent;
 | |
|             try
 | |
|             {
 | |
|                 htmlContent = await _razorEngine.CompileRenderAsync(templatePath, model);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al compilar la plantilla Razor: {TemplatePath}", templatePath);
 | |
|                 throw new InvalidOperationException($"No se pudo renderizar la plantilla Razor '{templatePath}'.", ex);
 | |
|             }
 | |
|             
 | |
|             IBrowser? browser = null;
 | |
|             try
 | |
|             {
 | |
|                 var launchOptions = new LaunchOptions
 | |
|                 {
 | |
|                     Headless = true,
 | |
|                     Args = new[] { "--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage" }
 | |
|                 };
 | |
| 
 | |
|                 _logger.LogInformation("Lanzando Chromium headless…");
 | |
|                 browser = await Puppeteer.LaunchAsync(launchOptions);
 | |
|                 await using var page = await browser.NewPageAsync();
 | |
| 
 | |
|                 _logger.LogInformation("Estableciendo contenido HTML en la página.");
 | |
|                 await page.SetContentAsync(htmlContent, new NavigationOptions { WaitUntil = new[] { WaitUntilNavigation.Networkidle0 } });
 | |
| 
 | |
|                 _logger.LogInformation("Generando PDF…");
 | |
|                 var pdfOptions = new PdfOptions
 | |
|                 {
 | |
|                     Format = options.Format,
 | |
|                     HeaderTemplate = options.HeaderTemplate,
 | |
|                     FooterTemplate = options.FooterTemplate,
 | |
|                     PrintBackground = options.PrintBackground,
 | |
|                     Landscape = options.Landscape,
 | |
|                     MarginOptions = options.Margin ?? new MarginOptions()
 | |
|                 };
 | |
| 
 | |
|                 var pdfBytes = await page.PdfDataAsync(pdfOptions);
 | |
|                 _logger.LogInformation("PDF generado exitosamente ({Length} bytes).", pdfBytes.Length);
 | |
| 
 | |
|                 return pdfBytes;
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error durante la generación del PDF con PuppeteerSharp.");
 | |
|                 throw;
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 if (browser is not null && !browser.IsClosed)
 | |
|                 {
 | |
|                     await browser.CloseAsync();
 | |
|                     _logger.LogInformation("Navegador cerrado.");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } |