diff --git a/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor b/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor
index 37456125..dd2f9d6d 100644
--- a/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor
+++ b/EnvelopeGenerator.ReceiverUI/Pages/ReportViewer.razor
@@ -1,12 +1,24 @@
@page "/reportviewer/"
@using DevExpress.XtraReports.UI;
+@using EnvelopeGenerator.ReceiverUI.Services;
+@inject InMemoryReportStorageWebExtension ReportStorage
-
+@if(Report is not null) {
+
+}
@code {
DxReportViewer reportViewer;
- XtraReport Report = new PredefinedReports.Report();
+ XtraReport? Report;
+
+ protected override async Task OnInitializedAsync() {
+ Report = ReportStorage.TryGetReport("LargeDatasetReport", out var savedReport)
+ ? savedReport
+ : PredefinedReports.ReportsFactory.GetReport("LargeDatasetReport");
+
+ await Task.CompletedTask;
+ }
}
\ No newline at end of file
diff --git a/EnvelopeGenerator.ReceiverUI/Program.cs b/EnvelopeGenerator.ReceiverUI/Program.cs
index 6d512004..778cb6ba 100644
--- a/EnvelopeGenerator.ReceiverUI/Program.cs
+++ b/EnvelopeGenerator.ReceiverUI/Program.cs
@@ -5,6 +5,7 @@ using DevExpress.DataAccess.Web;
using EnvelopeGenerator.ReceiverUI.Services;
using DevExpress.XtraReports.Services;
using DevExpress.Blazor.Reporting;
+using DevExpress.XtraReports.Web.Extensions;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add("#app");
@@ -20,6 +21,10 @@ builder.Services.AddScoped();
builder.Services.AddScoped();
DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EnvelopeGenerator.ReceiverUI.Data.DataItemList));
+DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EnvelopeGenerator.ReceiverUI.PredefinedReports.Report));
+builder.Services.AddSingleton();
+builder.Services.AddSingleton(sp => sp.GetRequiredService());
builder.Services.AddScoped();
+ReportStorageWebExtension.RegisterExtensionGlobal(new InMemoryReportStorageWebExtension());
await builder.Build().RunAsync();
\ No newline at end of file
diff --git a/EnvelopeGenerator.ReceiverUI/Services/CustomReportProvider.cs b/EnvelopeGenerator.ReceiverUI/Services/CustomReportProvider.cs
index fbe7a8f6..535d7ff1 100644
--- a/EnvelopeGenerator.ReceiverUI/Services/CustomReportProvider.cs
+++ b/EnvelopeGenerator.ReceiverUI/Services/CustomReportProvider.cs
@@ -5,7 +5,16 @@ using EnvelopeGenerator.ReceiverUI.PredefinedReports;
namespace EnvelopeGenerator.ReceiverUI.Services
{
public class CustomReportProvider : IReportProviderAsync {
+ private readonly InMemoryReportStorageWebExtension reportStorage;
+
+ public CustomReportProvider(InMemoryReportStorageWebExtension reportStorage) {
+ this.reportStorage = reportStorage;
+ }
+
public Task GetReportAsync(string id, ReportProviderContext context) {
+ if(reportStorage.TryGetReport(id, out var savedReport))
+ return Task.FromResult(savedReport);
+
return Task.FromResult(ReportsFactory.GetReport(id));
}
}
diff --git a/EnvelopeGenerator.ReceiverUI/Services/InMemoryReportStorageWebExtension.cs b/EnvelopeGenerator.ReceiverUI/Services/InMemoryReportStorageWebExtension.cs
new file mode 100644
index 00000000..96b40bb8
--- /dev/null
+++ b/EnvelopeGenerator.ReceiverUI/Services/InMemoryReportStorageWebExtension.cs
@@ -0,0 +1,83 @@
+using DevExpress.XtraReports.UI;
+using DevExpress.XtraReports.Web.Extensions;
+using EnvelopeGenerator.ReceiverUI.PredefinedReports;
+
+namespace EnvelopeGenerator.ReceiverUI.Services;
+
+public class InMemoryReportStorageWebExtension : ReportStorageWebExtension
+{
+ private const string DefaultReportName = "LargeDatasetReport";
+ private static readonly Dictionary Reports = new(StringComparer.OrdinalIgnoreCase);
+
+ public override bool CanSetData(string url) => IsValidUrl(url);
+
+ public override byte[] GetData(string url)
+ {
+ url = NormalizeUrl(url);
+
+ if (Reports.TryGetValue(url, out var reportLayout))
+ return reportLayout;
+
+ if (ReportsFactory.Reports.TryGetValue(url, out var reportFactory))
+ return SaveReport(reportFactory());
+
+ throw new DevExpress.XtraReports.Web.ClientControls.FaultException($"Report '{url}' was not found.");
+ }
+
+ public override Dictionary GetUrls()
+ {
+ var urls = ReportsFactory.Reports.Keys
+ .Concat(Reports.Keys)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToDictionary(name => name, name => name, StringComparer.OrdinalIgnoreCase);
+
+ return urls;
+ }
+
+ public override bool IsValidUrl(string url)
+ {
+ return !string.IsNullOrWhiteSpace(url)
+ && url.IndexOfAny(Path.GetInvalidFileNameChars()) < 0;
+ }
+
+ public override void SetData(XtraReport report, string url)
+ {
+ url = NormalizeUrl(url);
+ Reports[url] = SaveReport(report);
+ }
+
+ public override string SetNewData(XtraReport report, string defaultUrl)
+ {
+ var url = NormalizeUrl(defaultUrl);
+ Reports[url] = SaveReport(report);
+ return url;
+ }
+
+ public bool TryGetReport(string url, out XtraReport report)
+ {
+ url = NormalizeUrl(url);
+
+ if (!Reports.ContainsKey(url))
+ {
+ report = null!;
+ return false;
+ }
+
+ using var stream = new MemoryStream(Reports[url]);
+ report = XtraReport.FromXmlStream(stream, true);
+ report.Name = url;
+ return true;
+ }
+
+ private static string NormalizeUrl(string url)
+ {
+ return string.IsNullOrWhiteSpace(url) ? DefaultReportName : url;
+ }
+
+ private static byte[] SaveReport(XtraReport report)
+ {
+ using var stream = new MemoryStream();
+ report.SaveLayoutToXml(stream);
+ return stream.ToArray();
+ }
+}