NETReporter 1.3.0

NETReporter

Knihovna pro generování reportů (PDF, SVG, HTML, JSON) z deklarativních JSON šablon a JSON dat.

Šablona popisuje stránku, sekce, rozvržení, styly a bindingy na data; knihovna ji zvaliduje, vyhodnotí nad daty a vykreslí. PDF a SVG kreslí QuestPDF, grafy OxyPlot.

Instalace

Balíček je v privátním NuGet feedu Advisor Software:

dotnet nuget add source https://nuget.advisor-soft.com/v3/index.json --name AdvisorSoft
dotnet add package NETReporter

Požadavky: .NET 10.

Rychlý start

using NetReporter;

var renderer = new ReportRenderer();

await using var template = File.OpenRead("template.json");
await using var data = File.OpenRead("data.json");
await using var pdf = await renderer.RenderAsync(template, data);   // výchozí formát je PDF

await using var file = File.Create("report.pdf");
await pdf.CopyToAsync(file);

S DI kontejnerem (ReportRenderer se registruje jako singleton):

services.AddNetReporter();                        // ReportRenderer, TemplateSchemaParser, TemplateAnalyzer, VisualTreeBuilder
services.AddNetReporter<MyPipelineObserver>();    // + vlastní IReportPipelineObserver

var renderer = serviceProvider.GetRequiredService<ReportRenderer>();

RenderAsync bere šablonu a data jako Stream a vrací Stream s výstupem (pozice 0). Při neplatné šabloně vyhodí InvalidOperationException s diagnostikami (zpráva + JSON cesta).

Šablona v kostce

