-
Notifications
You must be signed in to change notification settings - Fork 24
Convert LinqPad examples to .NET 8 console apps with basic auth middleware #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b566d5b
64119f3
b898101
96eda82
3cc6fdb
65cd8cf
28bb8fd
54cda1d
f4875f2
ce98331
096803d
fde2acb
4b93802
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -289,3 +289,4 @@ __pycache__/ | |
| *.xsd.cs | ||
|
|
||
| settings.local.json | ||
| examples/**/output | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| </Project> |
| 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(); | ||
| } |
| 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> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| </Project> |
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix double-disposal of message handlers. The 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| 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)); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| </Project> |
Uh oh!
There was an error while loading. Please reload this page.