diff --git a/HtmlPdfPlus.sln b/HtmlPdfPlus.sln index 2ec94a5..b448fdf 100644 --- a/HtmlPdfPlus.sln +++ b/HtmlPdfPlus.sln @@ -29,9 +29,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{501D5A85-0 ProjectSection(SolutionItems) = preProject README.md = README.md src\README.txt = src\README.txt - ..\docs\swimlanes.io.AnyProcess.txt = ..\docs\swimlanes.io.AnyProcess.txt - ..\docs\swimlanes.io.http.txt = ..\docs\swimlanes.io.http.txt - ..\docs\swimlanes.io.OnlyServer.txt = ..\docs\swimlanes.io.OnlyServer.txt + docs\swimlanes.io.AnyProcess.txt = docs\swimlanes.io.AnyProcess.txt + docs\swimlanes.io.Http.txt = docs\swimlanes.io.Http.txt + docs\swimlanes.io.OnlyServer.txt = docs\swimlanes.io.OnlyServer.txt EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XmlDocMarkdown", "XmlDocMarkdown", "{A9894106-2EBA-4867-AE60-869D39CC2294}" diff --git a/README.md b/README.md index e111b93..13e29f7 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,23 @@ The current version (V.1.50.0) of **Playwright** supports **only the Chromium br - AfterPDF : Save file, Send to cloud, etc - Disable features to improve/ balance performance (minify, compress and log) -#### What's new in the latest version - -- v0.3.0-beta (latest version) +### What's new in the latest version + +- **v0.4.0-beta (latest version)** + - Relaxation of Package Reference for .net8 to .net9 + - Renamed the 'Source' command to 'Scope' + - Renamed the 'Request' command to 'ScopeRequest' + - Changed parameter in funcion SubmitHtmlToPdf to byte[] instead of string + - Changed parameter for command Run to byte[] instead of string + - Changed parameter for command ScopeRequest to byte[] instead of string + - Removed DecompressBytes() method to class HtmlPdfResult + - Added DecompressOutputData() method to class HtmlPdfResult for custom scenarios + - Improvements in the compression/decompression process to use asynchronous methods + - Small code reviews + - Updated documentation + - Preparation for GA version + +- **v0.3.0-beta** - Added FromUrl(Uri value) command to client-side mode - Fixed bug in server mode for multi thread safe when there is parameter customization and/or no client mode sending. - Moved the BeforePDF(Func> inputParam) command to the execution context. @@ -73,7 +87,8 @@ The current version (V.1.50.0) of **Playwright** supports **only the Chromium br - Added command FromHtml(string html, int converttimeout = 30000, bool minify = true) - Added command FromUrl(Uri value, int converttimeout = 30000) - Added command FromRazor\(string template, T model, int converttimeout = 30000, bool minify = true) -- v0.2.0-beta + +- **v0.2.0-beta** - Initial version ## Prerequisites @@ -95,9 +110,9 @@ dotnet tool install --global Microsoft.Playwright.CLI playwright.exe install --with-deps ``` -_Note: Make sure that the path to the executable is mapped to: C:\Users\[YourU)ser]\.dotnet\tools._ +_Note: Make sure that the path to the executable is mapped to: C:\Users\\[login]\\.dotnet\tools._ -_If it is not, run it directly via the path C:\Users\[YourUser]\.dotnet\tools\playwright.exe install --with-deps__ +_If it is not, run it directly via the path C:\Users\\[login]\\.dotnet\tools\playwright.exe install --with-deps_ ### Installation Steps for HtmlPdfPlus @@ -164,11 +179,20 @@ var clienthttp = HostApp!.Services .CreateClient("HtmlPdfServer"); //create client instance and send to HtmlPdfPlus server endpoint -var pdfresult = await HtmlPdfClient.Create("HtmlPdfPlusClient") - .PageConfig((cfg) => cfg.Margins(10)) - .FromHtml(HtmlSample()) - .Timeout(5000) - .Run(clienthttp, token); +var pdfresult = await HtmlPdfClient + .Create("HtmlPdfPlusClient") + .PageConfig((cfg) => + { + cfg.Margins(10) + .Footer("' of ") + .Header("'") + .Orientation(PageOrientation.Landscape) + .DisplayHeaderFooter(true); + }) + .Logger(HostApp.Services.GetService>()) + .FromHtml(HtmlSample()) + .Timeout(5000) + .Run(clienthttp, applifetime.ApplicationStopping); //performs writing to file after performing conversion if (pdfresult.IsSuccess) @@ -194,9 +218,11 @@ builder.Services.AddHtmlPdfService((cfg) => }); ... -app.MapPost("/GeneratePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] string requestclienthtmltopdf, CancellationToken token) => +app.MapPost("/GeneratePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] Stream requestclienthtmltopdf, CancellationToken token) => { - return await PDFserver.Run(requestclienthtmltopdf, token); + var data = await requestclienthtmltopdf.ReadToBytesAsync(); + return await PDFserver + .Run(data, token); }).Produces>(200); ``` @@ -211,24 +237,31 @@ app.MapPost("/GeneratePdf", async ([FromServices] IHtmlPdfServer ```csharp using HtmlPdfPlus; -//create client instance and send to HtmlPdfPlus server endpoint -var pdfresult = await HtmlPdfClient.Create("HtmlPdfPlusClient") - .PageConfig((cfg) => cfg.Margins(10)) - .FromHtml(HtmlSample()) - .Timeout(5000) - .Run(SendToServer, token); +// Generic suggestion for writing a file to a cloud like gcp/azure +// Suggested return would be the full path "repo/filename" +var paramTosave = new DataSavePDF("Filename.pdf","MyRepo","MyConnectionstring"); -//performs writing to file after performing conversion +var pdfresult = await HtmlPdfClient.Create("HtmlPdfPlusClient") + .PageConfig((cfg) => + { + cfg.Margins(10); + }) + .Logger(HostApp.Services.GetService>()) + .FromRazor(TemplateRazor(), order1) + .Timeout(50000) + .Run(SendToServer,paramTosave, applifetime.ApplicationStopping); + +//Shwo result if (pdfresult.IsSuccess) { - await File.WriteAllBytesAsync("html2pdfsample.pdf", pdfresult.OutputData!); + Console.WriteLine($"File PDF generate at {pdfresult.OutputData}"); } else { - //show error via pdfresult.Error + Console.WriteLine($"HtmlPdfClient error: {pdfresult.Error!}"); } -private static async Task> SendToServer(string requestdata, CancellationToken token) +private static async Task> SendToServer(byte[] requestdata, CancellationToken token) { //send requestdata to server and return result } @@ -242,14 +275,35 @@ using HtmlPdfPlus; ... var builder = WebApplication.CreateBuilder(args); -builder.Services.AddHtmlPdfService((cfg) => +builder.Services.AddHtmlPdfService((cfg) => { cfg.Logger(LogLevel.Debug, "MyPDFServer"); }); ... var PDFserver = HostApp.Services.GetHtmlPdfService(); -var result = await PDFserver.Run(requestdata , Token); +var result = await PDFserver + .ScopeRequest(data) + .BeforePDF( (html,inputparam, _) => + { + if (inputparam is null) + { + return Task.FromResult(html); + } + //performs replacement token substitution in the HTML source before performing the conversion + var aux = html.Replace("[{FileName}]", inputparam.Filename); + return Task.FromResult(aux); + }) + .AfterPDF( (pdfbyte, inputparam, token) => + { + if (inputparam is null) + { + return Task.FromResult(string.Empty); + } + //TODO : performs writing to file after performing conversion + return Task.FromResult(inputparam.Filename); + }) + .Run(token); //send result to client @@ -284,7 +338,7 @@ var PDFserver = HostApp!.Services.GetHtmlPdfService(); //Performs conversion and custom operations on the server var pdfresult = await PDFserver - .Source() + .ScopeData() .FromHtml(HtmlSample(),5000) .Run(applifetime.ApplicationStopping); diff --git a/docs/images/swimlanes.io.AnyProcess.png b/docs/images/swimlanes.io.AnyProcess.png index 9299bd8..b8ef5dd 100644 Binary files a/docs/images/swimlanes.io.AnyProcess.png and b/docs/images/swimlanes.io.AnyProcess.png differ diff --git a/docs/images/swimlanes.io.Http.png b/docs/images/swimlanes.io.Http.png index 5cf6580..770317d 100644 Binary files a/docs/images/swimlanes.io.Http.png and b/docs/images/swimlanes.io.Http.png differ diff --git a/docs/images/swimlanes.io.OnlyServer.png b/docs/images/swimlanes.io.OnlyServer.png index 5c510d6..0de699d 100644 Binary files a/docs/images/swimlanes.io.OnlyServer.png and b/docs/images/swimlanes.io.OnlyServer.png differ diff --git a/docs/swimlanes.io.AnyProcess.txt b/docs/swimlanes.io.AnyProcess.txt index a3df46e..45cc6f2 100644 --- a/docs/swimlanes.io.AnyProcess.txt +++ b/docs/swimlanes.io.AnyProcess.txt @@ -6,22 +6,24 @@ HtmlPdfServer -> App Server: AddHtmlPdfService App Server --> App Server : Warmup HtmlPdfService App Client --> HtmlPdfClient: FromHtml HtmlPdfClient --> HtmlPdfClient : Minify Html -App Client --> HtmlPdfClient: FromRazor(Optional) +App Client --> HtmlPdfClient: FromRazor HtmlPdfClient --> HtmlPdfClient : Execute Razor Engine HtmlPdfClient --> HtmlPdfClient : Minify Html +App Client --> HtmlPdfClient: FromUrl + App Client --> HtmlPdfClient: PageConfig App Client --> HtmlPdfClient: Timeout App Client -> HtmlPdfClient: ** Run (Optional Input param) ** -HtmlPdfClient --> HtmlPdfClient : Create and Compress RequestHtmlPdf in Base64 +HtmlPdfClient --> HtmlPdfClient : Create and Compress RequestHtmlPdf HtmlPdfClient --> Func.Submit : Execute Submit Func.Submit-> App Server : ** Any process ** App Server --> HtmlPdfServer: BeforePDF App Server --> HtmlPdfServer: AfterPDF -App Server -> HtmlPdfServer: ** Run (Compress Base64) ** +App Server -> HtmlPdfServer: ** Run (Compress) ** -HtmlPdfServer --> HtmlPdfServer : Uncompress Base64 to RequestHtmlPdf +HtmlPdfServer --> HtmlPdfServer : Uncompress to RequestHtmlPdf HtmlPdfServer --> HtmlPdfServer : Exec BeforePdf (Input param) HtmlPdfServer --> HtmlPdfServer : **Generate PDF** HtmlPdfServer --> HtmlPdfServer : Exec AfterPdf (Input param and Transform output type) diff --git a/docs/swimlanes.io.Http.txt b/docs/swimlanes.io.Http.txt index 16a587b..d07c11e 100644 --- a/docs/swimlanes.io.Http.txt +++ b/docs/swimlanes.io.Http.txt @@ -6,20 +6,21 @@ HtmlPdfServer -> App Server: AddHtmlPdfService App Server --> App Server : Warmup HtmlPdfService App Client --> HtmlPdfClient: FromHtml HtmlPdfClient --> HtmlPdfClient : Minify Html -App Client --> HtmlPdfClient: FromRazor(Optional) +App Client --> HtmlPdfClient: FromRazor HtmlPdfClient --> HtmlPdfClient : Execute Razor Engine HtmlPdfClient --> HtmlPdfClient : Minify Html +App Client --> HtmlPdfClient: FromUrl App Client --> HtmlPdfClient: PageConfig App Client --> HtmlPdfClient: Timeout App Client -> HtmlPdfClient: ** Run (Optional Input param) ** -HtmlPdfClient --> HtmlPdfClient : Create and Compress RequestHtmlPdf in Base64 +HtmlPdfClient --> HtmlPdfClient : Create and Compress RequestHtmlPdf HtmlPdfClient -> App Server : ** HTTP/POST ** App Server --> HtmlPdfServer: BeforePDF App Server --> HtmlPdfServer: AfterPDF -App Server -> HtmlPdfServer: ** Run (Compress Base64) ** +App Server -> HtmlPdfServer: ** Run (Compress) ** -HtmlPdfServer --> HtmlPdfServer : Uncompress Base64 to RequestHtmlPdf +HtmlPdfServer --> HtmlPdfServer : Uncompress to RequestHtmlPdf HtmlPdfServer --> HtmlPdfServer : Exec BeforePdf (Input param) HtmlPdfServer --> HtmlPdfServer : **Generate PDF** HtmlPdfServer --> HtmlPdfServer : Exec AfterPdf (Input param and Transform output type) diff --git a/docs/swimlanes.io.OnlyServer.txt b/docs/swimlanes.io.OnlyServer.txt index c2f72c8..aff6a01 100644 --- a/docs/swimlanes.io.OnlyServer.txt +++ b/docs/swimlanes.io.OnlyServer.txt @@ -1,19 +1,25 @@ -title: Generate PDF Client-Sever via only server +title: Generate PDF Client-Sever via any process -note: Compress disabled (via DisableOptionsHtmlToPdf) +note: Minify, Compress and Logging can be disabled (via DisableOptionsHtmlToPdf) -HtmlPdfServer ->App Client: AddHtmlPdfService (Optional Default PageConfig) -App Client --> App Client : Warmup HtmlPdfService -App Client --> Request HtmlPdf: Html + PageConfig(Optional) + timeout -Request HtmlPdf --> Request HtmlPdf : Minify Html - - -App Client -> HtmlPdfServer: ** Run (Optional Input param) ** +HtmlPdfServer -> App Server: AddHtmlPdfService +App Server --> App Server : Warmup HtmlPdfService +App Server --> HtmlPdfServer: FromHtml (Disable Compress) +HtmlPdfServer --> HtmlPdfServer : Minify Html +App Server --> HtmlPdfServer: FromRazor (Disable Compress) +HtmlPdfServer --> HtmlPdfServer : Execute Razor Engine +HtmlPdfServer --> HtmlPdfServer : Minify Html +App Server --> HtmlPdfServer: FromUrl (Disable Compress and Minify ) +App Server --> HtmlPdfServer: Input param (opc) +App Server --> HtmlPdfServer: Timeout (opc) +App Server --> HtmlPdfServer: PageConfig (opc) +App Server --> HtmlPdfServer: BeforePDF (opc) +App Server --> HtmlPdfServer: AfterPDF (opc) +App Server -> HtmlPdfServer: ** Run ** HtmlPdfServer --> HtmlPdfServer : Exec BeforePdf (Input param) HtmlPdfServer --> HtmlPdfServer : **Generate PDF** HtmlPdfServer --> HtmlPdfServer : Exec AfterPdf (Input param and Transform output type) +HtmlPdfServer -> App Server : ** Result HtmlPdf** -HtmlPdfServer -> App Client : ** Result HtmlPdf** - -Order: App Client, Request HtmlPdf, HtmlPdfServer \ No newline at end of file +Order: App Server, HtmlPdfServer \ No newline at end of file diff --git a/samples/ConsoleHtmlToPdfPlus.ClientSendHttp/Program.cs b/samples/ConsoleHtmlToPdfPlus.ClientSendHttp/Program.cs index a0f51d6..1ff4c02 100644 --- a/samples/ConsoleHtmlToPdfPlus.ClientSendHttp/Program.cs +++ b/samples/ConsoleHtmlToPdfPlus.ClientSendHttp/Program.cs @@ -105,11 +105,11 @@ public static async Task Main(string[] args) Console.WriteLine($"HtmlPdfClient send Url to PDF Server via http post"); pdfresult = await HtmlPdfClient.Create("HtmlPdfPlusClient") - .PageConfig((cfg) => cfg.Margins(10)) - .Logger(HostApp.Services.GetService>()) - .FromUrl(new Uri("https://github.com/FRACerqueira/HtmlPdfPlus")) - .Timeout(15000) - .Run(clienthttp, applifetime.ApplicationStopping); + .PageConfig((cfg) => cfg.Margins(10)) + .Logger(HostApp.Services.GetService>()) + .FromUrl(new Uri("https://github.com/FRACerqueira/HtmlPdfPlus")) + .Timeout(15000) + .Run(clienthttp, applifetime.ApplicationStopping); Console.WriteLine($"HtmlPdfClient IsSuccess {pdfresult.IsSuccess} after {pdfresult.ElapsedTime}"); diff --git a/samples/ConsoleHtmlToPdfPlus.ClientSendTcp/Program.cs b/samples/ConsoleHtmlToPdfPlus.ClientSendTcp/Program.cs index 14c7623..4a9d46f 100644 --- a/samples/ConsoleHtmlToPdfPlus.ClientSendTcp/Program.cs +++ b/samples/ConsoleHtmlToPdfPlus.ClientSendTcp/Program.cs @@ -5,6 +5,7 @@ // *************************************************************************************** using System.Text; +using System.Text.Json; using HtmlPdfPlus; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -20,9 +21,9 @@ public class Program private static readonly SimpleTcpClient ClientTcp = new("127.0.0.1:9000"); private static readonly SemaphoreSlim SemaphoreSlim = new(1); private static readonly List ResponseTcp = []; - private static string? ResultTcp= null; + private static byte[]? ResultTcp= null; private static readonly object Lockdatareceiver = new(); - private static int TimeoutWaitResponse = 30000; + private static readonly int TimeoutWaitResponse = 30000; public static async Task Main(string[] args) { @@ -62,7 +63,7 @@ public static async Task Main(string[] args) }) .Logger(HostApp.Services.GetService>()) .FromHtml(HtmlSample()) - .Timeout(5000) + .Timeout(500000) .Run(SendToTcpServer, applifetime.ApplicationStopping); Console.WriteLine($"HtmlPdfClient IsSuccess {pdfresult.IsSuccess} after {pdfresult.ElapsedTime}"); @@ -90,7 +91,8 @@ private static void DataReceivedTcp(object? sender, DataReceivedEventArgs e) ResponseTcp.AddRange(e.Data.Array!); if (ResponseTcp[^1] == 0) //token end message { - ResultTcp = Encoding.UTF8.GetString([.. ResponseTcp], 0, ResponseTcp.Count - 1); + ResponseTcp.RemoveAt(ResponseTcp.Count - 1); + ResultTcp = [.. ResponseTcp]; ResponseTcp.Clear(); SemaphoreSlim.Release(); } @@ -107,7 +109,7 @@ private static void ConnectedTcp(object? sender, ConnectionEventArgs e) Console.WriteLine($"*** Server {e.IpPort} connected"); } - private static async Task> SendToTcpServer(string requestdata, CancellationToken token) + private static async Task> SendToTcpServer(byte[] requestdata, CancellationToken token) { // This code mybe not efficient, just to demonstrate the functionality of HtmltoPdfPlus try @@ -121,9 +123,9 @@ private static async Task> SendToTcpServer(string requestd cts.CancelAfter(TimeoutWaitResponse); //wait response to tcpserver (trigger by DataReceivedTcp release enter Semaphore) await SemaphoreSlim.WaitAsync(TimeoutWaitResponse, token); - return ResultTcp!.ToHtmlPdfResult(); + var aux = JsonSerializer.Deserialize>(Encoding.UTF8.GetString(ResultTcp!))!; + return aux.DecompressOutputData(); } - catch (Exception ex) { return new HtmlPdfResult(false, false, TimeSpan.Zero, [], ex); diff --git a/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v1/Program.cs b/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v1/Program.cs index e2defd8..768f20f 100644 --- a/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v1/Program.cs +++ b/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v1/Program.cs @@ -36,7 +36,7 @@ public static async Task Main(string[] args) //Performs conversion and custom operations on the server var pdfresult = await PDFserver - .Source(Path.Combine(PathToSamples, "html2pdfHtml.pdf")) + .ScopeData(Path.Combine(PathToSamples, "html2pdfHtml.pdf")) .FromHtml(HtmlSample(), 5000) .BeforePDF((html, _, _) => { diff --git a/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v2/Program.cs b/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v2/Program.cs index 1d8efef..4cf1079 100644 --- a/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v2/Program.cs +++ b/samples/ConsoleHtmlToPdfPlus.OnlyAtServer/v2/Program.cs @@ -33,7 +33,7 @@ public static async Task Main(string[] args) //Performs conversion on the server var pdfresult = await PDFserver - .Source() + .ScopeData() .FromHtml(HtmlSample(),5000) .Run(applifetime.ApplicationStopping); @@ -53,7 +53,7 @@ public static async Task Main(string[] args) //Performs conversion on the server pdfresult = await PDFserver - .Source() + .ScopeData() .FromUrl(new Uri("https://github.com/FRACerqueira/HtmlPdfPlus"), 5000) .Run(applifetime.ApplicationStopping); @@ -89,7 +89,8 @@ private static IHostBuilder CreateHostBuilder(string[] args) => { services.AddHtmlPdfService((cfg) => { - cfg.Logger(LogLevel.Debug, "MyPDFServer") + cfg.DisableFeatures(HtmlPdfPlus.DisableOptionsHtmlToPdf.DisableCompress) + .Logger(LogLevel.Debug, "MyPDFServer") .DefaultConfig((page) => { page.DisplayHeaderFooter(true) diff --git a/samples/TcpServerHtmlToPdf.GenericServer/Program.cs b/samples/TcpServerHtmlToPdf.GenericServer/Program.cs index a072fac..2d9ebda 100644 --- a/samples/TcpServerHtmlToPdf.GenericServer/Program.cs +++ b/samples/TcpServerHtmlToPdf.GenericServer/Program.cs @@ -6,8 +6,6 @@ using System.Text; using System.Text.Json; -using HtmlPdfPlus; -using HtmlPdfPlus.Shared.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -81,7 +79,7 @@ private static IHostBuilder CreateHostBuilder(string[] args) => { services.AddHtmlPdfService((cfg) => { - cfg.DefaultConfig((cfg) => + cfg.DefaultConfig((cfg) => { cfg.DisplayHeaderFooter(true) .Margins(10); @@ -111,15 +109,11 @@ private static void DataReceived(object sender, DataReceivedEventArgs e) var PDFserver = HostApp!.Services.GetHtmlPdfService(); - var request = Encoding.UTF8.GetString(e.Data.Array!, 0, e.Data.Count); - var aux = PDFserver - .Request(request) + .ScopeRequest(e.Data.Array!) .Run(CancellationToken.None).Result; - var sendata = JsonSerializer.Serialize>(aux); - - _ServerTCP.Send(e.IpPort, sendata); + _ServerTCP.Send(e.IpPort, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(aux))); _ServerTCP.Send(e.IpPort, [0]); //token end message } diff --git a/samples/WebHtmlToPdf.CustomSaveFileServer/Program.cs b/samples/WebHtmlToPdf.CustomSaveFileServer/Program.cs index 2ca1e74..097342a 100644 --- a/samples/WebHtmlToPdf.CustomSaveFileServer/Program.cs +++ b/samples/WebHtmlToPdf.CustomSaveFileServer/Program.cs @@ -30,10 +30,11 @@ app.UseHttpsRedirection(); -app.MapPost("/SavePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] string requestclienthtmltopdf, CancellationToken token) => +app.MapPost("/SavePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] Stream requestclienthtmltopdf, CancellationToken token) => { + var data = await requestclienthtmltopdf.ReadToBytesAsync(); return await PDFserver - .Request(requestclienthtmltopdf) + .ScopeRequest(data) .BeforePDF( (html,inputparam, _) => { if (inputparam is null) diff --git a/samples/WebHtmlToPdf.GenericServer/Program.cs b/samples/WebHtmlToPdf.GenericServer/Program.cs index 8c15097..140f3b6 100644 --- a/samples/WebHtmlToPdf.GenericServer/Program.cs +++ b/samples/WebHtmlToPdf.GenericServer/Program.cs @@ -28,10 +28,11 @@ app.UseHttpsRedirection(); -app.MapPost("/GeneratePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] string requestclienthtmltopdf, CancellationToken token) => +app.MapPost("/GeneratePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] Stream requestclienthtmltopdf, CancellationToken token) => { + var data = await requestclienthtmltopdf.ReadToBytesAsync(); return await PDFserver - .Run(requestclienthtmltopdf,token); + .Run(data, token); }).Produces>(200); -app.Run(); \ No newline at end of file +app.Run(); diff --git a/src/HtmlPdfPlus.Client/Commands/IHtmlPdfClient.cs b/src/HtmlPdfPlus.Client/Commands/IHtmlPdfClient.cs index 1e9bc3c..38af3da 100644 --- a/src/HtmlPdfPlus.Client/Commands/IHtmlPdfClient.cs +++ b/src/HtmlPdfPlus.Client/Commands/IHtmlPdfClient.cs @@ -49,7 +49,7 @@ public interface IHtmlPdfClient IHtmlPdfClient FromHtml(string html); /// - /// ;Register Page Url to be executed by the server. + /// Register Page Url to be executed by the server. /// /// The url /// instance. @@ -84,7 +84,7 @@ public interface IHtmlPdfClient /// Returns bytes[] from representing the asynchronous operation of converting HTML to PDF. /// Thrown when the empty Html source. /// Thrown when the submitHtmlToPdf function is null. - Task> Run(Func>> submitHtmlToPdf, CancellationToken token = default); + Task> Run(Func>> submitHtmlToPdf, CancellationToken token = default); /// /// Submit the HTML to convert to PDF in byte[] via POST . @@ -119,7 +119,7 @@ public interface IHtmlPdfClient /// Returns representing the asynchronous operation of converting HTML to PDF. /// Thrown when the empty Html source. /// Thrown when the submitHtmlToPdf function or customData is null. - Task> Run(Func>> submitHtmlToPdf, Tin? customData, CancellationToken token = default); + Task> Run(Func>> submitHtmlToPdf, Tin? customData, CancellationToken token = default); /// /// Submit the HTML to convert to PDF in custom output via POST . diff --git a/src/HtmlPdfPlus.Client/Core/HtmlPdfClientInstance.cs b/src/HtmlPdfPlus.Client/Core/HtmlPdfClientInstance.cs index d3a786c..8bb86f9 100644 --- a/src/HtmlPdfPlus.Client/Core/HtmlPdfClientInstance.cs +++ b/src/HtmlPdfPlus.Client/Core/HtmlPdfClientInstance.cs @@ -147,13 +147,13 @@ public IHtmlPdfClient HtmlParser(bool validate, Action whenhaserror) /// - public async Task> Run(Func>> submitHtmlToPdf, CancellationToken token = default) + public async Task> Run(Func>> submitHtmlToPdf, CancellationToken token = default) { - return await Run(submitHtmlToPdf, null, token).ConfigureAwait(false); + return await Run(submitHtmlToPdf, null, token); } /// - public async Task> Run(Func>> submitHtmlToPdf, Tin? inputparam, CancellationToken token = default) + public async Task> Run(Func>> submitHtmlToPdf, Tin? inputparam, CancellationToken token = default) { if (_html.Length == 0) { @@ -163,7 +163,7 @@ public async Task> Run(Func(submitHtmlToPdf, inputparam, token).ConfigureAwait(false); + return await SubmitAsync(submitHtmlToPdf, inputparam, token); } /// @@ -196,12 +196,12 @@ public async Task> Run(HttpClient httpclient, str _parseError.Invoke(_errorparse); } var sw = Stopwatch.StartNew(); - HttpContent content = CreateHttpContent(customdata); + HttpContent content = await CreateHttpContent(customdata); content.Headers.ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Json); try { - var result = await httpclient.PostAsync(endpoint, content, token).ConfigureAwait(false); - return await HandleHttpResponse(result, sw, token).ConfigureAwait(false); + var result = await httpclient.PostAsync(endpoint, content, token); + return await HandleHttpResponse(result, sw, token); } catch (HttpRequestException ex) { @@ -222,7 +222,7 @@ public async Task> Run(HttpClient httpclient, str /// The input parameter. /// The cancellation token. /// The result of the HTML to PDF conversion. - private async Task> SubmitAsync(Func>> submitHtmlToPdf, Tin? inputparam, CancellationToken token) + private async Task> SubmitAsync(Func>> submitHtmlToPdf, Tin? inputparam, CancellationToken token) { if (_html.Length == 0) { @@ -240,11 +240,11 @@ private async Task> SubmitAsync(Func result = await submitHtmlToPdf(requestsend, linkcts.Token).ConfigureAwait(false), linkcts.Token); - var completed = await Task.WhenAny(tasksubmit, Task.Delay(_timeout, linkcts.Token)).ConfigureAwait(false); + var completed = await Task.WhenAny(tasksubmit, Task.Delay(_timeout, linkcts.Token)); if (completed != tasksubmit) { result = new HtmlPdfResult(false, false, sw.Elapsed, default, new TimeoutException($"Canceled by Timeout({_timeout})")); @@ -277,7 +277,7 @@ private async Task> SubmitAsync(Func(result.IsSuccess, result.BufferDrained, result.ElapsedTime, (Tout?)Convert.ChangeType(result.DecompressBytes(), typeof(Tout)), result.Error); + return new HtmlPdfResult(result.IsSuccess, result.BufferDrained, result.ElapsedTime, (Tout)(object)result.OutputData, result.Error); } } return result; @@ -299,13 +299,12 @@ private void LogMessage(string message) /// /// The type of the custom data. /// The custom data. - /// The HTTP content. - private StringContent CreateHttpContent(T? customdata) + /// The HTTP . + private async Task CreateHttpContent(T? customdata) { return disableOptions.HasFlag(DisableOptionsHtmlToPdf.DisableCompress) - ? new StringContent(new RequestHtmlPdf(_html, sourcealias, _pdfPageConfig, _timeout, customdata).ToString()) - : new StringContent(JsonSerializer.Serialize( - new RequestHtmlPdf(_html, sourcealias, _pdfPageConfig, _timeout, customdata).ToStringCompress())); + ? new ByteArrayContent(new RequestHtmlPdf(_html, sourcealias, _pdfPageConfig, _timeout, customdata).ToBytes()) + : new ByteArrayContent(await new RequestHtmlPdf(_html, sourcealias, _pdfPageConfig, _timeout, customdata).ToBytesCompress()); } /// @@ -313,12 +312,12 @@ private StringContent CreateHttpContent(T? customdata) /// /// The type of the input parameter. /// The input parameter. - /// The request send string. - private string CreateRequestSend(T? inputparam) + /// The request send in byte[]. + private async Task CreateRequestSend(T? inputparam) { return disableOptions.HasFlag(DisableOptionsHtmlToPdf.DisableCompress) - ? JsonSerializer.Serialize(new RequestHtmlPdf(_html, sourcealias, _pdfPageConfig, _timeout, inputparam), GZipHelper.JsonOptions) - : GZipHelper.CompressRequest(sourcealias, _pdfPageConfig, _html, _timeout, inputparam); + ? new RequestHtmlPdf(_html, sourcealias, _pdfPageConfig, _timeout, inputparam).ToBytes() + : await new RequestHtmlPdf(_html, sourcealias, _pdfPageConfig, _timeout, inputparam).ToBytesCompress(); } /// @@ -355,25 +354,26 @@ private async Task> HandleHttpResponse(HttpResponseMes if (result.StatusCode == System.Net.HttpStatusCode.OK) { #if NETSTANDARD2_1 - var resultconvert = await result.Content.ReadAsStringAsync().ConfigureAwait(false); + using var resultconvert = await result.Content.ReadAsStreamAsync(); #endif #if NET8_0_OR_GREATER - var resultconvert = await result.Content.ReadAsStringAsync(token).ConfigureAwait(false); + using var resultconvert = await result.Content.ReadAsStreamAsync(token); #endif if (typeof(Tout) == typeof(byte[])) { if (disableOptions.HasFlag(DisableOptionsHtmlToPdf.DisableCompress)) { - return JsonSerializer.Deserialize>(resultconvert, GZipHelper.JsonOptions)!; + return (await JsonSerializer.DeserializeAsync>(resultconvert, GZipHelper.JsonOptions, token))!; } else { - var auxresult = JsonSerializer.Deserialize>(resultconvert, GZipHelper.JsonOptions)!; - if (auxresult.OutputData is null) + var auxresult = await JsonSerializer.DeserializeAsync>(resultconvert, GZipHelper.JsonOptions, token)!; + if (auxresult!.OutputData is null) { return auxresult; } - return new HtmlPdfResult(auxresult.IsSuccess, auxresult.BufferDrained, auxresult.ElapsedTime, (Tout?)Convert.ChangeType(auxresult.DecompressBytes(), typeof(Tout)), auxresult.Error); + var output = await GZipHelper.DecompressAsync((byte[])(object)auxresult.OutputData,token); + return new HtmlPdfResult(auxresult.IsSuccess, auxresult.BufferDrained, auxresult.ElapsedTime, (Tout)(object)output, auxresult.Error); } } else diff --git a/src/HtmlPdfPlus.Client/HtmlPdfClient.cs b/src/HtmlPdfPlus.Client/HtmlPdfClient.cs index fc348b5..d5a981a 100644 --- a/src/HtmlPdfPlus.Client/HtmlPdfClient.cs +++ b/src/HtmlPdfPlus.Client/HtmlPdfClient.cs @@ -4,9 +4,7 @@ // https://github.com/FRACerqueira/HtmlPdfPlus // *************************************************************************************** -using System.Text.Json; using HtmlPdfPlus.Client.Core; -using HtmlPdfPlus.Shared.Core; namespace HtmlPdfPlus { @@ -29,32 +27,6 @@ public static IHtmlPdfClient Create(string? alias = null) { return new HtmlPdfClientInstance(alias ?? string.Empty, DisableOptions); } - - /// - /// Convert Response Data from server HtmlPdfPlus - /// - /// Response data - /// - public static HtmlPdfResult ToHtmlPdfResult(this string dataresponse) - { - return dataresponse.ToHtmlPdfResult(); - } - - /// - /// Convert Response Data from server HtmlPdfPlus - /// - /// Type of result - /// Response data - /// - public static HtmlPdfResult ToHtmlPdfResult(this string dataresponse) - { - if (string.IsNullOrEmpty(dataresponse)) - { - throw new ArgumentException("Response data cannot be null or empty", nameof(dataresponse)); - } - - return JsonSerializer.Deserialize>(dataresponse, GZipHelper.JsonOptions)!; - } } } diff --git a/src/HtmlPdfPlus.Client/HtmlPdfPlus.Client.csproj b/src/HtmlPdfPlus.Client/HtmlPdfPlus.Client.csproj index e379ed1..6ce659e 100644 --- a/src/HtmlPdfPlus.Client/HtmlPdfPlus.Client.csproj +++ b/src/HtmlPdfPlus.Client/HtmlPdfPlus.Client.csproj @@ -61,8 +61,8 @@ - + - + diff --git a/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServer.cs b/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServer.cs index dc98ff7..68ce110 100644 --- a/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServer.cs +++ b/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServer.cs @@ -14,28 +14,28 @@ namespace HtmlPdfPlus public interface IHtmlPdfServer : IDisposable { /// - /// Transfer context for server context with input data,and custom actions. + /// Transfer context scope for server with input data,and custom actions. /// Input data, for customizing HTML before converting to PDF on the server. /// /// An instance of . - IHtmlPdfServerContext Source(TIn? inputparam = default); + IHtmlPdfServerContext ScopeData(TIn? inputparam = default); /// - /// Transfer request client for server context for custom actions + /// Transfer request client for server context scope for custom actions /// - /// The compressed data from the request HtmlPdfCliPlus client. + /// The compressed byte[] data from the request HtmlPdfCliPlus client. /// An instance of . - IHtmlPdfServerContext Request(string requestClient); + IHtmlPdfServerContext ScopeRequest(byte[] requestClient); /// /// Perform HTML to PDF conversion from the request HtmlPdfCliPlus client. /// - /// The compressed data from the request HtmlPdfCliPlus client. + /// The compressed byte[] data from the request HtmlPdfCliPlus client. /// The to perform the conversion. /// An instance of . /// Thrown when is invalid. /// Thrown when is invalid. - Task> Run(string requestClient, CancellationToken token = default); + Task> Run(byte[] requestClient, CancellationToken token = default); } } diff --git a/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServerContext.cs b/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServerContext.cs index 9fcda7d..6b1d910 100644 --- a/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServerContext.cs +++ b/src/HtmlPdfPlus.Server/Commands/IHtmlPdfServerContext.cs @@ -70,7 +70,7 @@ public interface IHtmlPdfServerContext /// An instance of . /// Thrown when the empty source Html or Url. /// Thrown when is invalid. - /// Thrown when is invalid. + /// Thrown when is invalid. Task> Run(CancellationToken token = default); } } diff --git a/src/HtmlPdfPlus.Server/Core/HtmlPdfBuilder.cs b/src/HtmlPdfPlus.Server/Core/HtmlPdfBuilder.cs index bc5b45b..4acf962 100644 --- a/src/HtmlPdfPlus.Server/Core/HtmlPdfBuilder.cs +++ b/src/HtmlPdfPlus.Server/Core/HtmlPdfBuilder.cs @@ -163,12 +163,12 @@ public IHtmlPdfSrvBuilder Logger(LogLevel logLevel, string categoryName = "HtmlP internal async Task> BuildAsync(string sourcealias) { - return await BuildAsync(sourcealias).ConfigureAwait(false); + return await BuildAsync(sourcealias); } internal async Task> BuildAsync(string sourcealias) { - return await ExecuteBuildAsync(sourcealias).ConfigureAwait(false); + return await ExecuteBuildAsync(sourcealias); } private async Task> ExecuteBuildAsync(string sourcealias) @@ -176,7 +176,7 @@ private async Task> ExecuteBuildAsync(strin _sourcealias = sourcealias; try { - _playwright = await Playwright.CreateAsync().ConfigureAwait(false); + _playwright = await Playwright.CreateAsync(); if (_args.Length == 0) { _args = ["--run-all-compositor-stages-before-draw", "--disable-dev-shm-usage", "-disable-setuid-sandbox", "--no-sandbox"]; @@ -185,7 +185,7 @@ private async Task> ExecuteBuildAsync(strin LogMessage($"Build Chromium with args { string.Join("", _args) }"); for (int i = 0; i < _pagesbuffer; i++) { - _availableBuffer.Enqueue(await _browser.NewPageAsync().ConfigureAwait(false)); + _availableBuffer.Enqueue(await _browser.NewPageAsync()); } LogMessage($"Build Chromium with buffer {_pagesbuffer}"); } diff --git a/src/HtmlPdfPlus.Server/Core/HtmlPdfServer.cs b/src/HtmlPdfPlus.Server/Core/HtmlPdfServer.cs index efa4426..c8328d0 100644 --- a/src/HtmlPdfPlus.Server/Core/HtmlPdfServer.cs +++ b/src/HtmlPdfPlus.Server/Core/HtmlPdfServer.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Globalization; +using System.Text; using System.Text.Json; using HtmlPdfPlus.Shared.Core; using Microsoft.Extensions.Logging; @@ -41,21 +42,21 @@ public HtmlPdfServer(HtmlPdfBuilder? pdfSrvBuilder, string sourcealias) /// - public IHtmlPdfServerContext Source(Tin? inputparam) + public IHtmlPdfServerContext ScopeData(Tin? inputparam) { return new HtmlPdfServerContext(this, inputparam, null); } /// - public IHtmlPdfServerContext Request(string requestClient) + public IHtmlPdfServerContext ScopeRequest(byte[] requestClient) { return new HtmlPdfServerContext(this, default, requestClient); } /// - public async Task> Run(string requestclient, CancellationToken token = default) + public async Task> Run(byte[] requestclient, CancellationToken token = default) { - if (string.IsNullOrEmpty(requestclient)) + if (requestclient is null || requestclient.Length ==0) { throw new ArgumentNullException(nameof(requestclient), "request client is null or empty"); } @@ -63,15 +64,17 @@ public async Task> Run(string requestclient, CancellationTok RequestHtmlPdf requestHtmlPdf; try { + string data; if (PdfSrvBuilder.DisableOptions.HasFlag(DisableOptionsHtmlToPdf.DisableCompress)) { - requestHtmlPdf = JsonSerializer.Deserialize>(requestclient, GZipHelper.JsonOptions)!; + data = Encoding.UTF8.GetString(requestclient); } else { - requestHtmlPdf = GZipHelper.DecompressRequest(requestclient); + data = Encoding.UTF8.GetString(await GZipHelper.DecompressAsync(requestclient,token)); LogMessage($"Decompress Request after {sw.Elapsed}"); } + requestHtmlPdf = JsonSerializer.Deserialize>(data, GZipHelper.JsonOptions)!; requestHtmlPdf.Config ??= PdfSrvBuilder.Config; if (requestHtmlPdf.Timeout < 1) @@ -189,7 +192,7 @@ internal async Task> RunServer( catch (Exception ex) { cts.Cancel(); // cancel pending task - LogMessage($"Error Generate PDF from serverless browser after {sw.Elapsed} : {ex}"); + LogMessage($"Error Generate PDF from browser after {sw.Elapsed} : {ex}"); return new HtmlPdfResult(false, false, sw.Elapsed, default, ex); } } @@ -212,16 +215,14 @@ internal async Task> RunServer( var aux = await outputparam(bytespdf, requestHtmlPdf.InputParam, executeToken.Token); if (typeof(Tout) == typeof(byte[])) { - if (disableCompress) + if (!disableCompress) { result = new HtmlPdfResult(true, false, sw.Elapsed, aux, null); } else { - var auxBytes = (byte[]?)Convert.ChangeType(aux, typeof(byte[])) ?? - throw new InvalidOperationException("Conversion to byte[] resulted in null"); - var compresspdf = GZipHelper.Compress(auxBytes); - result = new HtmlPdfResult(true, false, sw.Elapsed, (Tout?)Convert.ChangeType(compresspdf, typeof(Tout)), null); + var compresspdf = await GZipHelper.CompressAsync((byte[])(object)aux!,token); + result = new HtmlPdfResult(true, false, sw.Elapsed, (Tout)(object)compresspdf, null); } } else @@ -274,13 +275,13 @@ internal async Task> RunServer( LogMessage($"End Convert Html to PDF from Server with AfterPDF function at {DateTime.Now} after {sw.Elapsed}"); return result!; } - LogMessage($"End Convert Html to PDF from Server at {DateTime.Now} after {sw.Elapsed}"); - if (disableCompress) + //output is byte[] + if (!disableCompress) { - return new HtmlPdfResult(true, false, sw.Elapsed, (Tout?)Convert.ChangeType(bytespdf, typeof(Tout)), null); + bytespdf = await GZipHelper.CompressAsync(bytespdf, token); } - var compresspdf = GZipHelper.Compress(bytespdf); - return new HtmlPdfResult(true, false, sw.Elapsed, (Tout?)Convert.ChangeType(compresspdf, typeof(Tout)), null); + LogMessage($"End Convert Html to PDF from Server at {DateTime.Now} after {sw.Elapsed}"); + return new HtmlPdfResult(true, false, sw.Elapsed, (Tout)(object)bytespdf, null); } private async Task GeneratePDF(bool isurl, RequestHtmlPdf request, long remaindtime, CancellationToken token) diff --git a/src/HtmlPdfPlus.Server/Core/HtmlPdfServerContext.cs b/src/HtmlPdfPlus.Server/Core/HtmlPdfServerContext.cs index 7a95b45..66233d8 100644 --- a/src/HtmlPdfPlus.Server/Core/HtmlPdfServerContext.cs +++ b/src/HtmlPdfPlus.Server/Core/HtmlPdfServerContext.cs @@ -5,8 +5,10 @@ // *************************************************************************************** using System.Diagnostics; +using System.Text; using System.Text.Json; using HtmlPdfPlus.Shared.Core; +using Microsoft.Extensions.Logging; using NUglify; namespace HtmlPdfPlus.Server.Core @@ -20,7 +22,7 @@ namespace HtmlPdfPlus.Server.Core /// Instance of . /// Input data, for customizing HTML before converting to PDF on the server. /// The compressed data from the request HtmlPdfCliPlus client. - internal sealed class HtmlPdfServerContext(HtmlPdfServer htmlPdfServer, TIn? inputparam, string? requestClient) : IHtmlPdfServerContext, IDisposable + internal sealed class HtmlPdfServerContext(HtmlPdfServer htmlPdfServer, TIn? inputparam, byte[]? requestClient) : IHtmlPdfServerContext, IDisposable { private bool isDisposed; private Func>? _inputparam = null; @@ -94,16 +96,23 @@ public async Task> Run(CancellationToken token = default) { var sw = Stopwatch.StartNew(); RequestHtmlPdf requestHtmlPdf; - if (!string.IsNullOrEmpty(requestClient)) + string data; + if (requestClient is not null) { + if (requestClient.Length == 0) + { + throw new ArgumentException("request client is empty"); + } if (htmlPdfServer.PdfSrvBuilder.DisableOptions.HasFlag(DisableOptionsHtmlToPdf.DisableCompress)) { - requestHtmlPdf = JsonSerializer.Deserialize>(requestClient, GZipHelper.JsonOptions)!; + data = Encoding.UTF8.GetString(requestClient); } else { - requestHtmlPdf = GZipHelper.DecompressRequest(requestClient); + data = Encoding.UTF8.GetString(await GZipHelper.DecompressAsync(requestClient, token)); + LogMessage($"Decompress Request after {sw.Elapsed}"); } + requestHtmlPdf = JsonSerializer.Deserialize>(data, GZipHelper.JsonOptions)!; requestHtmlPdf.Config ??= htmlPdfServer.PdfSrvBuilder.Config; } else @@ -130,11 +139,7 @@ public async Task> Run(CancellationToken token = default) return new HtmlPdfResult(false, false, sw.Elapsed, default, ex); } var isurl = Uri.IsWellFormedUriString(requestHtmlPdf.Html, UriKind.RelativeOrAbsolute); - var disabledcompress = false; - if (!string.IsNullOrEmpty(requestClient)) - { - disabledcompress = htmlPdfServer.PdfSrvBuilder.DisableOptions.HasFlag(DisableOptionsHtmlToPdf.DisableCompress); - } + var disabledcompress = htmlPdfServer.PdfSrvBuilder.DisableOptions.HasFlag(DisableOptionsHtmlToPdf.DisableCompress); return await htmlPdfServer.RunServer(isurl, _inputparam, _outputparam, sw, requestHtmlPdf, disabledcompress, token); } @@ -153,5 +158,31 @@ private void Cleanup() { htmlPdfServer?.Dispose(); } + + private void LogMessage(string message) + { + if (htmlPdfServer.PdfSrvBuilder is null || htmlPdfServer.PdfSrvBuilder.Log is null || (!htmlPdfServer.PdfSrvBuilder.Log?.IsEnabled(htmlPdfServer.PdfSrvBuilder.LevelLog) ?? false)) return; + + switch (htmlPdfServer.PdfSrvBuilder.LevelLog) + { + case LogLevel.None: + return; + case LogLevel.Trace: + logMessageForTrc(htmlPdfServer.PdfSrvBuilder.Log!, htmlPdfServer.SourceAlias, message, null); + break; + case LogLevel.Information: + logMessageForInf(htmlPdfServer.PdfSrvBuilder.Log!, htmlPdfServer.SourceAlias, message, null); + break; + case LogLevel.Debug: + logMessageForDbg(htmlPdfServer.PdfSrvBuilder.Log!, htmlPdfServer.SourceAlias, message, null); + break; + } + } + + // Reusable logging + private static readonly Action logMessageForInf = LoggerMessage.Define(LogLevel.Information, 0, "HtmlPdfServerContext({source}) : {message}"); + private static readonly Action logMessageForTrc = LoggerMessage.Define(LogLevel.Trace, 0, "HtmlPdfServerContext({source}) : {message}"); + private static readonly Action logMessageForDbg = LoggerMessage.Define(LogLevel.Debug, 0, "HtmlPdfServerContext({source}) : {message}"); + } } diff --git a/src/HtmlPdfPlus.Server/HtmlPdfPlus.Server.csproj b/src/HtmlPdfPlus.Server/HtmlPdfPlus.Server.csproj index b69334c..ecf0ebc 100644 --- a/src/HtmlPdfPlus.Server/HtmlPdfPlus.Server.csproj +++ b/src/HtmlPdfPlus.Server/HtmlPdfPlus.Server.csproj @@ -49,11 +49,11 @@ - - + + - + diff --git a/src/HtmlPdfPlus.Shared/Core/GZipHelper.cs b/src/HtmlPdfPlus.Shared/Core/GZipHelper.cs index 7bd03fb..e3f8656 100644 --- a/src/HtmlPdfPlus.Shared/Core/GZipHelper.cs +++ b/src/HtmlPdfPlus.Shared/Core/GZipHelper.cs @@ -5,7 +5,6 @@ // *************************************************************************************** using System.IO.Compression; -using System.Text; using System.Text.Json; namespace HtmlPdfPlus.Shared.Core @@ -14,57 +13,15 @@ internal static class GZipHelper { public static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true }; - /// - /// Decompresses a base64 encoded string. - /// - /// The base64 encoded string to decompress. - /// The decompressed string. - public static string Decompress(string input) - { - try - { - byte[] compressed = Convert.FromBase64String(input); - byte[] decompressed = Decompress(compressed); - return Encoding.UTF8.GetString(decompressed); - } - catch (FormatException ex) - { - // Log the exception - throw new InvalidOperationException("The input string is not a valid base64 string.", ex); - } - catch (InvalidOperationException ex) - { - // Log the exception - throw new InvalidOperationException("Failed to decompress the input string.", ex); - } - } + private const int BufferSize = 81920; // 80 KB buffer size /// - /// Compresses a string and returns a base64 encoded result. - /// - /// The string to compress. - /// The compressed and base64 encoded string. - public static string Compress(string input) - { - try - { - byte[] encoded = Encoding.UTF8.GetBytes(input); - byte[] compressed = Compress(encoded); - return Convert.ToBase64String(compressed); - } - catch (Exception ex) - { - // Handle or log the exception as needed - throw new InvalidOperationException("Failed to compress the input string.", ex); - } - } - - /// - /// Decompresses a byte array. + /// Decompresses a byte array asynchronously. /// /// The byte array to decompress. + /// The . /// The decompressed byte array. - public static byte[] Decompress(byte[] input) + public static async Task DecompressAsync(byte[] input, CancellationToken token = default) { try { @@ -72,7 +29,7 @@ public static byte[] Decompress(byte[] input) using var result = new MemoryStream(); using (var decompress = new GZipStream(source, CompressionMode.Decompress)) { - decompress.CopyTo(result); + await decompress.CopyToAsync(result, BufferSize,token); } return result.ToArray(); } @@ -89,18 +46,19 @@ public static byte[] Decompress(byte[] input) } /// - /// Compresses a byte array. + /// Compresses a byte array asynchronously. /// /// The byte array to compress. + /// The . /// The compressed byte array. - public static byte[] Compress(byte[] input) + public static async Task CompressAsync(byte[] input, CancellationToken token = default) { try { using var result = new MemoryStream(); - using (var compress = new GZipStream(result, CompressionMode.Compress)) + using (var compress = new GZipStream(result, CompressionLevel.Optimal)) { - compress.Write(input, 0, input.Length); + await compress.WriteAsync(input,token); } return result.ToArray(); } @@ -110,56 +68,5 @@ public static byte[] Compress(byte[] input) throw new InvalidOperationException("Failed to compress the input byte array.", ex); } } - - /// - /// Compresses a request object to a base64 encoded string. - /// - /// The type of the input parameter. - /// The alias for the request. - /// The PDF page configuration. - /// The HTML content. - /// The timeout value. - /// The input parameter. - /// The compressed and base64 encoded request string. - internal static string CompressRequest(string? alias, PdfPageConfig? pageConfig, string html, int timeout, T? inputparam) - { - try - { - var request = new RequestHtmlPdf(html, alias, pageConfig, timeout, inputparam); - var json = JsonSerializer.Serialize(request, JsonOptions); - return Compress(json); - } - catch (Exception ex) - { - // Log the exception - throw new InvalidOperationException("Failed to compress the request object.", ex); - } - } - - /// - /// Decompresses a base64 encoded request string to a request object. - /// - /// The type of the input parameter. - /// The compressed and base64 encoded request string. - /// The decompressed request object. - internal static RequestHtmlPdf DecompressRequest(string compressdata) - { - try - { - var json = Decompress(compressdata); - var result = JsonSerializer.Deserialize>(json, JsonOptions); - return result!; - } - catch (JsonException ex) - { - // Log the exception - throw new InvalidOperationException("Failed to deserialize the decompressed JSON string.", ex); - } - catch (Exception ex) - { - // Log the exception - throw new InvalidOperationException("Failed to decompress the request object.", ex); - } - } } } diff --git a/src/HtmlPdfPlus.Shared/Core/RequestHtmlPdf.cs b/src/HtmlPdfPlus.Shared/Core/RequestHtmlPdf.cs index 2e4c008..b3e916c 100644 --- a/src/HtmlPdfPlus.Shared/Core/RequestHtmlPdf.cs +++ b/src/HtmlPdfPlus.Shared/Core/RequestHtmlPdf.cs @@ -4,6 +4,7 @@ // https://github.com/FRACerqueira/HtmlPdfPlus // *************************************************************************************** +using System.Text; using System.Text.Json; using NUglify; @@ -94,21 +95,21 @@ public void ChangeHtml(string value, bool minify) } /// - /// Returns a JSON string representation of the . + /// Returns a byte[] of JSON string representation of the . /// /// JSON string representation - public override string ToString() + public byte[] ToBytes() { - return JsonSerializer.Serialize(this); + return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(this)); } /// - /// Returns a compressed (gzip) base64 JSON string representation of the . + /// Returns a a compressed (gzip) byte[] of JSON string representation of the . /// - /// Compressed (gzip) base64 JSON string representation - public string ToStringCompress() + /// JSON string representation + public async Task ToBytesCompress() { - return GZipHelper.Compress(ToString()); + return await GZipHelper.CompressAsync(ToBytes()); } } } diff --git a/src/HtmlPdfPlus.Shared/HtmlPdfPlus.Shared.csproj b/src/HtmlPdfPlus.Shared/HtmlPdfPlus.Shared.csproj index c465d80..340b35f 100644 --- a/src/HtmlPdfPlus.Shared/HtmlPdfPlus.Shared.csproj +++ b/src/HtmlPdfPlus.Shared/HtmlPdfPlus.Shared.csproj @@ -54,6 +54,6 @@ - + diff --git a/src/HtmlPdfPlus.Shared/HtmlPdfResult.cs b/src/HtmlPdfPlus.Shared/HtmlPdfResult.cs index 0977cc5..b689828 100644 --- a/src/HtmlPdfPlus.Shared/HtmlPdfResult.cs +++ b/src/HtmlPdfPlus.Shared/HtmlPdfResult.cs @@ -57,19 +57,21 @@ public HtmlPdfResult(bool isSuccess, bool bufferDrained, TimeSpan elapsedTime, T /// /// Output custom data or PDF in byte[] /// - public T? OutputData { get; } + public T? OutputData { get; internal set; } /// - /// Decompress output data if it is byte[] + /// Decompress OutputData when type is byte[] /// - /// Output data decompressed - public byte[]? DecompressBytes() + /// The with OutputData Decompressed when type is byte[] + /// OutputData is not byte[] + public HtmlPdfResult DecompressOutputData() { - if (OutputData is byte[] data && OutputData is not null) + if (OutputData is byte[] data) { - return GZipHelper.Decompress(data); + OutputData = (T)(object)GZipHelper.DecompressAsync(data).Result; + return this; } - return null; + throw new InvalidOperationException("OutputData is not byte[]"); } } } diff --git a/src/HtmlPdfPlus.Shared/StreamExtension.cs b/src/HtmlPdfPlus.Shared/StreamExtension.cs new file mode 100644 index 0000000..b9c8345 --- /dev/null +++ b/src/HtmlPdfPlus.Shared/StreamExtension.cs @@ -0,0 +1,26 @@ +// *************************************************************************************** +// MIT LICENCE +// The maintenance and evolution is maintained by the HtmlPdfPlus team +// https://github.com/FRACerqueira/HtmlPdfPlus +// *************************************************************************************** + +namespace HtmlPdfPlus +{ + /// + /// Extend function for + /// + public static class StreamExtension + { + /// + /// Read the stream and return the content as a byte[] + /// + /// The stream + /// + public static async Task ReadToBytesAsync(this Stream stream) + { + using var memoryStream = new MemoryStream(); + await stream.CopyToAsync(memoryStream); + return memoryStream.ToArray(); + } + } +} diff --git a/src/README.txt b/src/README.txt index 6a69b87..9e026f9 100644 --- a/src/README.txt +++ b/src/README.txt @@ -45,7 +45,22 @@ Features What's new in the latest version ================================ -- v0.3.0-beta (latest version) +- v0.4.0-beta (latest version) + - Relaxation of Package Reference for .net8 to .net9 + - Renamed the 'Source' command to 'Scope' + - Renamed the 'Request' command to 'ScopeRequest' + - Changed parameter in funcion SubmitHtmlToPdf to byte[] instead of string + - Changed parameter for command Run to byte[] instead of string + - Changed parameter for command ScopeRequest to byte[] instead of string + - Removed DecompressBytes() method to class HtmlPdfResult + - Added DecompressOutputData() method to class HtmlPdfResult for custom scenarios + - Improvements in the compression/decompression process to use asynchronous methods + - Small code reviews + - Updated documentation + - Preparation for GA version + +- v0.3.0-beta + - Added FromUrl(Uri value) command to client-side mode - Fixed bug in server mode for multi thread safe when there is parameter customization and/or no client mode sending. - Moved the BeforePDF(Func> inputParam) command to the execution context. @@ -59,6 +74,7 @@ What's new in the latest version - Added command FromRazor\(string template, T model, int converttimeout = 30000, bool minify = true) - v0.2.0-beta + - Initial version Prerequisites @@ -75,8 +91,8 @@ dotnet tool update --global PowerShell dotnet tool install --global Microsoft.Playwright.CLI playwright.exe install --with-deps -Note: Make sure that the path to the executable is mapped to: C:\Users\[YourU)ser]\.dotnet\tools. -If it is not, run it directly via the path C:\Users\[YourUser]\.dotnet\tools\playwright.exe install --with-deps +Note: Make sure that the path to the executable is mapped to: C:\Users\[login]\.dotnet\tools. +If it is not, run it directly via the path C:\Users\[login]\.dotnet\tools\playwright.exe install --with-deps Usage ===== @@ -105,11 +121,20 @@ var clienthttp = HostApp!.Services .CreateClient("HtmlPdfServer"); //create client instance and send to HtmlPdfPlus server endpoint -var pdfresult = await HtmlPdfClient.Create("HtmlPdfPlusClient") - .PageConfig((cfg) => cfg.Margins(10)) - .FromHtml(HtmlSample()) - .Timeout(5000) - .Run(clienthttp, token); +var pdfresult = await HtmlPdfClient + .Create("HtmlPdfPlusClient") + .PageConfig((cfg) => + { + cfg.Margins(10) + .Footer("' of ") + .Header("'") + .Orientation(PageOrientation.Landscape) + .DisplayHeaderFooter(true); + }) + .Logger(HostApp.Services.GetService>()) + .FromHtml(HtmlSample()) + .Timeout(5000) + .Run(clienthttp, applifetime.ApplicationStopping); //performs writing to file after performing conversion if (pdfresult.IsSuccess) @@ -135,9 +160,11 @@ builder.Services.AddHtmlPdfService((cfg) => }); ... -app.MapPost("/GeneratePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] string requestclienthtmltopdf, CancellationToken token) => +app.MapPost("/GeneratePdf", async ([FromServices] IHtmlPdfServer PDFserver, [FromBody] Stream requestclienthtmltopdf, CancellationToken token) => { - return await PDFserver.Run(requestclienthtmltopdf, token); + var data = await requestclienthtmltopdf.ReadToBytesAsync(); + return await PDFserver + .Run(data, token); }).Produces>(200); @@ -149,24 +176,31 @@ CLIENT SIDE using HtmlPdfPlus; -//create client instance and send to HtmlPdfPlus server endpoint -var pdfresult = await HtmlPdfClient.Create("HtmlPdfPlusClient") - .PageConfig((cfg) => cfg.Margins(10)) - .FromHtml(HtmlSample()) - .Timeout(5000) - .Run(SendToServer, token); +// Generic suggestion for writing a file to a cloud like gcp/azure +// Suggested return would be the full path "repo/filename" +var paramTosave = new DataSavePDF("Filename.pdf","MyRepo","MyConnectionstring"); -//performs writing to file after performing conversion +var pdfresult = await HtmlPdfClient.Create("HtmlPdfPlusClient") + .PageConfig((cfg) => + { + cfg.Margins(10); + }) + .Logger(HostApp.Services.GetService>()) + .FromRazor(TemplateRazor(), order1) + .Timeout(50000) + .Run(SendToServer,paramTosave, applifetime.ApplicationStopping); + +//Shwo result if (pdfresult.IsSuccess) { - await File.WriteAllBytesAsync("html2pdfsample.pdf", pdfresult.OutputData!); + Console.WriteLine($"File PDF generate at {pdfresult.OutputData}"); } else { - //show error via pdfresult.Error + Console.WriteLine($"HtmlPdfClient error: {pdfresult.Error!}"); } -private static async Task> SendToServer(string requestdata, CancellationToken token) +private static async Task> SendToServer(byte[] requestdata, CancellationToken token) { //send requestdata to server and return result } @@ -179,14 +213,35 @@ using HtmlPdfPlus; ... var builder = WebApplication.CreateBuilder(args); -builder.Services.AddHtmlPdfService((cfg) => +builder.Services.AddHtmlPdfService((cfg) => { cfg.Logger(LogLevel.Debug, "MyPDFServer"); }); ... var PDFserver = HostApp.Services.GetHtmlPdfService(); -var result = await PDFserver.Run(requestdata , Token); +var result = await PDFserver + .ScopeRequest(data) + .BeforePDF( (html,inputparam, _) => + { + if (inputparam is null) + { + return Task.FromResult(html); + } + //performs replacement token substitution in the HTML source before performing the conversion + var aux = html.Replace("[{FileName}]", inputparam.Filename); + return Task.FromResult(aux); + }) + .AfterPDF( (pdfbyte, inputparam, token) => + { + if (inputparam is null) + { + return Task.FromResult(string.Empty); + } + //TODO : performs writing to file after performing conversion + return Task.FromResult(inputparam.Filename); + }) + .Run(token); //send result to client @@ -215,7 +270,7 @@ var PDFserver = HostApp!.Services.GetHtmlPdfService(); //Performs conversion and custom operations on the server var pdfresult = await PDFserver - .Source() + .ScopeData() .FromHtml(HtmlSample(),5000) .Run(applifetime.ApplicationStopping); diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfClientInstanceTests.cs b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfClientInstanceTests.cs new file mode 100644 index 0000000..0499197 --- /dev/null +++ b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfClientInstanceTests.cs @@ -0,0 +1,263 @@ +// *************************************************************************************** +// MIT LICENCE +// The maintenance and evolution is maintained by the HtmlPdfPlus team +// https://github.com/FRACerqueira/HtmlPdfPlus +// *************************************************************************************** + +using Microsoft.Extensions.Logging; +using Moq; +using HtmlPdfPlus.Client.Core; +using HtmlPdfPlus; + +namespace TestHtmlPdfPlus.HtmlPdfCliPlus +{ + public class HtmlPdfClientInstanceTests + { + private readonly HttpClient _mockHttpClient; + private readonly Mock _mockLogger; + private readonly DisableOptionsHtmlToPdf _disableOptions; + private readonly HtmlPdfClientInstance _clientInstance; + + public HtmlPdfClientInstanceTests() + { + _mockHttpClient = new HttpClient() + { + BaseAddress = new Uri("http://localhost:8099"), + Timeout = TimeSpan.FromMilliseconds(1), + }; + _mockLogger = new Mock(); + _disableOptions = DisableOptionsHtmlToPdf.EnabledAllFeatures; + _clientInstance = new HtmlPdfClientInstance("testAlias", _disableOptions); + } + + [Fact] + public void PageConfig_ShouldThrowArgumentNullException_WhenConfigIsNull() + { + Assert.Throws(() => _clientInstance.PageConfig(null)); + } + + [Fact] + public void PageConfig_ShouldSetPdfPageConfig() + { + _clientInstance.PageConfig(config => config.Margins(10)); + Assert.NotNull(_clientInstance); + } + + [Fact] + public void FromHtml_ShouldThrowArgumentNullException_WhenValueIsNull() + { + Assert.Throws(() => _clientInstance.FromHtml(null)); + } + + [Fact] + public void FromHtml_ShouldSetHtml() + { + _clientInstance.FromHtml(""); + Assert.NotNull(_clientInstance); + } + + [Fact] + public void FromUrl_ShouldSetHtml() + { + var uri = new Uri("http://example.com"); + _clientInstance.FromUrl(uri); + Assert.NotNull(_clientInstance); + } + + [Fact] + public void FromRazor_ShouldThrowArgumentNullException_WhenTemplateIsNull() + { + Assert.Throws(() => _clientInstance.FromRazor(null, new object())); + } + + [Fact] + public void FromRazor_ShouldSetHtml() + { + var lstprod = new List + { + new("Product", 9.99m) + }; + var order1 = new Order("Roberto Rivellino", "Rua São Jorge, 777", "+55 11 912345678", lstprod); + _clientInstance.FromRazor(TemplateRazor(), order1); + Assert.NotNull(_clientInstance); + } + + [Fact] + public void Logger_ShouldThrowArgumentException_WhenLogLevelIsInvalid() + { + Assert.Throws(() => _clientInstance.Logger(_mockLogger.Object, LogLevel.Error)); + } + + [Fact] + public void Logger_ShouldSetLogger() + { + _clientInstance.Logger(_mockLogger.Object, LogLevel.Debug); + Assert.NotNull(_clientInstance); + } + + [Fact] + public void Timeout_ShouldThrowArgumentException_WhenValueIsInvalid() + { + Assert.Throws(() => _clientInstance.Timeout(0)); + } + + [Fact] + public void Timeout_ShouldSetTimeout() + { + _clientInstance.Timeout(10000); + Assert.NotNull(_clientInstance); + } + + [Fact] + public void HtmlParser_ShouldSetHtmlParser() + { + _clientInstance.HtmlParser(true, error => { }); + Assert.NotNull(_clientInstance); + } + + [Fact] + public async Task Run_ShouldThrowInvalidOperationException_WhenHtmlIsEmpty() + { + await Assert.ThrowsAsync(() => _clientInstance.Run((html, token) => Task.FromResult(new HtmlPdfResult(true, false, TimeSpan.Zero, new byte[0])), CancellationToken.None)); + } + + [Fact] + public async Task Run_ShouldThrowArgumentNullException_WhenSubmitHtmlToPdfIsNull() + { + Func>>? submitHtmlToPdf = null; + _clientInstance.FromHtml("

test

"); + await Assert.ThrowsAsync(() => _clientInstance.Run(submitHtmlToPdf, CancellationToken.None)); + } + + [Fact] + public async Task Run_ShouldReturnHtmlPdfResult() + { + _clientInstance.FromHtml("

test

"); + var result = await _clientInstance.Run((html, token) => Task.FromResult(new HtmlPdfResult(true, false, TimeSpan.Zero, new byte[0])), CancellationToken.None); + Assert.NotNull(result); + } + + [Fact] + public async Task Run_HttpClient_ShouldThrowInvalidOperationException_WhenHtmlIsEmpty() + { + await Assert.ThrowsAsync(() => _clientInstance.Run(new HttpClient(), CancellationToken.None)); + } + + [Fact] + public async Task Run_HttpClient_ShouldReturnHtmlPdfResult() + { + _clientInstance.FromHtml("

test

"); + var result = await _clientInstance.Run(_mockHttpClient, CancellationToken.None); + Assert.NotNull(result); + } + + [Fact] + public async Task Run_HttpClient_WithEndpoint_ShouldThrowInvalidOperationException_WhenHtmlIsEmpty() + { + await Assert.ThrowsAsync(() => _clientInstance.Run(new HttpClient(), "http://example.com", CancellationToken.None)); + } + + [Fact] + public async Task Run_HttpClient_WithEndpoint_ShouldReturnHtmlPdfResult() + { + _clientInstance.FromHtml("

test

"); + var result = await _clientInstance.Run(_mockHttpClient, "http://example.com", CancellationToken.None); + Assert.NotNull(result); + } + + [Fact] + public async Task Run_CustomData_ShouldThrowInvalidOperationException_WhenHtmlIsEmpty() + { + await Assert.ThrowsAsync(() => _clientInstance.Run(new HttpClient(), null, CancellationToken.None)); + } + + [Fact] + public async Task Run_CustomData_ShouldReturnHtmlPdfResult() + { + _clientInstance.FromHtml("

test

"); + var result = await _clientInstance.Run(_mockHttpClient, null, CancellationToken.None); + Assert.NotNull(result); + } + + [Fact] + public async Task Run_CustomData_WithEndpoint_ShouldThrowInvalidOperationException_WhenHtmlIsEmpty() + { + await Assert.ThrowsAsync(() => _clientInstance.Run(new HttpClient(), "http://example.com", null, CancellationToken.None)); + } + + [Fact] + public async Task Run_CustomData_WithEndpoint_ShouldReturnHtmlPdfResult() + { + _clientInstance.FromHtml("

test

"); + var result = await _clientInstance.Run(_mockHttpClient, "http://example.com", null, CancellationToken.None); + Assert.NotNull(result); + } + + private static string TemplateRazor() + { + return """ + + + + + Customer Details + + + +

Customer Details

+

Name: @Model.CustomerName

+

Address: @Model.CustomerAddress

+

Phone Number: @Model.CustomerPhoneNumber

+ +

Products (@Model.Products.Count)

+ @if(Model.Products.Any()) + { + + + + + + + + + @foreach (var product in Model.Products) + { + + + + + } + +
Product NamePrice
@product.Name@product.Price.ToString("C")
+ } + else + { +

No products found.

+ } + + + """; + + } + + public record Product(string Name, decimal Price); + + public record Order(string CustomerName, string CustomerAddress, string CustomerPhoneNumber, List Products); + } +} \ No newline at end of file diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfClientTest.cs b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfClientTest.cs index 516da08..478d8d7 100644 --- a/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfClientTest.cs +++ b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfClientTest.cs @@ -7,7 +7,6 @@ using HtmlPdfPlus; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging; -using HtmlPdfPlus.Shared.Core; namespace TestHtmlPdfPlus.HtmlPdfCliPlus { @@ -110,7 +109,7 @@ await HtmlPdfClient.Create("Teste") [Fact] public async Task Ensure_Run_Error_When_NotSubmmitFunction() { - Func>>? submmitFunction = null; + Func>>? submmitFunction = null; await Assert.ThrowsAsync(async () => { #pragma warning disable CS8604 // Possible null reference argument. @@ -125,7 +124,7 @@ await HtmlPdfClient.Create("Teste") [Fact] public async Task Ensure_RunGeneric_Error_When_NotSubmmitFunction() { - Func>>? submmitFunction = null; + Func>>? submmitFunction = null; await Assert.ThrowsAsync(async () => { #pragma warning disable CS8604 // Possible null reference argument. @@ -196,82 +195,6 @@ public async Task Ensure_RunGeneric_Success_With_Timeout_RunFunction() Assert.IsType(result.Error); } - [Fact] - public async Task Ensure_Run_Compress_Decompress_Request() - { - RequestHtmlPdf request = new("x","",new(),100, null); - var result = await HtmlPdfClient.Create("Teste") - .PageConfig(cfg => - { - cfg.Header("

header

") - .Footer("

Footer

") - .Orientation(PageOrientation.Landscape) - .Format(1,2) - .Scale(1.4f) - .DisplayHeaderFooter(true) - .PrintBackground(false) - .Margins(1, 2, 3, 4); - }) - .FromHtml("

Test

") - .Timeout(10000) - .Run((eventdata, token) => - { - request = GZipHelper.DecompressRequest(eventdata); - return Task.FromResult(new HtmlPdfResult(true,false, TimeSpan.Zero, [])); - }); - Assert.Equal(10000, request.Timeout); - Assert.Equal("Teste", request.Alias); - Assert.Equal("

Test

", request.Html); - Assert.Equal("

header", request.Config!.Header); - Assert.Equal("

Footer", request.Config!.Footer); - Assert.True(request.Config.DisplayHeaderFooter); - Assert.False(request.Config.PrintBackground); - Assert.Equal(1.4f, request.Config.Scale); - Assert.Null(request.InputParam); - Assert.Equal(PageOrientation.Landscape, request.Config.Orientation); - Assert.Equal("1.0;2.0", request.Config.Size.ToString()); - Assert.Equal("1.0;2.0;3.0;4.0", request.Config.Margins.ToString()); - Assert.Equal([], result.OutputData!); - } - - [Fact] - public async Task Ensure_Run_Compress_Decompress_Request_with_Param() - { - RequestHtmlPdf request = new("x","", new(), 100, null); - var result = await HtmlPdfClient.Create("Teste") - .PageConfig(cfg => - { - cfg.Header("

header

") - .Footer("

Footer

") - .Orientation(PageOrientation.Landscape) - .Format(1, 2) - .Scale(1.4f) - .DisplayHeaderFooter(true) - .PrintBackground(false) - .Margins(1, 2, 3, 4); - }) - .FromHtml("

Test

") - .Timeout(10000) - .Run((eventdata, token) => - { - request = GZipHelper.DecompressRequest(eventdata); - return Task.FromResult(new HtmlPdfResult(true,false, TimeSpan.Zero, "output")); - },"input"); - Assert.Equal(10000, request.Timeout); - Assert.Equal("Teste", request.Alias); - Assert.Equal("

Test

", request.Html); - Assert.Equal("

header", request.Config!.Header); - Assert.Equal("

Footer", request.Config!.Footer); - Assert.True(request.Config.DisplayHeaderFooter); - Assert.False(request.Config.PrintBackground); - Assert.Equal(1.4f, request.Config.Scale); - Assert.Equal("input",request.InputParam); - Assert.Equal(PageOrientation.Landscape, request.Config.Orientation); - Assert.Equal("1.0;2.0", request.Config.Size.ToString()); - Assert.Equal("1.0;2.0;3.0;4.0", request.Config.Margins.ToString()); - Assert.Equal("output",result.OutputData); - } - [Fact] public void Scale_ThrowsArgumentException_WhenValueIsOutOfRange() { diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfConfigTest.cs b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfConfigTest.cs index f052424..a02dc07 100644 --- a/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfConfigTest.cs +++ b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfConfigTest.cs @@ -16,7 +16,7 @@ public class HtmlPdfConfigTest public void Ensure_Create_HtmlPdfConfig_FormatByWH() { var result = new HtmlPdfConfig(); - result.Format(); + result.Format(); Assert.Equal("210.0;297.0", result.PageConfig.Size.ToString()); } @@ -66,7 +66,7 @@ public void Ensure_Create_HtmlPdfConfig_HeaderNull() public void Ensure_Create_HtmlPdfConfig_Margins() { var result = new HtmlPdfConfig(); - result.Margins(1,2,3,4); + result.Margins(1, 2, 3, 4); Assert.Equal("1.0;2.0;3.0;4.0", result.PageConfig.Margins.ToString()); } @@ -74,7 +74,7 @@ public void Ensure_Create_HtmlPdfConfig_Margins() public void Ensure_Create_HtmlPdfConfig_MarginsClass() { var result = new HtmlPdfConfig(); - result.Margins(PageMargins.Create(1,2,3,4)); + result.Margins(PageMargins.Create(1, 2, 3, 4)); Assert.Equal("1.0;2.0;3.0;4.0", result.PageConfig.Margins.ToString()); } diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfConfigTests.cs b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfConfigTests.cs new file mode 100644 index 0000000..8670ef9 --- /dev/null +++ b/src/TestHtmlPdfCliPlus/HtmlPdfCliPlus/HtmlPdfConfigTests.cs @@ -0,0 +1,164 @@ +// *************************************************************************************** +// MIT LICENCE +// The maintenance and evolution is maintained by the HtmlPdfPlus team +// https://github.com/FRACerqueira/HtmlPdfPlus +// *************************************************************************************** + +using HtmlPdfPlus; +using HtmlPdfPlus.Client.Core; + +namespace TestHtmlPdfPlus.HtmlPdfCliPlus +{ + public class HtmlPdfConfigTests + { + private readonly HtmlPdfConfig _config; + + public HtmlPdfConfigTests() + { + _config = new HtmlPdfConfig(); + } + + [Fact] + public void DisplayHeaderFooter_ShouldSetDisplayHeaderFooter() + { + _config.DisplayHeaderFooter(true); + Assert.True(_config.PageConfig.DisplayHeaderFooter); + } + + [Fact] + public void Footer_ShouldSetFooter() + { + _config.Footer("Footer content"); + Assert.Equal("Footer content", _config.PageConfig.Footer); + } + + [Fact] + public void Footer_ShouldSetFooterToNull_WhenValueIsNullOrEmpty() + { + _config.Footer(null); + Assert.Null(_config.PageConfig.Footer); + + _config.Footer(string.Empty); + Assert.Null(_config.PageConfig.Footer); + } + + [Fact] + public void Format_ShouldSetPageSize() + { + var pageSize = new PageSize(210, 297); + _config.Format(pageSize); + Assert.Equal(pageSize, _config.PageConfig.Size); + } + + [Fact] + public void Format_ShouldSetPageSizeWithWidthAndHeight() + { + _config.Format(210, 297); + Assert.Equal(210, _config.PageConfig.Size.Width); + Assert.Equal(297, _config.PageConfig.Size.Height); + } + + [Fact] + public void Format_ShouldThrowArgumentException_WhenWidthOrHeightIsInvalid() + { + Assert.Throws(() => _config.Format(-1, 297)); + Assert.Throws(() => _config.Format(210, -1)); + } + + [Fact] + public void Header_ShouldSetHeader() + { + _config.Header("Header content"); + Assert.Equal("Header content", _config.PageConfig.Header); + } + + [Fact] + public void Header_ShouldSetHeaderToNull_WhenValueIsNullOrEmpty() + { + _config.Header(null); + Assert.Null(_config.PageConfig.Header); + + _config.Header(string.Empty); + Assert.Null(_config.PageConfig.Header); + } + + [Fact] + public void Margins_ShouldSetMargins() + { + var margins = new PageMargins(10, 10, 10, 10); + _config.Margins(margins); + Assert.Equal(margins, _config.PageConfig.Margins); + } + + [Fact] + public void Margins_ShouldSetMarginsWithTopBottomLeftRight() + { + _config.Margins(10, 20, 30, 40); + Assert.Equal(10, _config.PageConfig.Margins.Top); + Assert.Equal(20, _config.PageConfig.Margins.Bottom); + Assert.Equal(30, _config.PageConfig.Margins.Left); + Assert.Equal(40, _config.PageConfig.Margins.Right); + } + + [Fact] + public void Margins_ShouldThrowArgumentException_WhenAnyMarginValueIsInvalid() + { + Assert.Throws(() => _config.Margins(-1, 20, 30, 40)); + Assert.Throws(() => _config.Margins(10, -1, 30, 40)); + Assert.Throws(() => _config.Margins(10, 20, -1, 40)); + Assert.Throws(() => _config.Margins(10, 20, 30, -1)); + } + + [Fact] + public void Margins_ShouldSetMarginsWithSingleValue() + { + _config.Margins(10); + Assert.Equal(10, _config.PageConfig.Margins.Top); + Assert.Equal(10, _config.PageConfig.Margins.Bottom); + Assert.Equal(10, _config.PageConfig.Margins.Left); + Assert.Equal(10, _config.PageConfig.Margins.Right); + } + + [Fact] + public void Margins_ShouldThrowArgumentException_WhenSingleMarginValueIsInvalid() + { + Assert.Throws(() => _config.Margins(-1)); + } + + [Fact] + public void Orientation_ShouldSetOrientation() + { + _config.Orientation(PageOrientation.Landscape); + Assert.Equal(PageOrientation.Landscape, _config.PageConfig.Orientation); + } + + [Fact] + public void PreferCSSPageSize_ShouldSetPreferCSSPageSize() + { + _config.PreferCSSPageSize(true); + Assert.True(_config.PageConfig.PreferCSSPageSize); + } + + [Fact] + public void PrintBackground_ShouldSetPrintBackground() + { + _config.PrintBackground(false); + Assert.False(_config.PageConfig.PrintBackground); + } + + [Fact] + public void Scale_ShouldSetScale() + { + _config.Scale(1.5f); + Assert.Equal(1.5f, _config.PageConfig.Scale); + } + + [Fact] + public void Scale_ShouldThrowArgumentException_WhenScaleValueIsOutOfRange() + { + Assert.Throws(() => _config.Scale(0.05f)); + Assert.Throws(() => _config.Scale(2.5f)); + } + } + +} diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/GZipHelperTests.cs b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/GZipHelperTests.cs new file mode 100644 index 0000000..ac6cb12 --- /dev/null +++ b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/GZipHelperTests.cs @@ -0,0 +1,57 @@ +// *************************************************************************************** +// MIT LICENCE +// The maintenance and evolution is maintained by the HtmlPdfPlus team +// https://github.com/FRACerqueira/HtmlPdfPlus +// *************************************************************************************** + +using HtmlPdfPlus.Shared.Core; +using System.Text; + +namespace TestHtmlPdfPlus.HtmlPdfShrPlus +{ + public class GZipHelperTests + { + [Fact] + public async Task CompressAsync_ValidInput_CompressesData() + { + // Arrange + var input = Encoding.UTF8.GetBytes("Hello, World!"); + var cancellationToken = CancellationToken.None; + + // Act + var compressedData = await GZipHelper.CompressAsync(input, cancellationToken); + + // Assert + Assert.NotNull(compressedData); + Assert.NotEqual(input, compressedData); + } + + [Fact] + public async Task DecompressAsync_ValidInput_DecompressesData() + { + // Arrange + var input = Encoding.UTF8.GetBytes("Hello, World!"); + var cancellationToken = CancellationToken.None; + var compressedData = await GZipHelper.CompressAsync(input, cancellationToken); + + // Act + var decompressedData = await GZipHelper.DecompressAsync(compressedData, cancellationToken); + + // Assert + Assert.NotNull(decompressedData); + Assert.Equal(input, decompressedData); + } + + [Fact] + public async Task DecompressAsync_InvalidInput_ThrowsInvalidOperationException() + { + // Arrange + var invalidInput = new byte[] { 0xAF, 0x8B, 0x08 }; // Invalid GZip header + var cancellationToken = CancellationToken.None; + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => GZipHelper.DecompressAsync(invalidInput, cancellationToken)); + Assert.Equal("The input byte array is not a valid GZip stream.", exception.Message); + } + } +} diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/HtmlPdfConfigTests.cs b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/HtmlPdfConfigTests.cs new file mode 100644 index 0000000..ae9bfd2 --- /dev/null +++ b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/HtmlPdfConfigTests.cs @@ -0,0 +1,216 @@ +using HtmlPdfPlus; +using HtmlPdfPlus.Client.Core; +namespace TestHtmlPdfPlus.HtmlPdfShrPlus +{ + public class HtmlPdfConfigTests + { + [Fact] + public void DisplayHeaderFooter_SetsValue_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + + // Act + var result = config.DisplayHeaderFooter(true); + + // Assert + Assert.Equal(config, result); + Assert.True(config.PageConfig.DisplayHeaderFooter); + } + + [Fact] + public void Footer_SetsValue_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + var footer = "Footer content"; + + // Act + var result = config.Footer(footer); + + // Assert + Assert.Equal(config, result); + Assert.Equal(footer, config.PageConfig.Footer); + } + + [Fact] + public void Format_SetsPageSize_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + var pageSize = PageSize.A4; + + // Act + var result = config.Format(pageSize); + + // Assert + Assert.Equal(config, result); + Assert.Equal(pageSize, config.PageConfig.Size); + } + + [Fact] + public void Format_SetsWidthAndHeight_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + decimal width = 210; + decimal height = 297; + + // Act + var result = config.Format(width, height); + + // Assert + Assert.Equal(config, result); + Assert.Equal(width, config.PageConfig.Size.Width); + Assert.Equal(height, config.PageConfig.Size.Height); + } + + [Fact] + public void Header_SetsValue_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + var header = "Header content"; + + // Act + var result = config.Header(header); + + // Assert + Assert.Equal(config, result); + Assert.Equal(header, config.PageConfig.Header); + } + + [Fact] + public void Margins_SetsPageMargins_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + var margins = new PageMargins(10, 10, 10, 10); + + // Act + var result = config.Margins(margins); + + // Assert + Assert.Equal(config, result); + Assert.Equal(margins, config.PageConfig.Margins); + } + + [Fact] + public void Margins_SetsAllMargins_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + decimal margin = 10; + + // Act + var result = config.Margins(margin); + + // Assert + Assert.Equal(config, result); + Assert.Equal(margin, config.PageConfig.Margins.Top); + Assert.Equal(margin, config.PageConfig.Margins.Bottom); + Assert.Equal(margin, config.PageConfig.Margins.Left); + Assert.Equal(margin, config.PageConfig.Margins.Right); + } + + [Fact] + public void Margins_SetsIndividualMargins_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + decimal top = 10; + decimal bottom = 20; + decimal left = 30; + decimal right = 40; + + // Act + var result = config.Margins(top, bottom, left, right); + + // Assert + Assert.Equal(config, result); + Assert.Equal(top, config.PageConfig.Margins.Top); + Assert.Equal(bottom, config.PageConfig.Margins.Bottom); + Assert.Equal(left, config.PageConfig.Margins.Left); + Assert.Equal(right, config.PageConfig.Margins.Right); + } + + [Fact] + public void Orientation_SetsValue_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + var orientation = PageOrientation.Landscape; + + // Act + var result = config.Orientation(orientation); + + // Assert + Assert.Equal(config, result); + Assert.Equal(orientation, config.PageConfig.Orientation); + } + + [Fact] + public void PreferCSSPageSize_SetsValue_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + + // Act + var result = config.PreferCSSPageSize(true); + + // Assert + Assert.Equal(config, result); + Assert.True(config.PageConfig.PreferCSSPageSize); + } + + [Fact] + public void PrintBackground_SetsValue_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + + // Act + var result = config.PrintBackground(false); + + // Assert + Assert.Equal(config, result); + Assert.False(config.PageConfig.PrintBackground); + } + + [Fact] + public void Scale_SetsValue_ReturnsInstance() + { + // Arrange + var config = new HtmlPdfConfig(); + float scale = 1.5f; + + // Act + var result = config.Scale(scale); + + // Assert + Assert.Equal(config, result); + Assert.Equal(scale, config.PageConfig.Scale); + } + + [Fact] + public void Scale_InvalidValue_ThrowsArgumentException() + { + // Arrange + var config = new HtmlPdfConfig(); + float invalidScale = 2.5f; + + // Act & Assert + var exception = Assert.Throws(() => config.Scale(invalidScale)); + Assert.Equal("Scale amount must be between 0.1 and 2.", exception.Message); + } + }// *************************************************************************************** + // MIT LICENCE + // The maintenance and evolution is maintained by the HtmlPdfPlus team + // https://github.com/FRACerqueira/HtmlPdfPlus + // *************************************************************************************** + + namespace TestHtmlPdfPlus.HtmlPdfShrPlus + { + + } +} \ No newline at end of file diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/HtmlPdfResultTests.cs b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/HtmlPdfResultTests.cs new file mode 100644 index 0000000..1d67c2e --- /dev/null +++ b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/HtmlPdfResultTests.cs @@ -0,0 +1,80 @@ +// *************************************************************************************** +// MIT LICENCE +// The maintenance and evolution is maintained by the HtmlPdfPlus team +// https://github.com/FRACerqueira/HtmlPdfPlus +// *************************************************************************************** + +using System.IO.Compression; +using System.Text; +using HtmlPdfPlus; + +namespace TestHtmlPdfPlus.HtmlPdfShrPlus +{ + public class HtmlPdfResultTests + { + [Fact] + public void Constructor_ShouldInitializeProperties() + { + // Arrange + var isSuccess = true; + var bufferDrained = false; + var elapsedTime = TimeSpan.FromSeconds(1); + var outputData = "Test Data"; + var error = new Exception("Test Exception"); + + // Act + var result = new HtmlPdfResult(isSuccess, bufferDrained, elapsedTime, outputData, error); + + // Assert + Assert.Equal(isSuccess, result.IsSuccess); + Assert.Equal(bufferDrained, result.BufferDrained); + Assert.Equal(elapsedTime, result.ElapsedTime); + Assert.Equal(outputData, result.OutputData); + Assert.Equal(error, result.Error); + } + + [Fact] + public void DecompressOutputData_ShouldDecompressByteArray() + { + // Arrange + var isSuccess = true; + var bufferDrained = false; + var elapsedTime = TimeSpan.FromSeconds(1); + var originalData = Encoding.UTF8.GetBytes("Test Data"); + var compressedData = Compress(originalData); + var result = new HtmlPdfResult(isSuccess, bufferDrained, elapsedTime, compressedData); + + // Act + var decompressedResult = result.DecompressOutputData(); + + // Assert + Assert.Equal(originalData, decompressedResult.OutputData); + } + + [Fact] + public void DecompressOutputData_ShouldThrowInvalidOperationException_WhenOutputDataIsNotByteArray() + { + // Arrange + var isSuccess = true; + var bufferDrained = false; + var elapsedTime = TimeSpan.FromSeconds(1); + var outputData = "Test Data"; + var result = new HtmlPdfResult(isSuccess, bufferDrained, elapsedTime, outputData); + + // Act & Assert + Assert.Throws(() => result.DecompressOutputData()); + } + + private byte[] Compress(byte[] data) + { + using (var memoryStream = new System.IO.MemoryStream()) + { + using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) + { + gzipStream.Write(data, 0, data.Length); + } + return memoryStream.ToArray(); + } + } + } +} diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/RequestHtmlPdfTests.cs b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/RequestHtmlPdfTests.cs new file mode 100644 index 0000000..da03f92 --- /dev/null +++ b/src/TestHtmlPdfCliPlus/HtmlPdfShrPlus/RequestHtmlPdfTests.cs @@ -0,0 +1,152 @@ +// *************************************************************************************** +// MIT LICENCE +// The maintenance and evolution is maintained by the HtmlPdfPlus team +// https://github.com/FRACerqueira/HtmlPdfPlus +// *************************************************************************************** + +using HtmlPdfPlus; +using HtmlPdfPlus.Shared.Core; +using NUglify; +using System.Text; +using System.Text.Json; + +namespace TestHtmlPdfPlus.HtmlPdfShrPlus +{ + public class RequestHtmlPdfTests + { + [Fact] + public void Constructor_ValidParameters_ShouldInitializeProperties() + { + // Arrange + var html = ""; + var alias = "testAlias"; + var config = new PdfPageConfig(); + var timeout = 30000; + var inputParam = "input"; + + // Act + var request = new RequestHtmlPdf(html, alias, config, timeout, inputParam); + + // Assert + Assert.Equal(html, request.Html); + Assert.Equal(alias, request.Alias); + Assert.Equal(config, request.Config); + Assert.Equal(timeout, request.Timeout); + Assert.Equal(inputParam, request.InputParam); + } + + [Fact] + public void Constructor_NullHtml_ShouldThrowArgumentException() + { + // Arrange + string html = null; + + // Act & Assert + Assert.Throws(() => new RequestHtmlPdf(html)); + } + + [Fact] + public void Constructor_EmptyHtml_ShouldThrowArgumentException() + { + // Arrange + var html = ""; + + // Act & Assert + Assert.Throws(() => new RequestHtmlPdf(html)); + } + + [Fact] + public void Constructor_TimeoutLessThanOrEqualToZero_ShouldThrowArgumentException() + { + // Arrange + var html = ""; + var timeout = 0; + + // Act & Assert + Assert.Throws(() => new RequestHtmlPdf(html, timeout: timeout)); + } + + [Fact] + public void ChangeHtml_ValidHtml_ShouldUpdateHtml() + { + // Arrange + var html = ""; + var request = new RequestHtmlPdf(html); + var newHtml = "Updated"; + + // Act + request.ChangeHtml(newHtml, false); + + // Assert + Assert.Equal(newHtml, request.Html); + } + + [Fact] + public void ChangeHtml_NullHtml_ShouldThrowArgumentException() + { + // Arrange + var html = ""; + var request = new RequestHtmlPdf(html); + + // Act & Assert + Assert.Throws(() => request.ChangeHtml(null, false)); + } + + [Fact] + public void ChangeHtml_EmptyHtml_ShouldThrowArgumentException() + { + // Arrange + var html = ""; + var request = new RequestHtmlPdf(html); + + // Act & Assert + Assert.Throws(() => request.ChangeHtml("", false)); + } + + [Fact] + public void ChangeHtml_Minify_ShouldMinifyHtml() + { + // Arrange + var html = " Test "; + var request = new RequestHtmlPdf(html); + var expectedHtml = Uglify.Html(html).Code; + + // Act + request.ChangeHtml(html, true); + + // Assert + Assert.Equal(expectedHtml, request.Html); + } + + [Fact] + public void ToBytes_ShouldReturnByteArray() + { + // Arrange + var html = ""; + var request = new RequestHtmlPdf(html); + var expectedBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(request)); + + // Act + var result = request.ToBytes(); + + // Assert + Assert.Equal(expectedBytes, result); + } + + [Fact] + public async Task ToBytesCompress_ShouldReturnCompressedByteArray() + { + // Arrange + var html = ""; + var request = new RequestHtmlPdf(html); + var bytes = request.ToBytes(); + var expectedCompressedBytes = await GZipHelper.CompressAsync(bytes); + + // Act + var result = await request.ToBytesCompress(); + + // Assert + Assert.Equal(expectedCompressedBytes, result); + } + } +} diff --git a/src/TestHtmlPdfCliPlus/HtmlPdfSrvPlus/HtmlPdfServerTest.cs b/src/TestHtmlPdfCliPlus/HtmlPdfSrvPlus/HtmlPdfServerTest.cs index 04c901e..0cd148c 100644 --- a/src/TestHtmlPdfCliPlus/HtmlPdfSrvPlus/HtmlPdfServerTest.cs +++ b/src/TestHtmlPdfCliPlus/HtmlPdfSrvPlus/HtmlPdfServerTest.cs @@ -17,7 +17,7 @@ public class HtmlPdfServerTests public void BeforePDF_ThrowsArgumentNullException_WhenInputParamIsNull() { // Act & Assert - Assert.Throws(() => new HtmlPdfServer(null, "teste").Source(null).BeforePDF(null)); + Assert.Throws(() => new HtmlPdfServer(null, "teste").ScopeData(null).BeforePDF(null)); } @@ -25,7 +25,7 @@ public void BeforePDF_ThrowsArgumentNullException_WhenInputParamIsNull() public void AfterPDF_ThrowsArgumentNullException_WhenInputParamIsNull() { // Act & Assert - Assert.Throws(() => new HtmlPdfServer(null, "teste").Source(null).AfterPDF(null)); + Assert.Throws(() => new HtmlPdfServer(null, "teste").ScopeData(null).AfterPDF(null)); } [Fact] @@ -62,7 +62,7 @@ public async Task Run_ThrowsArgumentNullException_WhenRequestclientIsEmpty() // Arrange using var objbuilder = new HtmlPdfBuilder(null); // Act & Assert - await Assert.ThrowsAsync(async () => await new HtmlPdfServer(objbuilder, "Test").Run("", CancellationToken.None)); + await Assert.ThrowsAsync(async () => await new HtmlPdfServer(objbuilder, "Test").Run([], CancellationToken.None)); } [Fact] @@ -72,20 +72,7 @@ public async Task Run_ThrowsArgumentNullException_WhenNotExistfterPDFAndReturnCu using var objbuilder = new HtmlPdfBuilder(null); // Act & Assert await Assert.ThrowsAsync(async () => await new HtmlPdfServer(objbuilder, "Teste").Run( - new RequestHtmlPdf("","Teste", new PdfPageConfig(), 10000).ToStringCompress(), CancellationToken.None)); - } - - [Fact] - public async Task Run_Resultfalse_WhenInvalidFormatRequestclient() - { - // Arrange - using var objbuilder = new HtmlPdfBuilder(null); - // Act & Assert - var result = await new HtmlPdfServer(objbuilder, "Teste").Run("teste", CancellationToken.None); - Assert.IsType(result.Error); - Assert.False(result.IsSuccess); - Assert.True(result.ElapsedTime.TotalMilliseconds > 0); - Assert.Null(result.OutputData); + await new RequestHtmlPdf("","Teste", new PdfPageConfig(), 10000).ToBytesCompress(), CancellationToken.None)); } @@ -94,11 +81,10 @@ public async Task Run_Resultfalse_WhenErrorOnBeforePDF() { // Arrange using var objbuilder = new HtmlPdfBuilder(null); - var requestHtmlPdf = GZipHelper.CompressRequest("Client", new PdfPageConfig(), "

Test

", 10000, "teste"); - + var requestHtmlPdf = await new RequestHtmlPdf("

Test

","teste", new PdfPageConfig(),10000).ToBytesCompress(); // Act & Assert - var result = await new HtmlPdfServer(objbuilder, "Server") - .Request(requestHtmlPdf) + var result = await new HtmlPdfServer(objbuilder, "Server") + .ScopeRequest(requestHtmlPdf) .BeforePDF((_, _, _) => throw new InvalidTimeZoneException("Test")) .Run(CancellationToken.None); Assert.IsType(result.Error); @@ -120,7 +106,7 @@ public async Task Run_ResultTrue_BasicPDF() Orientation = PageOrientation.Landscape, Size = PageSize.A3 }; - var requestHtmlPdf = GZipHelper.CompressRequest("Client", config, "

Test

", 5000, null); + var requestHtmlPdf = await new RequestHtmlPdf("

Test

", "teste", new PdfPageConfig(), 5000).ToBytesCompress(); // Act & Assert var result = await new HtmlPdfServer(objbuilder, "Server") @@ -146,11 +132,11 @@ public async Task Run_ResultTrue_WithBeforePDF_AND_AfterPDF() Orientation = PageOrientation.Landscape, Size = PageSize.A3, }; - var requestHtmlPdf = GZipHelper.CompressRequest("Client", config, "

Test

", 50000, null); + var requestHtmlPdf = await new RequestHtmlPdf("

Test

", "teste", new PdfPageConfig(), 5000).ToBytesCompress(); // Act & Assert var result = await new HtmlPdfServer(objbuilder, "Server") - .Request(requestHtmlPdf) + .ScopeRequest(requestHtmlPdf) .BeforePDF((_,_,_) => Task.FromResult("

Test

")) .AfterPDF((_,_,_) => Task.FromResult("Test")) .Run(CancellationToken.None); diff --git a/src/docs/assemblies/HtmlPdfPlus.Shared.md b/src/docs/assemblies/HtmlPdfPlus.Shared.md index 4312c20..bbea437 100644 --- a/src/docs/assemblies/HtmlPdfPlus.Shared.md +++ b/src/docs/assemblies/HtmlPdfPlus.Shared.md @@ -14,6 +14,7 @@ | enum [PageOrientation](./HtmlPdfPlus/PageOrientation.md) | Orientation Page PDF | | class [PageSize](./HtmlPdfPlus/PageSize.md) | Page size for PDF. | | class [PdfPageConfig](./HtmlPdfPlus/PdfPageConfig.md) | The Config PDF page. | +| static class [StreamExtension](./HtmlPdfPlus/StreamExtension.md) | Extend function for Stream | ### See Also * [Main Index](../docindex.md) diff --git a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfClient.md b/src/docs/assemblies/HtmlPdfPlus/HtmlPdfClient.md index d398b24..792c0cb 100644 --- a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfClient.md +++ b/src/docs/assemblies/HtmlPdfPlus/HtmlPdfClient.md @@ -16,8 +16,6 @@ public static class HtmlPdfClient | --- | --- | | static [DisableOptions](HtmlPdfClient/DisableOptions.md) { get; set; } | Options for disabling internal features. | | static [Create](HtmlPdfClient/Create.md)(…) | Create an instance of Html to Pdf Client | -| static [ToHtmlPdfResult](HtmlPdfClient/ToHtmlPdfResult.md)(…) | Convert Response Data from server HtmlPdfPlus | -| static [ToHtmlPdfResult<T>](HtmlPdfClient/ToHtmlPdfResult.md)(…) | Convert Response Data from server HtmlPdfPlus | ### See Also diff --git a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfClient/ToHtmlPdfResult.md b/src/docs/assemblies/HtmlPdfPlus/HtmlPdfClient/ToHtmlPdfResult.md deleted file mode 100644 index 933a705..0000000 --- a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfClient/ToHtmlPdfResult.md +++ /dev/null @@ -1,50 +0,0 @@ -![HtmlPdfPLus Logo](https://raw.githubusercontent.com/FRACerqueira/HtmlPdfPLus/refs/heads/main/docs/images/iconsmall.png) - -### HtmlPdfClient.ToHtmlPdfResult method (1 of 2) -
- - -#### Convert Response Data from server HtmlPdfPlus - -```csharp -public static HtmlPdfResult ToHtmlPdfResult(this string dataresponse) -``` - -| parameter | description | -| --- | --- | -| dataresponse | Response data | - -### Return Value - -HtmlPdfResult - -### See Also - -* class [HtmlPdfClient](../HtmlPdfClient.md) -* namespace [HtmlPdfPlus](../../HtmlPdfPlus.Client.md) - ---- - -### HtmlPdfClient.ToHtmlPdfResult<T> method (2 of 2) - -#### Convert Response Data from server HtmlPdfPlus - -```csharp -public static HtmlPdfResult ToHtmlPdfResult(this string dataresponse) -``` - -| parameter | description | -| --- | --- | -| T | Type of result | -| dataresponse | Response data | - -### Return Value - -HtmlPdfResult - -### See Also - -* class [HtmlPdfClient](../HtmlPdfClient.md) -* namespace [HtmlPdfPlus](../../HtmlPdfPlus.Client.md) - - diff --git a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1.md b/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1.md index 7fe1564..79e9ed4 100644 --- a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1.md +++ b/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1.md @@ -24,7 +24,7 @@ public sealed class HtmlPdfResult | [Error](HtmlPdfResult-1/Error.md) { get; } | The exception during conversion. Exception | | [IsSuccess](HtmlPdfResult-1/IsSuccess.md) { get; } | If the conversion was successful | | [OutputData](HtmlPdfResult-1/OutputData.md) { get; } | Output custom data or PDF in byte[] | -| [DecompressBytes](HtmlPdfResult-1/DecompressBytes.md)() | Decompress output data if it is byte[] | +| [DecompressOutputData](HtmlPdfResult-1/DecompressOutputData.md)() | Decompress OutputData when type is byte[] | ### See Also diff --git a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1/DecompressOutputData.md b/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1/DecompressOutputData.md new file mode 100644 index 0000000..d5b57cd --- /dev/null +++ b/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1/DecompressOutputData.md @@ -0,0 +1,28 @@ +![HtmlPdfPLus Logo](https://raw.githubusercontent.com/FRACerqueira/HtmlPdfPLus/refs/heads/main/docs/images/iconsmall.png) + +### HtmlPdfResult<T>.DecompressOutputData method +
+ + +#### Decompress OutputData when type is byte[] + +```csharp +public HtmlPdfResult DecompressOutputData() +``` + +### Return Value + +The [`HtmlPdfResult`](../HtmlPdfResult-1.md) with OutputData Decompressed when type is byte[] + +### Exceptions + +| exception | condition | +| --- | --- | +| InvalidOperationException | OutputData is not byte[] | + +### See Also + +* class [HtmlPdfResult<T>](../HtmlPdfResult-1.md) +* namespace [HtmlPdfPlus](../../HtmlPdfPlus.Shared.md) + + diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient.md index b5ff8a9..336d14d 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient.md @@ -16,7 +16,7 @@ public interface IHtmlPdfClient | --- | --- | | [FromHtml](IHtmlPdfClient/FromHtml.md)(…) | Register HTML to be executed by the server. | | [FromRazor<T>](IHtmlPdfClient/FromRazor.md)(…) | Execute the Razor HTML template with the data and register the HTML. | -| [FromUrl](IHtmlPdfClient/FromUrl.md)(…) | ;Register Page Url to be executed by the server. | +| [FromUrl](IHtmlPdfClient/FromUrl.md)(…) | Register Page Url to be executed by the server. | | [HtmlParser](IHtmlPdfClient/HtmlParser.md)(…) | Execute parse validation of the HTML before sending it to the server. | | [Logger](IHtmlPdfClient/Logger.md)(…) | Set Logger integration. | | [PageConfig](IHtmlPdfClient/PageConfig.md)(…) | Set PDF page configuration. | diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/FromUrl.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/FromUrl.md index 0772357..84e4330 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/FromUrl.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/FromUrl.md @@ -4,7 +4,7 @@
-#### ;Register Page Url to be executed by the server. +#### Register Page Url to be executed by the server. ```csharp public IHtmlPdfClient FromUrl(Uri value) diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/Run.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/Run.md index 98aa11a..1ee1df9 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/Run.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfClient/Run.md @@ -8,7 +8,7 @@ ```csharp public Task> Run( - Func>> submitHtmlToPdf, + Func>> submitHtmlToPdf, CancellationToken token = default) ``` @@ -103,7 +103,7 @@ Returns bytes[] from HtmlPdfResult representing the asynchronous operation of co ```csharp public Task> Run( - Func>> submitHtmlToPdf, Tin? customData, + Func>> submitHtmlToPdf, Tin? customData, CancellationToken token = default) ``` diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2.md index cf30009..b4c4b12 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2.md @@ -19,9 +19,9 @@ public interface IHtmlPdfServer : IDisposable | name | description | | --- | --- | -| [Request](IHtmlPdfServer-2/Request.md)(…) | Transfer request client for [`IHtmlPdfServerContext`](./IHtmlPdfServerContext-2.md) server context for custom actions | | [Run](IHtmlPdfServer-2/Run.md)(…) | Perform HTML to PDF conversion from the request HtmlPdfCliPlus client. | -| [Source](IHtmlPdfServer-2/Source.md)(…) | Transfer context for [`IHtmlPdfServerContext`](./IHtmlPdfServerContext-2.md) server context with input data,and custom actions. Input data, for customizing HTML before converting to PDF on the server. | +| [ScopeData](IHtmlPdfServer-2/ScopeData.md)(…) | Transfer context scope for [`IHtmlPdfServerContext`](./IHtmlPdfServerContext-2.md) server with input data,and custom actions. Input data, for customizing HTML before converting to PDF on the server. | +| [ScopeRequest](IHtmlPdfServer-2/ScopeRequest.md)(…) | Transfer request client for [`IHtmlPdfServerContext`](./IHtmlPdfServerContext-2.md) server context scope for custom actions | ### See Also diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Run.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Run.md index 8a031ca..171695c 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Run.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Run.md @@ -7,12 +7,12 @@ #### Perform HTML to PDF conversion from the request HtmlPdfCliPlus client. ```csharp -public Task> Run(string requestClient, CancellationToken token = default) +public Task> Run(byte[] requestClient, CancellationToken token = default) ``` | parameter | description | | --- | --- | -| requestClient | The compressed data from the request HtmlPdfCliPlus client. | +| requestClient | The compressed byte[] data from the request HtmlPdfCliPlus client. | | token | The CancellationToken to perform the conversion. | ### Return Value diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Source.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/ScopeData.md similarity index 61% rename from src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Source.md rename to src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/ScopeData.md index f6e8ea4..e40567e 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Source.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/ScopeData.md @@ -1,13 +1,13 @@ ![HtmlPdfPLus Logo](https://raw.githubusercontent.com/FRACerqueira/HtmlPdfPLus/refs/heads/main/docs/images/iconsmall.png) -### IHtmlPdfServer<TIn,TOut>.Source method +### IHtmlPdfServer<TIn,TOut>.ScopeData method
-#### Transfer context for [`IHtmlPdfServerContext`](../IHtmlPdfServerContext-2.md) server context with input data,and custom actions. Input data, for customizing HTML before converting to PDF on the server. +#### Transfer context scope for [`IHtmlPdfServerContext`](../IHtmlPdfServerContext-2.md) server with input data,and custom actions. Input data, for customizing HTML before converting to PDF on the server. ```csharp -public IHtmlPdfServerContext Source(TIn? inputparam = default) +public IHtmlPdfServerContext ScopeData(TIn? inputparam = default) ``` ### Return Value diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Request.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/ScopeRequest.md similarity index 69% rename from src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Request.md rename to src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/ScopeRequest.md index 390ec3a..135b3c7 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/Request.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServer-2/ScopeRequest.md @@ -1,18 +1,18 @@ ![HtmlPdfPLus Logo](https://raw.githubusercontent.com/FRACerqueira/HtmlPdfPLus/refs/heads/main/docs/images/iconsmall.png) -### IHtmlPdfServer<TIn,TOut>.Request method +### IHtmlPdfServer<TIn,TOut>.ScopeRequest method
-#### Transfer request client for [`IHtmlPdfServerContext`](../IHtmlPdfServerContext-2.md) server context for custom actions +#### Transfer request client for [`IHtmlPdfServerContext`](../IHtmlPdfServerContext-2.md) server context scope for custom actions ```csharp -public IHtmlPdfServerContext Request(string requestClient) +public IHtmlPdfServerContext ScopeRequest(byte[] requestClient) ``` | parameter | description | | --- | --- | -| requestClient | The compressed data from the request HtmlPdfCliPlus client. | +| requestClient | The compressed byte[] data from the request HtmlPdfCliPlus client. | ### Return Value diff --git a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServerContext-2/Run.md b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServerContext-2/Run.md index 98d7dee..5d747e8 100644 --- a/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServerContext-2/Run.md +++ b/src/docs/assemblies/HtmlPdfPlus/IHtmlPdfServerContext-2/Run.md @@ -24,7 +24,7 @@ An instance of HtmlPdfResult. | --- | --- | | ArgumentException | Thrown when the empty source Html or Url. | | ArgumentException | Thrown when *TOut* is invalid. | -| ArgumentException | Thrown when [`Request`](../IHtmlPdfServer-2/Request.md) is invalid. | +| ArgumentException | Thrown when [`ScopeRequest`](../IHtmlPdfServer-2/ScopeRequest.md) is invalid. | ### See Also diff --git a/src/docs/assemblies/HtmlPdfPlus/StreamExtension.md b/src/docs/assemblies/HtmlPdfPlus/StreamExtension.md new file mode 100644 index 0000000..4f61018 --- /dev/null +++ b/src/docs/assemblies/HtmlPdfPlus/StreamExtension.md @@ -0,0 +1,23 @@ +![HtmlPdfPLus Logo](https://raw.githubusercontent.com/FRACerqueira/HtmlPdfPLus/refs/heads/main/docs/images/iconsmall.png) + +### StreamExtension class +
+ + +#### Extend function for Stream + +```csharp +public static class StreamExtension +``` + +### Public Members + +| name | description | +| --- | --- | +| static [ReadToBytesAsync](StreamExtension/ReadToBytesAsync.md)(…) | Read the stream and return the content as a byte[] | + +### See Also + +* namespace [HtmlPdfPlus](../HtmlPdfPlus.Shared.md) + + diff --git a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1/DecompressBytes.md b/src/docs/assemblies/HtmlPdfPlus/StreamExtension/ReadToBytesAsync.md similarity index 50% rename from src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1/DecompressBytes.md rename to src/docs/assemblies/HtmlPdfPlus/StreamExtension/ReadToBytesAsync.md index 764d130..49677bf 100644 --- a/src/docs/assemblies/HtmlPdfPlus/HtmlPdfResult-1/DecompressBytes.md +++ b/src/docs/assemblies/HtmlPdfPlus/StreamExtension/ReadToBytesAsync.md @@ -1,22 +1,22 @@ ![HtmlPdfPLus Logo](https://raw.githubusercontent.com/FRACerqueira/HtmlPdfPLus/refs/heads/main/docs/images/iconsmall.png) -### HtmlPdfResult<T>.DecompressBytes method +### StreamExtension.ReadToBytesAsync method
-#### Decompress output data if it is byte[] +#### Read the stream and return the content as a byte[] ```csharp -public byte[]? DecompressBytes() +public static Task ReadToBytesAsync(this Stream stream) ``` -### Return Value - -Output data decompressed +| parameter | description | +| --- | --- | +| stream | The stream | ### See Also -* class [HtmlPdfResult<T>](../HtmlPdfResult-1.md) +* class [StreamExtension](../StreamExtension.md) * namespace [HtmlPdfPlus](../../HtmlPdfPlus.Shared.md) diff --git a/src/docs/docindex.md b/src/docs/docindex.md index 069b6bf..0ce6d27 100644 --- a/src/docs/docindex.md +++ b/src/docs/docindex.md @@ -7,6 +7,7 @@ | public type | description | | --- | --- | +| static Extension [ReadToBytesAsync](./assemblies/HtmlPdfPlus/StreamExtension/ReadToBytesAsync.md) | Read the stream and return the content as a byte[] | | static class [HtmlPdfClient](./assemblies/HtmlPdfPlus/HtmlPdfClient.md) | Fluent interface commands to perform client HTML to PDF conversion | | class [HtmlPdfResult<T>](./assemblies/HtmlPdfPlus/HtmlPdfResult-1.md) | Result of converting Html to PDF | | class [PageMargins](./assemblies/HtmlPdfPlus/PageMargins.md) | Page margins. |