{
  "version": "1.0",
  "meta": { "name": "Faktura", "culture": "cs-CZ", "palette": { "primary": "#1A73E8" } },
  "page": { "size": "A4", "orientation": "Portrait", "marginsMm": { "top": 15, "right": 12, "bottom": 15, "left": 12 } },
  "styles": {
    "base": { "font": "Arial", "fontSize": 9 },
    "h1": { "fontSize": 16, "bold": true, "color": "primary" }
  },
  "content": {
    "root": {
      "type": "Stack",
      "gapMm": 3,
      "items": [
        { "type": "Text", "text": "Faktura {{$.Number}}", "styleRef": "h1" },
        { "type": "Text", "text": "Vystaveno: {{$.Issued:dd.MM.yyyy}}, celkem {{$.Total:C2}}" },
        {
          "type": "Table",
          "columns": [
            { "key": "name", "header": "Položka", "width": "3*" },
            { "key": "price", "header": "Cena", "width": "1*", "align": "Right" }
          ],
          "rows": {
            "source": "$.Items",
            "as": "item",
            "cells": {
              "name": { "text": "{{item.Name}}" },
              "price": { "text": "{{item.Price:N2}}" }
            }
          }
        }
      ]
    }
  },
  "pageFooter": {
    "root": { "type": "PageNumbers", "mode": "Current", "showTotal": true, "separator": " / " }
  }
}
  • Sekce: pageBackground, pageHeader, reportHeader, content, reportFooter, firstPageFooter, pageFooter, pageOverlay.
  • Rozvržení: Stack, Row, Box, Absolute, Spacer, PageBreak; libovolný uzel lze opakovat nad kolekcí přes "repeat": { "source": "$.Items", "as": "item" }; "keepTogether": true (u Stack, Row, Box, Text, Paragraph, Table) zabrání zalomení uzlu přes stránku – nevejde-li se na zbytek stránky, přesune se celý na další.
  • Obsah: Text, Paragraph, HttpLink, Image, Line, PageNumbers, Barcode, Code2D (QR, DataMatrix…), Checkbox, Table (skupiny, souhrny, stránkování), Chart.
  • Binding: {{$.Cesta.K.Hodnote}} (kořen dat), {{alias.Pole}} (položka repeat/tabulky/grafu), formát za dvojtečkou ({{$.Total:N2}}, {{$.Date:dd.MM.yyyy}}), C# výrazy s prefixem # ({{#item.Qty * item.Price}}), systémové proměnné now, page.number, page.total. Formátuje se podle meta.culture.
  • Styly: pojmenované styly v styles (base platí pro vše), odkaz styleRef a inline style; písmo, barvy (#RRGGBB nebo název z meta.palette), okraje a výplně v mm, rámečky, zarovnání. Styl lze vybrat podle dat – styleRef může obsahovat binding, jehož výsledkem je jméno stylu ("styleRef": "{{# item.Overdue ? \"overdue\" : \"\" }}"); tabulky mají styl řádku rows.styleRef a buňky rows.cells.<key>.styleRef / style.

Kompletní popis formátu je v přibalené dokumentaci (viz níže) – kapitola 02_template_format.md.

Grafy

{
  "type": "Chart",
  "chartType": "Column",
  "source": "$.Months",
  "as": "m",
  "category": "{{m.Month}}",
  "series": [
    { "name": "2025", "value": "m.Revenue", "color": "primary" },
    { "name": "Plán", "value": "#m.Revenue * 1.1", "dashed": true }
  ],
  "valueAxis": { "format": "N0" },
  "legend": { "position": "Top" }
}

Typy Column, Bar, Line, Area, Pie, Donut; více sérií, paleta, legenda, osy, popisky hodnot, skládání. Kombinovaný graf: série může přepsat typ ("type": "Line") a čáry mohou mít druhou osu vpravo ("axis": "Secondary" + secondaryValueAxis). Grafy jsou vektorové ve všech výstupech. Podrobnosti: 02_template_format.md §7.11 a 17-charts.md.

Výstupní formáty

await using var output = await renderer.RenderAsync(template, data, new RenderOptions { Format = RenderFormat.Svg });
Formát Popis
RenderFormat.Pdf výchozí; plnohodnotné PDF se stránkováním
RenderFormat.Svg stejný layout a stránkování jako PDF; jeden SVG se stránkami pod sebou (data-pages, <svg data-page="N">)
RenderFormat.Html HTML náhled bez stránkování (vhodný pro editor/prohlížeč)
RenderFormat.Json strukturovaný výsledek renderu – vyhodnocené texty, data grafů, metadata obrázků a kódů; pro automatické a AI kontroly

Každou SVG stránku zvlášť vrací RenderSvgPagesAsync:

IReadOnlyList<string> pages = await renderer.RenderSvgPagesAsync(template, data);

Do SVG se nevkládají fonty – prohlížeč použije písmo nainstalované v systému (pozice znaků zůstanou zachované).

Ladění šablon: new RenderOptions { Format = RenderFormat.Html, RenderBindingsAsExpressions = true } zobrazí místo hodnot samotné binding výrazy.

Limit stránek: PDF/SVG render skončí RenderPageLimitExceededException po překročení RenderOptions.MaxPages (výchozí 10 000, 0 = bez limitu) – ochrana před šablonou se zacykleným layoutem. CancellationToken se kontroluje i během generování stránek. Generování PDF/SVG (QuestPDF) se v rámci procesu serializuje (souběžné generování QuestPDF tiše poškozuje výstup), takže souběžné požadavky na PDF/SVG čekají na řadu; HTML a JSON se renderují souběžně.

Metadata PDF

Vlastnosti dokumentu (Název, Autor, Předmět, Klíčová slova, Aplikace, Jazyk) se nastavují v meta.document. Hodnoty jsou texty s bindingy vyhodnocené nad daty; prázdný výsledek se nezapíše, klíčová slova mohou být pole a bez language se použije meta.culture. Metadata se zapisují jen do PDF.

"meta": {
  "name": "Faktura",
  "culture": "cs-CZ",
  "document": { "title": "Faktura {{$.Number}}", "author": "{{$.Supplier}}", "keywords": [ "faktura", "{{$.Number}}" ] }
}

Podrobnosti: 02_template_format.md §1.4.

Validace šablony

Šablonu lze zkontrolovat bez renderu. Parser ji ověří proti vestavěnému schématu a vrátí diagnostiky s JSON cestou k chybě:

using NetReporter.Common;
using NetReporter.Template.Parsing;

var parser = new TemplateSchemaParser();                  // výchozí ParserValidationMode.Strict
var result = parser.Parse(templateJson);

if (!result.Success)
{
    foreach (var d in result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error))
        Console.WriteLine($"{d.JsonPath}: {d.Message} ({d.Code})");
}
  • Strict hlásí neznámé vlastnosti a chybný obsah stylů (neznámá vlastnost, špatný typ, neplatný enum) jako chybu, Compat jako varování (new TemplateSchemaParser(validationMode: ParserValidationMode.Compat); při renderu new RenderOptions { ValidationMode = ParserValidationMode.Compat }, varování pak dostane pozorovatel v ParseCompletedContext.Diagnostics).
  • Diagnostiky mají stabilní Code a JsonPath (např. $.content.root.items[2].rows.source).
  • Schéma šablon (typy uzlů, vlastnosti, enumy) vrací TemplateSchemaProvider.Create().

