NETReporter.Client 2.0.0

NETReporter.Client

Tenký klient pro ReportServer: stejné rozhraní jako knihovna NETReporter, ale report se vykreslí na serveru. Aplikace nemusí nést QuestPDF, Roslyn, OxyPlot ani ZXing; přihlašuje se API tokenem, který si vygenerujete v UI ReportServeru.

Klient implementuje IReportRenderer a ITemplateTools z balíčku NETReporter.Abstractions, takže mezi lokálním a vzdáleným renderem přepíná jen registrace v DI. Kód, který renderuje, se nemění.

Instalace

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

Požadavky: .NET 10. Balíčky NETReporter, NETReporter.Abstractions a NETReporter.Client se vydávají společně se stejnou verzí.

API token

  1. Přihlaste se do UI ReportServeru a otevřete stránku API tokeny.
  2. Zadejte název (a případně dobu platnosti) a token vytvořte. Otevřený text se ukáže jen jednou, server si pamatuje jen hash; uložte ho do tajných hodnot (proměnná prostředí, user secrets, trezor), ne do repozitáře.
  3. Token má stejná práva jako jeho vlastník. Odvolat ho může vlastník i správce; deaktivace vlastníka ho vyřadí hned.

Rychlý start s DI

using Microsoft.Extensions.DependencyInjection;
using NetReporter;

services.AddNetReporterClient(options =>
{
    options.BaseAddress = new Uri("https://reports.example.com/api");   // adresa API včetně předpony cesty
    options.ApiToken = configuration["NetReporter:ApiToken"];           // nrp_…
});

// kdekoli v aplikaci
public sealed class InvoiceService(IReportRenderer renderer)
{
    public async Task<byte[]> CreatePdfAsync(Stream template, Stream data)
    {
        await using var pdf = await renderer.RenderAsync(template, data);
        using var buffer = new MemoryStream();
        await pdf.CopyToAsync(buffer);
        return buffer.ToArray();
    }
}

Nastavení jde číst z konfigurace: services.AddNetReporterClient(configuration) čte sekci NetReporterClient s klíči BaseAddress, ApiToken a Timeout. Chybějící adresa nebo token zastaví aplikaci při startu srozumitelnou chybou.

Bez DI

using NetReporter.Client;

using var http = NetReporterClient.CreateHttpClient(new NetReporterClientOptions
{
    BaseAddress = new Uri("https://reports.example.com/api"),
    ApiToken = Environment.GetEnvironmentVariable("NETREPORTER_API_TOKEN")
});

IReportRenderer renderer = new ReportServerRenderer(http);
ITemplateTools tools = new ReportServerTemplateTools(http);

Co klient umí

  • Render libovolné šablony (ad-hoc) do všech formátů: PDF, HTML, JSON, SVG, WebP, PNG, JPEG, i po stránkách (RenderSvgPagesAsync, RenderWebpPagesAsync, …) a se všemi volbami RenderOptions (PDF/A, přílohy, šifrování, vodoznak, rozlišení…).
  • Diagnostiky bindingů přes RenderOptions.OnBindingDiagnostics a pozorovatele pipeline.
  • Nástroje nad šablonou (ITemplateTools): validace šablony a dat, datový kontrakt a ukázková data.
  • Mimo rozsah: správa uložených šablon, render podle uložené šablony a historie jobů (ty zůstávají v UI a REST API).

Čím se vzdálený render liší od lokálního

  • Soubory z disku se na serveru nenačítají: obrázky, SVG ani podklady PDF z cesty k souboru nefungují (použijte data URI nebo adresu http/https).
  • Server omezuje počet stránek, rozlišení obrazů a velikost příloh; diagnostik bindingů vrací nejvýše 50 různých.
  • RenderOptions.Icons se nepoužije: server vykresluje ikony vlastním katalogem.
  • Pozorovatel pipeline dostane zjednodušené události (parsování proběhlo na serveru).

Chyby

