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."); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |