Skip to content

Commit

Permalink
feat: add OutputFormat option to add html output (#96)
Browse files Browse the repository at this point in the history
This change adds the OutputFormat option to BlazorReports to register a report to output either PDF or HTML format. This helps in debugging reports while building them.
  • Loading branch information
gabynevada authored Aug 24, 2024
1 parent a6d70da commit ff9ea24
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 82 deletions.
7 changes: 7 additions & 0 deletions examples/SimpleReportServer/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BlazorReports.Extensions;
using BlazorReports.Models;
using SimpleReportServer;

var builder = WebApplication.CreateSlimBuilder(args);
Expand All @@ -16,5 +17,11 @@
}

app.MapGroup("reports").MapBlazorReport<HelloReport, HelloReportData>();
app.MapGroup("reports")
.MapBlazorReport<HelloReport, HelloReportData>(opts =>
{
opts.ReportName = "HelloReportHtml";
opts.OutputFormat = ReportOutputFormat.Html;
});

app.Run();
4 changes: 2 additions & 2 deletions examples/SimpleReportServer/SimpleReportServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.1" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/BlazorReports.Client/BlazorReports.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.5" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.8" />
</ItemGroup>
</Project>
39 changes: 39 additions & 0 deletions src/BlazorReports/Extensions/BlazorReportExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using BlazorReports.Models;

namespace BlazorReports.Extensions;

/// <summary>
/// Extension methods for <see cref="BlazorReport" />.
/// </summary>
public static class BlazorReportExtensions
{
/// <summary>
/// Gets the content type for the specified <see cref="BlazorReport" />.
/// </summary>
/// <param name="blazorReport"> The <see cref="BlazorReport" /> to get the content type for. </param>
/// <returns> The content type for the specified <see cref="BlazorReport" />. </returns>
public static string GetContentType(this BlazorReport blazorReport)
{
return blazorReport.OutputFormat switch
{
ReportOutputFormat.Pdf => "application/pdf",
ReportOutputFormat.Html => "text/html",
_ => "application/pdf"
};
}

/// <summary>
/// Gets the file extension for the specified <see cref="BlazorReport" />.
/// </summary>
/// <param name="blazorReport"> The <see cref="BlazorReport" /> to get the file extension for. </param>
/// <returns> The file extension for the specified <see cref="BlazorReport" />. </returns>
public static string GetFileExtension(this BlazorReport blazorReport)
{
return blazorReport.OutputFormat switch
{
ReportOutputFormat.Pdf => "pdf",
ReportOutputFormat.Html => "html",
_ => "pdf"
};
}
}
16 changes: 10 additions & 6 deletions src/BlazorReports/Extensions/ReportExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ public static RouteHandlerBuilder MapBlazorReport<T>(
CancellationToken token
) =>
{
context.Response.ContentType = "application/pdf";
var contentType = blazorReport.GetContentType();
var extension = blazorReport.GetFileExtension();
context.Response.ContentType = contentType;
context.Response.Headers.Append(
"Content-Disposition",
$"attachment; filename=\"{blazorReport.Name}.pdf\""
$"attachment; filename=\"{blazorReport.Name}.{extension}\""
);
var result = await reportService.GenerateReport(
context.Response.BodyWriter,
Expand All @@ -118,7 +120,7 @@ CancellationToken token
}
}
)
.Produces<FileStreamHttpResult>(200, "application/pdf")
.Produces<FileStreamHttpResult>(200, blazorReport.GetContentType())
.Produces(StatusCodes.Status503ServiceUnavailable);
}

Expand Down Expand Up @@ -154,10 +156,12 @@ public static RouteHandlerBuilder MapBlazorReport<T, TD>(
CancellationToken token
) =>
{
context.Response.ContentType = "application/pdf";
var contentType = blazorReport.GetContentType();
var extension = blazorReport.GetFileExtension();
context.Response.ContentType = contentType;
context.Response.Headers.Append(
"Content-Disposition",
$"attachment; filename=\"{blazorReport.Name}.pdf\""
$"attachment; filename=\"{blazorReport.Name}.{extension}\""
);
var result = await reportService.GenerateReport(
context.Response.BodyWriter,
Expand All @@ -180,7 +184,7 @@ CancellationToken token
}
}
)
.Produces<FileStreamHttpResult>(200, "application/pdf")
.Produces<FileStreamHttpResult>(200, blazorReport.GetContentType())
.Produces(StatusCodes.Status503ServiceUnavailable);
}

Expand Down
7 changes: 6 additions & 1 deletion src/BlazorReports/Models/BlazorReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ namespace BlazorReports.Models;
/// </summary>
public class BlazorReport
{
/// <summary>
/// Output format for the report. Defaults to PDF.
/// </summary>
public ReportOutputFormat OutputFormat { get; set; } = ReportOutputFormat.Pdf;

/// <summary>
/// The name of the report.
/// </summary>
Expand Down Expand Up @@ -33,7 +38,7 @@ public class BlazorReport
/// <summary>
/// Assets path to use for the report.
/// </summary>
public Dictionary<string, string> Assets { get; set; } = new();
public Dictionary<string, string> Assets { get; set; } = [];

/// <summary>
/// The page settings to use for the report.
Expand Down
5 changes: 5 additions & 0 deletions src/BlazorReports/Models/BlazorReportRegistrationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ namespace BlazorReports.Models;
/// </summary>
public class BlazorReportRegistrationOptions
{
/// <summary>
/// Output format for the report. Defaults to PDF.
/// </summary>
public ReportOutputFormat OutputFormat { get; set; } = ReportOutputFormat.Pdf;

/// <summary>
/// The name of the report. This is utilized to generate the route for the report.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/BlazorReports/Models/BlazorReportRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public BlazorReport AddReport<T>(BlazorReportRegistrationOptions? options = null
);
var blazorReport = new BlazorReport
{
OutputFormat = options?.OutputFormat ?? ReportOutputFormat.Pdf,
Name = reportNameToUse,
NormalizedName = normalizedReportName,
Component = typeof(T),
Expand Down Expand Up @@ -124,6 +125,7 @@ public BlazorReport AddReport<T, TD>(BlazorReportRegistrationOptions? options =
);
var blazorReport = new BlazorReport
{
OutputFormat = options?.OutputFormat ?? ReportOutputFormat.Pdf,
Name = reportNameToUse,
NormalizedName = normalizedReportName,
Component = typeof(T),
Expand Down
17 changes: 17 additions & 0 deletions src/BlazorReports/Models/ReportOutputFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace BlazorReports.Models;

/// <summary>
/// Output format for the report.
/// </summary>
public enum ReportOutputFormat
{
/// <summary>
/// Portable Document Format
/// </summary>
Pdf,

/// <summary>
/// HyperText Markup Language
/// </summary>
Html
}
56 changes: 25 additions & 31 deletions src/BlazorReports/Services/BrowserServices/BrowserPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,24 @@ namespace BlazorReports.Services.BrowserServices;
/// <summary>
/// Represents a page in the browser
/// </summary>
internal sealed class BrowserPage : IAsyncDisposable
/// <remarks>
/// Creates a new instance of the BrowserPage
/// </remarks>
/// <param name="logger"> The logger</param>
/// <param name="targetId"> The id of the page in the browser</param>
/// <param name="connection"> The connection to the browser</param>
internal sealed class BrowserPage(
ILogger<BrowserPage> logger,
string targetId,
Connection connection
) : IAsyncDisposable
{
private readonly ILogger<BrowserPage> _logger;

/// <summary>
/// The id of the page in the browser
/// </summary>
internal readonly string TargetId;
private readonly Connection _connection;
private readonly CustomFromBase64Transform _transform;

/// <summary>
/// Creates a new instance of the BrowserPage
/// </summary>
/// <param name="logger"> The logger</param>
/// <param name="targetId"> The id of the page in the browser</param>
/// <param name="connection"> The connection to the browser</param>
public BrowserPage(ILogger<BrowserPage> logger, string targetId, Connection connection)
{
_logger = logger;
TargetId = targetId;
_connection = connection;
_transform = new CustomFromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces);
}
internal readonly string TargetId = targetId;
private readonly CustomFromBase64Transform _transform =
new(FromBase64TransformMode.IgnoreWhiteSpaces);

/// <summary>
/// Displays the HTML in the browser
Expand All @@ -47,17 +41,17 @@ public BrowserPage(ILogger<BrowserPage> logger, string targetId, Connection conn
/// <exception cref="ArgumentException"> Thrown when the HTML is null or whitespace</exception>
internal async Task DisplayHtml(string html, CancellationToken stoppingToken = default)
{
await _connection.ConnectAsync(stoppingToken);
await connection.ConnectAsync(stoppingToken);
if (string.IsNullOrWhiteSpace(html))
throw new ArgumentException("Value cannot be null or whitespace.", nameof(html));

// Enables or disables the cache
var cacheMessage = new BrowserMessage("Network.setCacheDisabled");
cacheMessage.Parameters.Add("cacheDisabled", false);
_connection.SendAsync(cacheMessage);
connection.SendAsync(cacheMessage);

var getPageFrameTreeMessage = new BrowserMessage("Page.getFrameTree");
await _connection.SendAsync(
await connection.SendAsync(
getPageFrameTreeMessage,
PageGetFrameTreeResponseSerializationContext
.Default
Expand All @@ -67,7 +61,7 @@ await _connection.SendAsync(
var pageSetDocumentContentMessage = new BrowserMessage("Page.setDocumentContent");
pageSetDocumentContentMessage.Parameters.Add("frameId", response.Result.FrameTree.Frame.Id);
pageSetDocumentContentMessage.Parameters.Add("html", html);
_connection.SendAsync(pageSetDocumentContentMessage);
connection.SendAsync(pageSetDocumentContentMessage);
},
stoppingToken
);
Expand All @@ -79,10 +73,10 @@ internal async ValueTask ConvertPageToPdf(
CancellationToken stoppingToken = default
)
{
await _connection.ConnectAsync(stoppingToken);
await connection.ConnectAsync(stoppingToken);
var message = CreatePrintToPdfBrowserMessage(pageSettings);

await _connection.SendAsync(
await connection.SendAsync(
message,
PagePrintToPdfResponseSerializationContext
.Default
Expand All @@ -101,7 +95,7 @@ await _connection.SendAsync(
{
if (finished)
break;
await _connection.SendAsync(
await connection.SendAsync(
ioReadMessage,
IoReadResponseSerializationContext.Default.BrowserResultResponseIoReadResponse,
async ioReadResponse =>
Expand Down Expand Up @@ -201,19 +195,19 @@ CancellationToken stoppingToken

private async ValueTask ClosePdfStream(string stream, CancellationToken stoppingToken = default)
{
await _connection.ConnectAsync(stoppingToken);
await connection.ConnectAsync(stoppingToken);
var ioCloseMessage = new BrowserMessage("IO.close");
ioCloseMessage.Parameters.Add("handle", stream);
_connection.SendAsync(ioCloseMessage);
connection.SendAsync(ioCloseMessage);
}

/// <summary>
/// Disposes the BrowserPage
/// </summary>
public async ValueTask DisposeAsync()
{
LogMessages.BrowserPageDispose(_logger, TargetId);
await _connection.DisposeAsync();
LogMessages.BrowserPageDispose(logger, TargetId);
await connection.DisposeAsync();
_transform.Dispose();
}
}
Loading

0 comments on commit ff9ea24

Please sign in to comment.