Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,4 @@ __pycache__/
*.xsd.cs

settings.local.json
examples/**/output
145 changes: 142 additions & 3 deletions GotenbergSharpApiClient.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,32 @@ VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gotenberg.Sharp.Api.Client", "src\Gotenberg.Sharp.Api.Client\Gotenberg.Sharp.Api.Client.csproj", "{75F783A4-9392-412F-9DFE-00EE89527C10}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FE638D0D-6A76-4BF4-AF06-D8AAB9726723}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GotenbergSharpClient.Tests", "test\GotenbergSharpClient.Tests\GotenbergSharpClient.Tests.csproj", "{EEAF9CA2-7962-176A-E851-BF81D8DE31F0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
examples\appsettings.json = examples\appsettings.json
examples\Directory.Build.props = examples\Directory.Build.props
examples\README.md = examples\README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GotenbergSharpClient.Tests", "test\GotenbergSharpClient.Tests\GotenbergSharpClient.Tests.csproj", "{EEAF9CA2-7962-176A-E851-BF81D8DE31F0}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DIExample", "examples\DIExample\DIExample.csproj", "{C022147F-DA63-5B3C-9349-FEB9675362DF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlConvert", "examples\HtmlConvert\HtmlConvert.csproj", "{6113FC36-F04E-B6CA-5C64-EA6156640C94}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlWithMarkdown", "examples\HtmlWithMarkdown\HtmlWithMarkdown.csproj", "{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OfficeMerge", "examples\OfficeMerge\OfficeMerge.csproj", "{2A1FC5B6-EB87-C86A-71BB-42784913627C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PdfConvert", "examples\PdfConvert\PdfConvert.csproj", "{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PdfMerge", "examples\PdfMerge\PdfMerge.csproj", "{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UrlConvert", "examples\UrlConvert\UrlConvert.csproj", "{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UrlsToMergedPdf", "examples\UrlsToMergedPdf\UrlsToMergedPdf.csproj", "{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Webhook", "examples\Webhook\Webhook.csproj", "{01C9F662-6378-3FC4-B629-9FD37A38033D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -46,10 +66,129 @@ Global
{EEAF9CA2-7962-176A-E851-BF81D8DE31F0}.Release|x64.Build.0 = Release|Any CPU
{EEAF9CA2-7962-176A-E851-BF81D8DE31F0}.Release|x86.ActiveCfg = Release|Any CPU
{EEAF9CA2-7962-176A-E851-BF81D8DE31F0}.Release|x86.Build.0 = Release|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Debug|x64.ActiveCfg = Debug|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Debug|x64.Build.0 = Debug|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Debug|x86.ActiveCfg = Debug|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Debug|x86.Build.0 = Debug|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Release|Any CPU.Build.0 = Release|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Release|x64.ActiveCfg = Release|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Release|x64.Build.0 = Release|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Release|x86.ActiveCfg = Release|Any CPU
{C022147F-DA63-5B3C-9349-FEB9675362DF}.Release|x86.Build.0 = Release|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Debug|x64.ActiveCfg = Debug|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Debug|x64.Build.0 = Debug|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Debug|x86.ActiveCfg = Debug|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Debug|x86.Build.0 = Debug|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Release|Any CPU.Build.0 = Release|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Release|x64.ActiveCfg = Release|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Release|x64.Build.0 = Release|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Release|x86.ActiveCfg = Release|Any CPU
{6113FC36-F04E-B6CA-5C64-EA6156640C94}.Release|x86.Build.0 = Release|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Debug|x64.ActiveCfg = Debug|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Debug|x64.Build.0 = Debug|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Debug|x86.ActiveCfg = Debug|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Debug|x86.Build.0 = Debug|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Release|Any CPU.Build.0 = Release|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Release|x64.ActiveCfg = Release|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Release|x64.Build.0 = Release|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Release|x86.ActiveCfg = Release|Any CPU
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3}.Release|x86.Build.0 = Release|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Debug|x64.ActiveCfg = Debug|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Debug|x64.Build.0 = Debug|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Debug|x86.ActiveCfg = Debug|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Debug|x86.Build.0 = Debug|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Release|Any CPU.Build.0 = Release|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Release|x64.ActiveCfg = Release|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Release|x64.Build.0 = Release|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Release|x86.ActiveCfg = Release|Any CPU
{2A1FC5B6-EB87-C86A-71BB-42784913627C}.Release|x86.Build.0 = Release|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Debug|x64.ActiveCfg = Debug|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Debug|x64.Build.0 = Debug|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Debug|x86.ActiveCfg = Debug|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Debug|x86.Build.0 = Debug|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Release|Any CPU.Build.0 = Release|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Release|x64.ActiveCfg = Release|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Release|x64.Build.0 = Release|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Release|x86.ActiveCfg = Release|Any CPU
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A}.Release|x86.Build.0 = Release|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Debug|x64.ActiveCfg = Debug|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Debug|x64.Build.0 = Debug|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Debug|x86.ActiveCfg = Debug|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Debug|x86.Build.0 = Debug|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Release|Any CPU.Build.0 = Release|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Release|x64.ActiveCfg = Release|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Release|x64.Build.0 = Release|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Release|x86.ActiveCfg = Release|Any CPU
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9}.Release|x86.Build.0 = Release|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Debug|x64.ActiveCfg = Debug|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Debug|x64.Build.0 = Debug|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Debug|x86.ActiveCfg = Debug|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Debug|x86.Build.0 = Debug|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Release|Any CPU.Build.0 = Release|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Release|x64.ActiveCfg = Release|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Release|x64.Build.0 = Release|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Release|x86.ActiveCfg = Release|Any CPU
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17}.Release|x86.Build.0 = Release|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Debug|x64.ActiveCfg = Debug|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Debug|x64.Build.0 = Debug|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Debug|x86.ActiveCfg = Debug|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Debug|x86.Build.0 = Debug|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Release|Any CPU.Build.0 = Release|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Release|x64.ActiveCfg = Release|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Release|x64.Build.0 = Release|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Release|x86.ActiveCfg = Release|Any CPU
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881}.Release|x86.Build.0 = Release|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Debug|x64.ActiveCfg = Debug|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Debug|x64.Build.0 = Debug|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Debug|x86.ActiveCfg = Debug|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Debug|x86.Build.0 = Debug|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Release|Any CPU.Build.0 = Release|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Release|x64.ActiveCfg = Release|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Release|x64.Build.0 = Release|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Release|x86.ActiveCfg = Release|Any CPU
{01C9F662-6378-3FC4-B629-9FD37A38033D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C022147F-DA63-5B3C-9349-FEB9675362DF} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{6113FC36-F04E-B6CA-5C64-EA6156640C94} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{893AD0F6-7E7E-8550-56D7-BBCB77933BD3} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{2A1FC5B6-EB87-C86A-71BB-42784913627C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{BB512649-8BE2-38B1-49D1-E8CA8701BA1A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{DDD4236E-F481-4DE9-306C-66E77A8D2CB9} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{9C18F2D1-E9E9-613A-DE10-4263A2EA8A17} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{A4D0B498-A934-2F11-2AA7-18D1D1C9E881} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{01C9F662-6378-3FC4-B629-9FD37A38033D} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E732CE09-693A-4EB7-BC1C-34E0D4E2E19F}
EndGlobalSection
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public void ConfigureServices(IServiceCollection services)

```
# Using GotenbergSharpClient
*See the [linqPad folder](linqpad/)* for complete examples.
*See the [examples folder](examples/)* for complete working examples as console applications.

## Required Using Statements
```csharp
Expand Down
2 changes: 2 additions & 0 deletions examples/DIExample/DIExample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project Sdk="Microsoft.NET.Sdk">
</Project>
70 changes: 70 additions & 0 deletions examples/DIExample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Gotenberg.Sharp.API.Client;
using Gotenberg.Sharp.API.Client.Domain.Builders;
using Gotenberg.Sharp.API.Client.Domain.Builders.Faceted;
using Gotenberg.Sharp.API.Client.Domain.Requests;
using Gotenberg.Sharp.API.Client.Domain.Settings;
using Gotenberg.Sharp.API.Client.Extensions;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

// Builds a simple DI container with logging enabled.
// Client retrieved through the service provider is configured with options defined in appsettings.json
// Watch the polly-retry policy in action:
// Turn off gotenberg, run this script and let it fail/retry two or three times.
// Turn gotenberg back on & the request will successfully complete.
// Example builds a 1 page PDF from the specified TargetUrl

const string TargetUrl = "https://www.cnn.com";
var saveToPath = args.Length > 0 ? args[0] : Path.Combine(Directory.GetCurrentDirectory(), "output");
Directory.CreateDirectory(saveToPath);

var services = BuildServiceCollection();
var sp = services.BuildServiceProvider();

var sharpClient = sp.GetRequiredService<GotenbergSharpClient>();
var request = await CreateUrlRequest();
var response = await sharpClient.UrlToPdfAsync(request);

var resultPath = Path.Combine(saveToPath, $"GotenbergFromUrl-{DateTime.Now:yyyyMMddHHmmss}.pdf");

await using (var destinationStream = File.Create(resultPath))
{
await response.CopyToAsync(destinationStream, CancellationToken.None);
}

Console.WriteLine($"PDF created: {resultPath}");

IServiceCollection BuildServiceCollection()
{
var config = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();

return new ServiceCollection()
.AddOptions<GotenbergSharpClientOptions>()
.Bind(config.GetSection(nameof(GotenbergSharpClient))).Services
.AddGotenbergSharpClient()
.Services.AddLogging(s => s.AddSimpleConsole(ops =>
{
ops.IncludeScopes = true;
ops.SingleLine = false;
ops.TimestampFormat = "hh:mm:ss ";
}));
}

Task<UrlRequest> CreateUrlRequest()
{
var builder = new UrlRequestBuilder()
.SetUrl(TargetUrl)
.ConfigureRequest(b => b.SetPageRanges("1-2"))
.WithPageProperties(b =>
{
b.SetPaperSize(PaperSizes.A4)
.SetMargins(Margins.None);
});

return builder.BuildAsync();
}
31 changes: 31 additions & 0 deletions examples/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Gotenberg.Sharp.Api.Client\Gotenberg.Sharp.Api.Client.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<None Include="..\appsettings.json" Link="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\resources\**\*.*" Link="resources\%(RecursiveDir)%(Filename)%(Extension)">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions examples/HtmlConvert/HtmlConvert.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project Sdk="Microsoft.NET.Sdk">
</Project>
71 changes: 71 additions & 0 deletions examples/HtmlConvert/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Gotenberg.Sharp.API.Client;
using Gotenberg.Sharp.API.Client.Domain.Builders;
using Gotenberg.Sharp.API.Client.Domain.Settings;
using Gotenberg.Sharp.API.Client.Infrastructure.Pipeline;

using Microsoft.Extensions.Configuration;

var config = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();

var options = new GotenbergSharpClientOptions();
config.GetSection(nameof(GotenbergSharpClient)).Bind(options);

var destinationDirectory = args.Length > 0 ? args[0] : Path.Combine(Directory.GetCurrentDirectory(), "output");
Directory.CreateDirectory(destinationDirectory);

var resourcePath = Path.Combine(AppContext.BaseDirectory, "resources", "Html", "ConvertExample");
var path = await CreateFromHtml(destinationDirectory, resourcePath, options);

Console.WriteLine($"PDF created: {path}");

static async Task<string> CreateFromHtml(string destinationDirectory, string resourcePath, GotenbergSharpClientOptions options)
{
using var handler = new HttpClientHandler();
using var authHandler = !string.IsNullOrWhiteSpace(options.BasicAuthUsername) && !string.IsNullOrWhiteSpace(options.BasicAuthPassword)
? new BasicAuthHandler(options.BasicAuthUsername, options.BasicAuthPassword) { InnerHandler = handler }
: null;

using var httpClient = new HttpClient(authHandler ?? (HttpMessageHandler)handler)
{
BaseAddress = options.ServiceUrl,
Timeout = options.TimeOut
};
Comment on lines +26 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix double-disposal of message handlers.

The using var declarations on both handler and authHandler cause double-disposal. When HttpClient is disposed, it disposes its message handler (either authHandler or handler). Since authHandler wraps handler as its InnerHandler, disposing authHandler also disposes handler. The explicit using statements then attempt to dispose these handlers again at the end of the scope.

Apply this diff to fix the disposal pattern:

-    using var handler = new HttpClientHandler();
-    using var authHandler = !string.IsNullOrWhiteSpace(options.BasicAuthUsername) && !string.IsNullOrWhiteSpace(options.BasicAuthPassword)
+    var handler = new HttpClientHandler();
+    var authHandler = !string.IsNullOrWhiteSpace(options.BasicAuthUsername) && !string.IsNullOrWhiteSpace(options.BasicAuthPassword)
         ? new BasicAuthHandler(options.BasicAuthUsername, options.BasicAuthPassword) { InnerHandler = handler }
         : null;
 
     using var httpClient = new HttpClient(authHandler ?? (HttpMessageHandler)handler)
     {
         BaseAddress = options.ServiceUrl,
         Timeout = options.TimeOut
     };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
using var handler = new HttpClientHandler();
using var authHandler = !string.IsNullOrWhiteSpace(options.BasicAuthUsername) && !string.IsNullOrWhiteSpace(options.BasicAuthPassword)
? new BasicAuthHandler(options.BasicAuthUsername, options.BasicAuthPassword) { InnerHandler = handler }
: null;
using var httpClient = new HttpClient(authHandler ?? (HttpMessageHandler)handler)
{
BaseAddress = options.ServiceUrl,
Timeout = options.TimeOut
};
var handler = new HttpClientHandler();
var authHandler = !string.IsNullOrWhiteSpace(options.BasicAuthUsername) && !string.IsNullOrWhiteSpace(options.BasicAuthPassword)
? new BasicAuthHandler(options.BasicAuthUsername, options.BasicAuthPassword) { InnerHandler = handler }
: null;
using var httpClient = new HttpClient(authHandler ?? (HttpMessageHandler)handler)
{
BaseAddress = options.ServiceUrl,
Timeout = options.TimeOut
};
🤖 Prompt for AI Agents
In examples/HtmlConvert/Program.cs around lines 26 to 35, the HttpMessageHandler
instances are declared with "using var" causing double-disposal when HttpClient
(which disposes its handler chain) is disposed; create the handlers without
"using" (remove the using on handler and authHandler), build authHandler with
handler as InnerHandler if needed, and keep HttpClient in a using so only
HttpClient is disposed (it will cascade-dispose the handler(s)); alternatively,
if you prefer explicit disposal, dispose only the outermost handler (authHandler
if non-null, otherwise handler) after disposing HttpClient — but do not dispose
both.


var sharpClient = new GotenbergSharpClient(httpClient);

var builder = new HtmlRequestBuilder()
.AddAsyncDocument(async doc =>
doc.SetBody(await GetHtmlFile(resourcePath, "body.html"))
.SetFooter(await GetHtmlFile(resourcePath, "footer.html"))
).WithPageProperties(dims => dims.UseChromeDefaults())
.WithAsyncAssets(async assets =>
assets.AddItem("ear-on-beach.jpg", await GetImageBytes(resourcePath))
)
.SetConversionBehaviors(b =>
b.AddAdditionalHeaders("hello", "from-earth")
)
.ConfigureRequest(b => b.SetPageRanges("1"));

var request = await builder.BuildAsync();

var resultPath = Path.Combine(destinationDirectory, $"GotenbergFromHtml-{DateTime.Now:yyyyMMddHHmmss}.pdf");
var response = await sharpClient.HtmlToPdfAsync(request);

await using var destinationStream = File.Create(resultPath);
await response.CopyToAsync(destinationStream, CancellationToken.None);

return resultPath;
}

static Task<byte[]> GetImageBytes(string resourcePath)
{
return File.ReadAllBytesAsync(Path.Combine(resourcePath, "ear-on-beach.jpg"));
}

static Task<byte[]> GetHtmlFile(string resourcePath, string fileName)
{
return File.ReadAllBytesAsync(Path.Combine(resourcePath, fileName));
}
2 changes: 2 additions & 0 deletions examples/HtmlWithMarkdown/HtmlWithMarkdown.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project Sdk="Microsoft.NET.Sdk">
</Project>
Loading
Loading