Situace Výjimka
Chyba v šabloně ReportServerException (kód TEMPLATE_VALIDATION_FAILED, Diagnostics s JSON cestami)
Vadné volby ArgumentException (ParamName == "options"), u lokálních kontrol bez volání serveru
Překročený limit stránek RenderPageLimitExceededException
Zrušení volajícím OperationCanceledException
Neplatný, odvolaný nebo prošlý token ReportServerException (AUTH_UNAUTHORIZED)
Server nedostupný nebo překročený Timeout ReportServerException (REPORTSERVER_UNAVAILABLE nebo REPORTSERVER_TIMEOUT)

ReportServerException dědí z InvalidOperationException, takže ji zachytí i kód napsaný pro lokální render. Seznam změn je v souboru CHANGELOG.md v balíčku.

No packages depend on NETReporter.Client.

- Template editor and ReportServer: **shared sign-in and registration** on ASP.NET Core Identity. The new project `NetReporter.Identity` (not a package) holds the accounts (schema `identity` in the ReportServer database with its own migration history; every host applies the migrations at start under the EF migration lock, the API before it reports ready, the UI and the editor in the background with `/readyz` not ready until done), the shared sign-in cookie `.NetReporter.Auth` (`Path=/`, Data Protection keys in `identity."DataProtectionKeys"` under the application name `NetReporter`, so a sign-in in one application holds in the other on the same host) and the account pages `Account/*` (Razor Pages served by both applications, split screen in the style of `nr-ui.css`, light and dark mode): sign-in, sign-out, registration (off by default: `NETREPORTER_AUTH_REGISTRATION_ENABLED`, or only for `NETREPORTER_AUTH_ALLOWED_EMAIL_DOMAINS`), forgotten password and e-mail confirmation (only with SMTP: `NETREPORTER_AUTH_SMTP_*` and `NETREPORTER_AUTH_PUBLIC_ORIGIN`, the links are never built from the `Host` header), change of password and the user administration for admins (create, roles, deactivate, set a password; delete in the ReportServer UI goes through the API, so the templates, jobs and stored files of the user go too). Sign-in with **Google and Microsoft is off by default** (on-premise) and is switched on by `NETREPORTER_AUTH_GOOGLE_*` and `NETREPORTER_AUTH_MICROSOFT_*` (client id, secret, tenant); an external account is linked to an existing account only by a verified e-mail (Google `email_verified`, Microsoft `userPrincipalName`, never `mail`) and creates an account only when registration or the e-mail domain allows it. Roles: `Admin`, `User` (ReportServer) and the new `Editor` (template editor); a registered account gets `User`. The admin is still seeded from `REPORTSERVER_ADMINSEED_*` (the log warns while the default password is in use). The sign-in of an open page is revalidated every 5 minutes (`NETREPORTER_AUTH_REVALIDATION_MINUTES`), so a deactivated account, a new password or a removed role signs the user out. Configuration: `NetReporter:Auth:*` or the flat `NETREPORTER_AUTH_*` variables, checked at start with an error in Czech that names the key and the variable. Docs: the new chapter `doc/netreporter-server/dev/21-prihlaseni-a-uzivatele.md` (configuration, the redirect URIs for Google and Microsoft Entra, the order of the rollout). - **Breaking** ReportServer API: the users moved to the shared accounts. At start the API imports the users of `public."Users"` and `"UserRoles"` with the same ids (templates, jobs and storage paths keep their owner; an inactive user becomes locked out); two e-mails that differ only in letter case stop the migration with an error, so check them before the update (the query is in chapter 21). Old passwords keep working and are rehashed at the next sign-in. `POST /auth/login` keeps its contract, but the e-mail is case-insensitive, an account is locked for 15 minutes after 5 failed attempts (the service account of the MCP server too) and every failure is the same `401 AUTH_INVALID_CREDENTIALS`. A new password (`POST /users`, `PUT /users/{id}/password`) needs at least 10 characters (`NETREPORTER_AUTH_PASSWORD_MIN_LENGTH`, no character classes), the roles are `User`, `Editor` and `Admin`, `PUT /users/{id}/active` with `false` locks the account and signs it out of the UI and the editor, and nobody can deactivate or delete themselves or the last active admin. The old tables stay in the database, unused. `JwtTokenIssuer`, `JwtOptions` and `AdminSeedOptions` of the server were replaced by `NetReporterAccessTokenIssuer`, `NetReporterJwtOptions` and `NetReporterAdminSeedOptions` of `NetReporter.Identity`. - **Breaking** ReportServer UI: signs in with the shared cookie; the JWT in `localStorage` is gone (the old key is removed), so every user signs in once more. For each call of the API the UI issues itself a 5-minute JWT of the signed-in user, so it needs the same `JWT_ISSUER`, `JWT_AUDIENCE` and `JWT_SIGNING_KEY` as the API and the account database (`REPORTSERVER_CONNECTION_STRING` or `NETREPORTER_IDENTITY_CONNECTION_STRING`); `UI_DATA_PROTECTION_REDIS` is no longer used. `/login` and `/users` redirect to the shared pages, the user panel has the change of password, the link to the template editor (role `Editor` or `Admin`) and the sign-out. A `401` of the API (different JWT settings) shows a configuration error instead of a sign-out, a `403` says that the permission is missing. - **Breaking** Template editor: with an account database (`NETREPORTER_IDENTITY_CONNECTION_STRING` or `REPORTSERVER_CONNECTION_STRING`) the editor requires a sign-in with the role `Editor` or `Admin` (others get the access-denied page); `NETREPORTER_AUTH_ENABLED=false`, or no database, keeps the single-user mode. With sign-in the templates and blocks in the editor database belong to the signed-in account (`IEditorUserContext` from the cookie in requests and from the authentication state in the Blazor circuit; the same id as in ReportServer), the items saved before by the local user are taken over by the seeded admin once at start (name collisions stay with the local user and are logged), the drafts and preview data in the browser, the gallery metadata and the thumbnail cache are kept per user (thumbnails of user templates are `Cache-Control: private`) and the app bar has a user menu (change password, users, ReportServer, sign out). - Fix: the template editor under a path base (`/edit` in k3s, ToDo #97): `UsePathBase` ran after the static files and the routing, so `/edit/css/site.css` and `/edit/_framework/blazor.server.js` returned 404 and `/edit/livez` the editor page. The path base is applied first now in the editor and the ReportServer UI, a GET with a different letter case of the path base (`/ui/...` for `/UI`) is redirected (301) to the canonical one, and `<base href>` follows the path base. Deployment: k3s has `UI_PATH_BASE=/UI` (as the ingress), the new `EDITOR_PATH_BASE=/edit`, the `NETREPORTER_AUTH_*` keys in the config map and the optional secrets `NETREPORTER_AUTH_GOOGLE_CLIENT_SECRET`, `NETREPORTER_AUTH_MICROSOFT_CLIENT_SECRET`, `NETREPORTER_AUTH_SMTP_PASSWORD` and `EDITOR_CONNECTION_STRING` (templates of the editor in the database; empty keeps the folder in the pod). The images of the API, the UI and the editor set `ASPNETCORE_FORWARDEDHEADERS_ENABLED=true` (https return addresses for Google and Microsoft behind Traefik and nginx), the nginx of the compose sample passes `Host $http_host`. Roll out the API first, then the UI, then the editor (chapter 21). 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 4 10/28/2026
3.9.1 1 10/27/2026
3.9.0 8 10/20/2026
3.8.1 3 10/19/2026
3.8.0 3 10/19/2026
3.7.0 3 10/19/2026
3.6.0 4 10/17/2026
3.5.1 4 10/15/2026
3.5.0 4 10/15/2026
3.4.2 4 10/15/2026
3.4.0 4 10/12/2026
3.3.0 4 10/11/2026
3.2.2 4 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 4 10/09/2026
3.0.1 4 10/08/2026
3.0.0 4 10/08/2026
2.2.1 5 10/05/2026
2.2.0 4 10/05/2026
2.1.0 4 10/04/2026
2.0.1 4 10/04/2026
2.0.0 4 10/03/2026
1.7.0 4 10/03/2026