Podrobnosti: kapitola 03_parser_and_validation.md.

Sledování pipeline

IReportPipelineObserver dostává události OnPipelineStarted, OnParseStarted/Completed, OnRenderStarted/Completed (doba, velikost výstupu) a OnError (fáze, kategorie, stabilní kód chyby) – vhodné pro metriky a logování. Registruje se přes AddNetReporter<TObserver>() nebo konstruktor ReportRenderer. Knihovna loguje přes ILogger, pokud předáte ILoggerFactory.

RenderCompletedContext v OnRenderCompleted nese také BindingDiagnostics a OmittedBindingDiagnostics: chyby v bindingech (nedokončené {{, nečíselná hodnota grafu…) render nezastaví, takže je jinak neuvidíte. Shodné diagnostiky se slučují a počet omezuje RenderOptions.MaxBindingDiagnostics (výchozí 200, 0 sběr vypne). Při selhání renderu je (do chyby nasbírané) nese i PipelineError v OnError.

Dokumentace v balíčku

Balíček obsahuje dokumentaci knihovny a šablon ve složce docs/ (po instalaci v %USERPROFILE%\.nuget\packages\netreporter\<verze>\docs\, na Linuxu ~/.nuget/packages/netreporter/<verze>/docs/). Rozcestník je docs/README.md:

Soubor Obsah
docs/user/pouziti-knihovny.md průvodce použitím knihovny krok za krokem
docs/dev/02_template_format.md formát šablony – sekce, uzly, vlastnosti, repeat, tabulky, grafy
docs/dev/03_parser_and_validation.md parser a validace šablon, diagnostiky
docs/dev/04_style_system.md stylovací systém
docs/dev/05_binding_system.md binding a výrazy
docs/dev/17-charts.md grafy – chování a omezení
docs/dev/01_introduction.md, 06_runtime_pipeline.md, 07_renderer_questpdf.md, 08_program_flow_example.md, 09_extensibility.md architektura knihovny, pipeline, renderer, rozšiřitelnost

Seznam změn všech verzí je v souboru CHANGELOG.md v kořeni balíčku; změny konkrétní verze ukazuje NuGet v release notes balíčku.

Licence

MIT, © Advisor Software s.r.o.

Zdrojový kód, ukázkové šablony a změny verzí: repozitář projektu.

No packages depend on NETReporter.

- Validation: the three enum synonyms that the renderers have always accepted - `Middle` (= `Center`) and `End` (= `Right` for `align`, `Bottom` for `alignVertical` / `cellVerticalAlign`) for alignment, and `NormalWeight` (= `Normal`) for `fontWeight` - are valid again in styles and in the node property `align` (table column); 1.2.0 rejected them as `NRP015` although they rendered correctly before. They are declared in the new `enumAliases` section of `template-schema.json` (`PropertySchema.EnumAliases` / `StylePropertySchema.EnumAliases`, additive), are not offered by the template editor, and any other unknown value is still `NRP015`. - Template editor: editing the template text on the JSON tab no longer closes the SignalR circuit for templates over about 16 KB (the Blazor Server limit for one incoming message was 32 KB, so the editor reset itself to the default template and lost the Undo history); the limit is now 4 MB (`EditorLimits.MaxHubMessageSize`, twice the 2 MB upload limit). - Validation: the format of colors in styles is now checked (new code `NRP029`, `DiagnosticCodes.InvalidColor`): `color`, `background`, `decorationColor`, `border*.color` and `shadow.color` must be a hex color `#RGB`, `#ARGB`, `#RRGGBB` or `#AARRGGBB` (the hash is optional, as with QuestPDF `Color.FromHex`) or a name from `meta.palette`, and the values in `meta.palette` are checked as well (`$.meta.palette.<name>`); an empty color is still ignored. Before, a style such as `"color": "red"` passed validation and the PDF render failed with an exception from QuestPDF. An error in strict mode, a warning in compat mode like the other style content checks; the HTML/JSON formats were more tolerant (CSS color names) but such a template could not be rendered to PDF either. The color of a `Line` node (`Line.color`) is checked the same way (reported on the node property, e.g. `$.content.root.items[1].color`; QuestPDF reads it as strictly as the colors of styles); chart colors (`series[].color`, `palette`) are checked separately and only as a warning in both modes, because OxyPlot reads only hex with a hash (`#RGB`, `#RRGGBB`, `#AARRGGBB`; also `R,G,B`), does not know color names or hex without the hash and silently falls back to `SteelBlue` (a `meta.palette` name is resolved to its value first). - A style border with an empty `color` (`"border": { "color": "" }`) now gets the default color `#000000` like a missing one; the empty string used to reach QuestPDF `BorderColor` and fail the render. - `PipelineError` (the argument of `IReportPipelineObserver.OnError`) has the new init properties `BindingDiagnostics` and `OmittedBindingDiagnostics` (additive, empty by default): when a render fails (page limit, cancellation, an exception from the renderer) the binding diagnostics collected up to the failure are delivered too, which helps to find the cause; an error in the parse stage carries an empty list. - Tables: new variables in the summary rows: `groupCount` (number of data rows of the group) in `rows.group.summary` and `totalCount` (number of all data rows) in `totalSummary`, e.g. `{{totalCount}}` or `{{# totalCount * 2 }}`; they replace the removed implicit row count of the `qty` cell. - Binding diagnostics: an invalid C# expression (compile error, reported as an error with the Roslyn code, e.g. `CS1525`) and a C# expression that throws at run time (warning with the exception type) are now reported with the JSON path instead of silently giving an empty text; the same problem on the same path is reported once per render. `IBindingEvaluator` has the new default interface method `Render(TextTemplate, DataContext, List<BindingDiagnostic>?, string?)` (custom evaluators keep compiling and report nothing); `TextTemplate.ParseDiagnostics` is new and `TextTemplateCache.GetOrParse` reports the parse diagnostics of a broken text on every path where it is used (before, only on the first one, because the text is parsed once per render), once per path. - C# expressions: methods without arguments over JSON arrays now work: `{{# root.items.Count() }}` (before, `Count()` failed silently and rendered an empty text although the property `root.items.Count` worked) and `Any()`, `First()`, `FirstOrDefault()`, `Last()`, `LastOrDefault()`; unsupported calls are reported as a warning. - Charts: a series value that cannot be converted to a number is reported once per series with the number of such values and the first one as an example (before, every different value was a separate diagnostic and flooded the limit of binding diagnostics); the value expression of a series and the `source` expressions of `repeat`, charts and tables are parsed once instead of on every data row or pass. - Template editor: turning the group or the total summary of a table off and on again in the table editor now restores the properties of `group`, `group.summary` and `totalSummary` that the editor does not manage (they were lost when the object was removed); the same for a summary that lost all its cells and got some again. - Template editor: the *Load template* dialog closed with the cross in its header no longer leaves the modal overlay behind (it blocked all clicks) and can be opened again; the dialog visibility is now bound two-way (`@bind-Visible`). - Template editor: after a node is deleted, the next sibling (or the previous one, or the parent only when there is no sibling) is selected instead of the parent, so pressing Delete again no longer removes the whole container with its children. - Schema: `PropertySchema.ColorFormat` (additive; the `colorFormat` property of `template-schema.json`) tells whether the format of a `color` property is validated: `hex` (the default when missing) or `unchecked` (`Chart.series.color`, which OxyPlot reads on its own and the validation checks with a warning); the descriptions of `Line.color` and `Chart.series.color` list the accepted notations. - Charts: a series or palette color for which OxyPlot throws `OverflowException` instead of `FormatException` (a hex notation that is too long such as `#FFFFFFFFF`, a number out of range such as `256,0,0` or `-1,0,0`) no longer fails the render of the chart; like every other unreadable color it falls back to `SteelBlue` (all colors of a chart are read through the new internal `ChartColors.TryParse`). The validation warns about such colors (`NRP029`, a warning in both modes). - Rendering: `RenderOptions.ValidationMode` (default `Strict`, so nothing changes) lets a caller render a template with `Compat` validation: problems that 1.2.0 started to reject as errors (unknown style property, wrong type, invalid enum or color, unknown node property) are warnings and the template renders as it did before. `ParseCompletedContext.Diagnostics` (new, additive) delivers the parse diagnostics (warnings) to the pipeline observer in both modes, and `ReportRenderer` logs them as one warning in `Compat`. `Compat` does not guarantee that the template renders: a value the renderer cannot accept (e.g. an invalid style color in PDF) still fails when the output is generated. - Rendering: `RenderOptions.OnBindingDiagnostics` (new `BindingDiagnosticsCallback` delegate, additive) delivers the binding diagnostics of one render to the caller without replacing the pipeline observer (an observer passed to `RenderAsync` replaces the one from the constructor/DI, the callback does not): it is called once after the render finished, also after a failed one (with what was collected up to the failure, empty for a parse error), and an exception thrown by it is logged and does not change the result of the render. - MCP server: `validate_data` and `validate_data_files` return the binding diagnostics of the render (`bindingDiagnostics`, the same entries as `render_report`), and a binding error makes `success=false` with an `error` message (before, only an exception of the render did; the prompt already said "fix binding problems until success=true"). Binding warnings do not fail the validation; a missing data field is not a binding problem and is not reported. - Validation: a margin or padding property (`marginMm`, `paddingTopMm`, ...) in the inline style of a paragraph span (`spans[].style`) now gives the warning `NRP030` (`DiagnosticCodes.SpanLayoutStyleIgnored`, a warning in both modes): PDF and SVG render only the text properties of a span and ignore it, HTML turns it into CSS of the span, so the outputs differed silently. A `styleRef` to a named style with such properties is not checked. - Template editor: quick consecutive edits of the same node with the same editor (the table or chart editor, the node property grid; each within 2 seconds of the previous one) are now one Undo step instead of one step per edit, so repeated clicking in the table editor no longer uses up the 50 steps of the history; Undo returns the state before the first edit of the series (`TemplateChange.GroupKey`, `TemplateHistory.CoalesceWindow`). - Template editor: the Preview tab now shows the binding errors of the template texts (an unterminated `{{`, an empty `{{}}`, an invalid C# expression) with their JSON path in the panel "Chyby bindingů v textech (z náhledu)" (`PreviewService.PreviewResult.BindingErrors`, collected through `RenderOptions.OnBindingDiagnostics`); before, such errors were invisible in the editor. Binding warnings are not shown: the preview runs over empty data, so they would only report the missing data (for example every chart). - Dependencies: removed the unused `SkiaSharp.Svg` 1.60.0 (with its transitive `SkiaSharp` 1.60.0, whose `win7-x64`/`win7-x86` runtimes caused the NETSDK1206 warning in every project; no code used it and the charts chapter says Skia measuring is intentionally not used) from the NuGet package. Other updates for known vulnerabilities and missing versions: AngleSharp 1.4.0 -> 1.8.3 (template editor), Microsoft.AspNetCore.OpenApi 10.0.3 -> 10.0.12 with Microsoft.OpenApi 2.12 (ReportServer API), AWSSDK.Core pinned to 4.0.102.8 (ReportServer core), AspNetCore.HealthChecks.UI 8.0.2 -> 9.0.0 and KubernetesClient pinned to 17.0.14 (ReportServer UI). The solution builds without warnings and `dotnet list package --vulnerable --include-transitive` reports nothing. - Validation: nodes that the AST builder cannot build are now reported with their JSON path and node id (an error in both modes) instead of being dropped silently - and because a parent with an unbuilt child is dropped too, one such node used to remove its whole subtree up to the section root (for `content` the template failed to build without a single diagnostic, in an optional section like `pageFooter` the section silently vanished): an empty required `Image.src`, `HttpLink.text`/`url`, `Barcode.value`, `Code2D.value`, `Checkbox.value` or `Chart.source` (`NRP011`), an incomplete `repeat` (empty or missing `source` or `as`: the repetition used to be ignored silently and the node rendered once; `NRP011`), an `Absolute.zIndex` that is not an integer in the Int32 range such as `1.5` (`NRP014`) and a `Row.columns` number out of the `decimal` range (`NRP014`). - Template editor: the template in progress is kept as a draft in the browser (`localStorage`, written 1.5 s after the last change), and a new circuit offers to restore it ("Obnovit" / "Zahodit") instead of silently starting with the default template - after a network loss, a pod restart or an expired Blazor circuit the work in progress used to be lost (the Undo history of the lost circuit still is). Saving to the server, loading, uploading and Reset clear the draft; only unsaved work is offered (`TemplateDraftStore`). - Template editor: the chart editor model (mapping of the chart node to and from JSON, the rules by chart type, series and palette operations) was extracted from the `ChartEditor` component into the public `ChartEditorModel` with tests, like the table editor model before; a series, palette or size value outside the `decimal` range no longer throws when the chart is loaded. - Rendering: a `Line` without `color` now uses the `color` of its style (`styles.base`, `styleRef`, inline `style`) as documented, and black only when the style has none. Before, the schema default `#000000` of `Line.color` was filled in before the build, so the color of the style was never used (the fallback in the renderers was unreachable); the default was removed from `template-schema.json`. A template whose style has a `color` and that has lines without their own `color` now draws those lines in that color instead of black; set the `color` of the line to `#000000` to keep it black. - Dependencies: QuestPDF 2025.12.3 -> 2026.9.1. This fixes the concurrent generation bug of QuestPDF (silently corrupted PDF/SVG output when documents are generated in parallel in one process), so the process-wide lock around `GeneratePdf`/`GenerateSvg` introduced in 1.2.0 is removed and PDF/SVG rendering is parallel again (`ConcurrentRenderTests` stay as a guard; they failed on 2025.12.3 and 2026.8.0 and pass on 2026.9). QuestPDF 2026.9 changed the font defaults (system fonts off, an unavailable font family or a missing glyph stops the generation), so `ReportRenderer` sets `UseSystemFonts = true`, `ThrowOnMissingFontFamilies = false` and `ThrowOnMissingTextGlyphs = false` at the first render to keep the behavior of the earlier versions (a template that uses a font that is not installed, for example `Inter` in a container, is rendered with the built-in Lato instead of failing). These are process-wide QuestPDF settings. The binary output of PDF files changed with the new QuestPDF version. - ReportServer: binding diagnostics of a render are now recorded on the render job (new nullable `text` column `RenderJobs.BindingDiagnosticsJson`, EF migration `AddRenderJobBindingDiagnostics`, applied when the API starts). The API collects them through `RenderOptions.OnBindingDiagnostics` (merged, at most 50 distinct, message cut to 1000 and JSON path to 500 characters) and returns them from the job detail (`GET /render/jobs/{id}`, `/render/jobs/last`, `/render/jobs/users/{userId}/last`: `bindingDiagnostics` with `severity`, `message`, `jsonPath`, and `bindingDiagnosticsOmitted`); the job lists return only the counts `bindingDiagnosticCount` and `bindingErrorCount`. An empty array means none, `null` means not recorded (a job from before the column, or a render that failed before bindings were evaluated; a failed render stores diagnostics only when it collected some). A cache hit takes the diagnostics of the original job (the same input gives the same diagnostics). Every render response now carries the header `X-Render-Job-Id` (the new cache-hit job for a cache hit; also on an error response once the job exists; exposed in the UI CORS policy) so that clients can read the diagnostics of exactly that job. - MCP server: `render_template` returns `bindingDiagnostics` (read from the recorded diagnostics of the ReportServer job; before, always `null` because the render ran in ReportServer) and the new field `jobId` (ReportServer render job id, to be used with `get_render_job` / `get_render_job_pdf`); `get_render_job` returns `bindingDiagnostics` and `bindingDiagnosticsOmitted`, `list_render_jobs` the counts `bindingDiagnosticCount` and `bindingErrorCount`. When the job cannot be read (or has no recorded diagnostics) `bindingDiagnostics` stays `null` and the render does not fail. - ReportServer UI: the Render page shows the binding diagnostics of the rendered job in a warning box, the Jobs page has the column "Bindingy" (count, red when there is an error; a tick when there are none) and lists the diagnostics in the detail of the user's own jobs (the detail of another user's job, which an admin sees, shows only the count), the Diagnostics page shows the count; the list is the new shared component `BindingDiagnosticsList`. - Fix (ReportServer): an exception message longer than the column `RenderJobs.ErrorMessage` (2000 characters, for example `DocumentLayoutException` of QuestPDF, whose message describes the whole layout) made saving the failed render throw `DbUpdateException`: the job stayed in the state Running and the client got an unhandled HTTP 500 instead of `RENDER_FAILED`. The stored message is now cut to the column length (ending with an ellipsis). - Fix (ReportServer UI): `AspNetCore.HealthChecks.UI` 9.0.0 references the assembly `IdentityModel` without declaring the dependency; it used to come with `KubernetesClient` 15.0.1, which the previous dependency update replaced by 17.0.14 (no longer depends on it), so the health collector of the dashboard `/health-ui` threw `FileNotFoundException` on every cycle and showed nothing. `IdentityModel` 5.2.0 is now referenced explicitly. Celý seznam změn: CHANGELOG.md v balíčku a https://dev.azure.com/advsoft/Knihovny/_git/NetReporter?path=/src/NetReporter/CHANGELOG.md

Version Downloads Last updated
3.9.2 3 10/28/2026
3.9.1 1 10/27/2026
3.9.0 6 10/20/2026
3.8.1 6 10/19/2026
3.8.0 4 10/19/2026
3.7.0 4 10/19/2026
3.6.0 6 10/17/2026
3.5.1 62 10/15/2026
3.5.0 4 10/15/2026
3.4.2 5 10/15/2026
3.4.0 4 10/12/2026
3.3.0 5 10/11/2026
3.2.2 5 10/10/2026
3.2.1 4 10/10/2026
3.2.0 4 10/10/2026
3.1.1 4 10/09/2026
3.1.0 5 10/09/2026
3.0.1 8 10/08/2026
3.0.0 5 10/08/2026
2.2.1 5 10/05/2026
2.2.0 4 10/05/2026
2.1.0 9 10/04/2026
2.0.1 8 10/04/2026
2.0.0 5 10/03/2026
1.7.0 6 10/03/2026
1.6.0 5 10/02/2026
1.5.0 12 10/02/2026
1.4.0 6 10/01/2026
1.3.0 4 10/01/2026
1.2.0 5 10/01/2026
1.1.1 6 09/30/2026
1.1.0 8 09/30/2026
1.0.10 4 09/29/2026
1.0.9 4 09/29/2026
1.0.8 16 09/29/2026
1.0.7 115 09/24/2026
1.0.6 9 09/24/2026
1.0.5 7 09/24/2026
1.0.4 11 09/24/2026
1.0.3 8 09/24/2026
1.0.2 13 09/23/2026
1.0.0 7 09/23/2026
0.9.1 13 09/23/2026
0.9.0 87 09/14/2026
0.8.1 25 02/20/2026
0.8.1-preview.1 34 02/13/2026
0.7.1-preview.2 32 02/10/2026
0.7.1-preview.1 33 02/10/2026
0.7.0 30 02/10/2026
0.0.6 28 02/01/2026
0.0.5 19 02/01/2026
0.0.0-alpha.0.17 35 02/01/2026