Implementacja: PrintReportWithJsonSource
Opis scenariusza biznesowego
Klasa demonstracyjna PrintReportWithJsonSource realizuje kluczowy scenariusz integracyjny, w którym aplikacja nadrzędna (np. mikroserwis WMS lub platforma e-commerce) posiada pełny zestaw danych gotowy w pamięci operacyjnej i nie chce, aby silnik sPrint API odpytywał zewnętrzne bazy danych SQL. Dane wejściowe przekazywane są w postaci ustrukturyzowanego dokumentu JSON (w tym przypadku pliku products.json), który definiuje kolekcję produktów wraz z ich właściwościami.
Klasa prezentuje dwa alternatywne podejścia architektoniczne do przesyłania szablonu raportu .sp oraz stowarzyszonego z nim źródła danych JSON:
- Podejście ścieżkowe (Path-Based): Zarówno szablon, źródło danych, jak i plik wynikowy PDF są procesowane na podstawie lokalnych lub sieciowych ścieżek fizycznych zdefiniowanych w systemie.
- Podejście strumieniowe (Byte-Based): Szablon oraz plik JSON są wczytywane do tablic bajtów, a wynikowy dokument PDF jest odbierany z serwera jako surowy strumień binarny i zapisywany w pamięci aplikacji klienckiej.
Analiza metod demonstracyjnych
1. Przetwarzanie oparte na ścieżkach (PrintReportFromPath)
Metoda PrintReportFromPath realizuje pełny cykl wydruku bez przesyłania dużych obiektów binarnych w payloadzie HTTP. W żądaniu przekazywane są wyłącznie wskaźniki lokalizacyjne. Silnik sPrint API samodzielnie odczytuje plik szablonu oraz plik danych bezpośrednio ze wskazanych ścieżek dyskowych, a wygenerowany dokument PDF zapisuje bezpośrednio pod ścieżką zdefiniowaną w konfiguracji wyjściowej.
Zaletą tego rozwiązania jest minimalne obciążenie sieci oraz brak konieczności serializacji i konwersji plików do formatu Base64 po stronie aplikacji integrującej.
2. Przetwarzanie oparte na strumieniach bajtów (PrintReportFromBytes)
Metoda PrintReportFromBytes to w pełni bezstanowy model, zalecany dla architektur rozproszonych i systemów chmurowych. Aplikacja kliencka asynchronicznie wczytuje plik szablonu oraz dane JSON do pamięci za pomocą metody File.ReadAllBytesAsync, a następnie przesyła je jako tablice bajtów. Silnik sPrint API przetwarza dane w pamięci podręcznej i zwraca gotowy dokument PDF jako binarny strumień odpowiedzi.
Kluczowym elementem tej metody jest poprawne odebranie strumienia oraz jego asynchroniczne skopiowanie do lokalnego strumienia pliku za pomocą instrukcji result.Stream.CopyToAsync(fileStream), co zapobiega uszkodzeniu struktury binarnej pliku PDF.
Pełny kod źródłowy przykładu (C#)
Poniższy blok kodu prezentuje kompletną implementację klasy PrintReportWithJsonSource w standardzie platformy .NET 8, zawierającą konfigurację polimorficznych modeli żądań oraz wstrzykiwanie parametrów biznesowych (takich jak filtr grupy produktów):
using Comarch.BI.CounterSprint.Integration.Client;
namespace Comarch.BI.CounterSprint;
public static class PrintReportWithJsonSource
{
private static readonly string ReportPath = Path.GetFullPath(@"Packages\JsonSource\CounterSprintJsonMain.sp");
private static readonly string ReportJsonSourcePath = Path.GetFullPath(@"Packages\JsonSource\products.json");
private static readonly string PrintResultPath1 = Path.GetFullPath(@"Packages\JsonSource\CounterSprintJsonMain1.pdf");
private static readonly string PrintResultPath2 = Path.GetFullPath(@"Packages\JsonSource\CounterSprintJsonMain2.pdf");
/// <summary>
/// Demonstration method: prints a report using file paths as sources.
/// </summary>
public static async Task PrintReportFromPath(IntegrationApiClient client)
{
var operationId = Guid.NewGuid().ToString();
LogStep($"Retrieving report information, operation ID: {operationId}");
var infoRequest = CreateInfoRequestFromPath(operationId);
var info = await client.InfoAsync(infoRequest);
LogStep($"Printing report to PDF, operation ID: {operationId}");
var printRequest = CreatePrintRequestFromPath();
await client.PrintAsync(printRequest);
LogStep($"Report saved to {PrintResultPath1}");
}
/// <summary>
/// Demonstration method: prints a report using byte arrays as sources.
/// </summary>
public static async Task PrintReportFromBytes(IntegrationApiClient client)
{
var operationId = Guid.NewGuid().ToString();
LogStep($"Retrieving report information, operation ID: {operationId}");
var infoRequest = await CreateInfoRequestFromBytes(operationId);
var info = await client.InfoAsync(infoRequest);
LogStep($"Printing report to PDF, operation ID: {operationId}");
var printRequest = await CreatePrintRequestFromBytes();
var result = await client.PrintAsync(printRequest);
// Bezpieczne zapisanie binarnego strumienia odpowiedzi do pliku PDF
await using (var fileStream = File.Create(PrintResultPath2))
{
await result.Stream.CopyToAsync(fileStream);
}
LogStep($"Report saved to {PrintResultPath2}");
}
private static PrintViewModel CreatePrintRequestFromPath()
=> new ()
{
OperationId = Guid.NewGuid().ToString(),
Report = new PathSourceViewModel { Path = ReportPath },
PrintFormat = FileFormat.Pdf,
Output = new PathOutputViewModel { Path = PrintResultPath1 },
DataSources = [new JsonDataSourceViewModel
{
JsonSource = new PathSourceViewModel { Path = ReportJsonSourcePath }
}],
Parameters = [new ParameterToReplaceViewModel
{
Name = "group_name",
Value = "Home Decor"
}]
};
private static async Task<PrintViewModel> CreatePrintRequestFromBytes()
=> new ()
{
OperationId = Guid.NewGuid().ToString(),
Report = new ByteSourceViewModel { Source = await File.ReadAllBytesAsync(ReportPath) },
PrintFormat = FileFormat.Pdf,
Output = new ByteOutputViewModel(),
DataSources = [new JsonDataSourceViewModel
{
JsonSource = new ByteSourceViewModel { Source = await File.ReadAllBytesAsync(ReportJsonSourcePath) }
}],
Parameters = [new ParameterToReplaceViewModel
{
Name = "group_name",
Value = "Furniture"
}]
};
private static InfoViewModel CreateInfoRequestFromPath(string operationId)
=> new ()
{
OperationId = operationId,
Report = new PathSourceViewModel { Path = ReportPath }
};
private static async Task<InfoViewModel> CreateInfoRequestFromBytes(string operationId)
=> new ()
{
OperationId = operationId,
Report = new ByteSourceViewModel { Source = await File.ReadAllBytesAsync(ReportPath) }
};
private static void LogStep(string message)
=> Console.WriteLine($"[Demo PrintReportWithJsonSource] {message}");
}
Kluczowe aspekty implementacyjne
- Dynamiczna parametryzacja (Parameters): W obu żądaniach przesyłana jest tablica obiektów ParameterToReplaceViewModel. Przekazanie parametru o nazwie group_name pozwala na natychmiastowe przefiltrowanie struktury JSON bezpośrednio w silniku sPrint (np. zawężenie wydruku katalogu produktów wyłącznie do sekcji Home Decor lub Furniture).
- Polimorfizm modeli raportu (Report): W zależności od scenariusza, właściwość Report przyjmuje obiekt PathSourceViewModel (wymagający podania ścieżki tekstowej) lub ByteSourceViewModel (wymagający wstrzyknięcia surowej tablicy bajtów).
- Konfiguracja źródeł JSON (JsonSource): Wewnątrz tablicy źródeł danych inicjalizowany jest dedykowany model JsonDataSourceViewModel. Silnik sPrint automatycznie mapuje strukturę pól zawartą w pliku JSON na pola zdefiniowane w warstwie wizualnej pliku szablonu .sp.