SSRS2.NETCore
1.3.0
See the version list below for details.
dotnet add package SSRS2.NETCore --version 1.3.0
NuGet\Install-Package SSRS2.NETCore -Version 1.3.0
<PackageReference Include="SSRS2.NETCore" Version="1.3.0" />
<PackageVersion Include="SSRS2.NETCore" Version="1.3.0" />
<PackageReference Include="SSRS2.NETCore" />
paket add SSRS2.NETCore --version 1.3.0
#r "nuget: SSRS2.NETCore, 1.3.0"
#:package SSRS2.NETCore@1.3.0
#addin nuget:?package=SSRS2.NETCore&version=1.3.0
#tool nuget:?package=SSRS2.NETCore&version=1.3.0
SSRS2.NETCore
Cross-platform RDLC report engine for .NET Framework 4.7.2 / 4.8 and .NET 8 / 9 / 10. Drop-in replacement for the LocalReport of Microsoft's Report Viewer — generate PDF, Excel, Word, HTML, and image reports from existing .rdlc files on Windows, Linux, macOS, Docker, Kubernetes, and cloud environments.
No GDI+ and no libgdiplus. On Linux, SSRS2 needs fontconfig, which most systems have but
the official .NET Docker images do not; add it to your image:
RUN apt-get update && apt-get install -y --no-install-recommends libfontconfig1 && rm -rf /var/lib/apt/lists/*
(Alpine: apk add --no-cache fontconfig.)
Installation
dotnet add package SSRS2.NETCore
Basic Usage
using SSRS2.Reporting.NETCore;
// Load report definition
Stream reportDefinition; // your RDLC from file or resource
IEnumerable dataSource; // your data for the report
LocalReport report = new LocalReport();
report.LoadReportDefinition(reportDefinition);
report.DataSources.Add(new ReportDataSource("DataSet1", dataSource));
report.SetParameters(new[] { new ReportParameter("Parameter1", "value") });
// Render to PDF
byte[] pdf = report.Render("PDF");
// Or any other supported format
byte[] excel = report.Render("EXCELOPENXML"); // .xlsx
byte[] word = report.Render("WORDOPENXML"); // .docx
byte[] html = report.Render("HTML5"); // .html
byte[] png = report.Render("PNG"); // .png
Checking a report before running it
CheckDefinition() compiles the report definition, as rendering it would, and returns what the engine found, a
Warning per problem: its code, the item and the property it is about, the message. Nothing is rendered and no data is
needed, and it does not throw for a definition that is not valid.
LocalReport report = new LocalReport();
report.LoadReportDefinition(reportDefinition);
foreach (Warning problem in report.CheckDefinition())
{
// rsFieldReference | Textbox Title.Value | The Value expression for the text box 'Title' refers to the field 'Nmae'...
Console.WriteLine($"{problem.Severity} {problem.Code} | {problem.ObjectType} {problem.ObjectName}.{problem.PropertyName} | {problem.Message}");
}
An error means the report cannot run: XML that is not the RDL schema's, a field or a parameter that does not exist, a scope, an expression that does not compile. Useful before deploying a report, and where reports are generated or edited by a program.
Reports your application did not write: RestrictedCode
A report's expressions and custom code run with your application's permissions: on .NET 8 and later nothing restrains
them. For reports that come from elsewhere (uploaded by users, written by a language model, converted from another
tool), RestrictedCode holds them to what a report computes with: the report object model (Fields, Parameters,
Globals...), Visual Basic's functions, and .NET's text, numbers, dates, collections, regular expressions and cultures.
LocalReport report = new LocalReport { RestrictedCode = true };
report.LoadReportDefinition(reportDefinition);
Warning[] problems = report.CheckDefinition();
// rsCompilerErrorInExpression | TextRun Title.Paragraphs[0].TextRuns[0].Value |
// ... contains an error: [SSRS2001] 'System.IO.File' is not available to a restricted report
// problems[0].Expression: =System.IO.File.ReadAllText("/etc/hosts")
Files, the environment, processes, threads, reflection (GetType), native libraries (Declare) and code modules are
refused: the report does not compile, and the error names what was refused and the item it is in. A member Visual Basic
only finds when the expression runs (of a value typed Object) is checked then, and shows as #Error with a warning.
It is a guard against mistakes and injected code, not a boundary against a determined attacker, and it does not limit
time or memory: render hostile reports in a process of their own. .NET 8 and later.
A viewer of your own: toggles, sorts, drillthrough
A report shown on screen is more than its pages: a group's rows open on a click, a column sorts, a link leads to
another report. Render the report as HTML5 with the ActionScript device setting: every such click then calls your
script function with what was clicked, viewerAction('Toggle', id, event). Send it to your application, tell the
report, and render it again:
byte[] page = report.Render("HTML5", "<DeviceInfo><ActionScript>viewerAction</ActionScript></DeviceInfo>");
report.Toggle(id); // 'Toggle': a +/- box
report.Sort(sortId, SortOrder.Descending); // 'Sort': the id ends with _A or _D, the order asked for
int pageNumber = report.FindBookmark(bookmark); // 'Bookmark': a "Go to bookmark" link
LocalReport detail = report.Drillthrough(id, out string reportPath); // 'Drillthrough'
Drillthrough returns the report the action opens, holding the parameter values the action gives it: load its
definition if yours came from a stream, give it its rows, render it. FindDocumentMapNode gives the page of an entry
of GetDocumentMap(). Each call is what the click does in Report Viewer.
Supported Export Formats
| Format | Render string | Extension |
|---|---|---|
"PDF" |
||
| Excel | "EXCELOPENXML" |
.xlsx |
| Word | "WORDOPENXML" |
.docx |
| HTML5 | "HTML5" |
.html |
| HTML 4.0 | "HTML4.0" |
.html |
| MHTML | "MHTML" |
.mhtml |
| PNG | "PNG" |
.png |
| JPEG | "JPEG" |
.jpg |
| WebP | "WEBP" |
.webp |
| TIFF, every page in one file | "IMAGE" (DeviceInfo OutputFormat: TIFF by default) |
.tif |
| PNG or JPEG, a stream per page | "IMAGE" (DeviceInfo OutputFormat: PNG, JPEG), as Report Viewer's code that prints a report reads them |
.png, .jpg |
| CSV (the report's data) | "CSV" |
.csv |
| XML (the report's data) | "XML" |
.xml |
PDF: what it says of itself, passwords, PDF/A
A PDF carries the report's display name as its title and the report's Author, as Report Viewer's do. The device
information sets the rest, or other values:
report.DisplayName = "Sales by region";
byte[] pdf = report.Render("PDF", @"<DeviceInfo>
<Author>Finance</Author><Subject>Board pack</Subject><Keywords>sales, quarter</Keywords>
<UserPassword>to open it</UserPassword>
<OwnerPassword>to change what it permits</OwnerPassword>
<PermitPrinting>false</PermitPrinting><PermitCopying>false</PermitCopying>
</DeviceInfo>");
With a password the PDF is encrypted (AES-256). UserPassword is asked for when the file is opened; with an
OwnerPassword alone it opens freely and PermitPrinting, PermitCopying and PermitModifying say what its reader
may do.
<PdfA>true</PdfA> writes PDF/A-2b, for archives: the file holds its fonts, the profile of its colours and what it
says of itself, and cannot have a password. Text with characters its font lacks (drawn as boxes) keeps a file from
conforming: give such text a font that has them.
Platform Support
- Windows x64
- Linux x64 and ARM64 (Debian, Ubuntu, RHEL, Alpine)
- macOS (Intel & Apple Silicon)
- Docker & Kubernetes
- Azure App Service, AWS ECS, Google Cloud Run: wherever those containers run
Target Frameworks
- .NET Framework 4.7.2
- .NET Framework 4.8
- .NET 8.0 (LTS)
- .NET 9.0
- .NET 10.0
The same package works for both legacy .NET Framework apps and modern cross-platform .NET, so you can adopt SSRS2 in place on Windows today and migrate to .NET 10 / Linux when ready.
Licensing
SSRS2.NETCore is commercially licensed: one licence per company, USD 799 a year or USD 1,999 for three years, bought at ssrs2.net/pricing. A key keeps working forever with every version released until its date. Without a license key, output renders with a trial watermark (no exceptions thrown). See LICENSE.md and the licence terms.
Documentation
For full documentation, migration guides, and live demos, visit ssrs2.net.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Framework | net472 is compatible. net48 is compatible. net481 was computed. |
-
.NETFramework 4.7.2
- Microsoft.CodeAnalysis.VisualBasic (>= 4.8.0)
- PdfSharp (>= 6.2.0)
- SkiaSharp (>= 2.88.8)
- SkiaSharp.HarfBuzz (>= 2.88.8)
- System.Text.Json (>= 8.0.5)
-
.NETFramework 4.8
- Microsoft.CodeAnalysis.VisualBasic (>= 4.8.0)
- PdfSharp (>= 6.2.0)
- SkiaSharp (>= 2.88.8)
- SkiaSharp.HarfBuzz (>= 2.88.8)
- System.Text.Json (>= 8.0.5)
-
net10.0
- HarfBuzzSharp.NativeAssets.Linux (>= 8.3.1.5)
- Microsoft.CodeAnalysis.VisualBasic (>= 4.14.0)
- PdfSharp (>= 6.2.0)
- SkiaSharp (>= 3.119.4)
- SkiaSharp.HarfBuzz (>= 3.119.4)
- SkiaSharp.NativeAssets.Linux (>= 3.119.4)
- System.CodeDom (>= 10.0.0)
- System.IO.Packaging (>= 10.0.0)
- System.Security.Cryptography.Xml (>= 10.0.11)
- System.ServiceModel.Http (>= 10.0.652802)
-
net8.0
- HarfBuzzSharp.NativeAssets.Linux (>= 8.3.1.5)
- Microsoft.CodeAnalysis.VisualBasic (>= 4.8.0)
- PdfSharp (>= 6.2.0)
- SkiaSharp (>= 3.119.4)
- SkiaSharp.HarfBuzz (>= 3.119.4)
- SkiaSharp.NativeAssets.Linux (>= 3.119.4)
- System.CodeDom (>= 8.0.0)
- System.IO.Packaging (>= 8.0.1)
- System.Security.Cryptography.Xml (>= 8.0.4)
- System.ServiceModel.Http (>= 8.1.0)
-
net9.0
- HarfBuzzSharp.NativeAssets.Linux (>= 8.3.1.5)
- Microsoft.CodeAnalysis.VisualBasic (>= 4.8.0)
- PdfSharp (>= 6.2.0)
- SkiaSharp (>= 3.119.4)
- SkiaSharp.HarfBuzz (>= 3.119.4)
- SkiaSharp.NativeAssets.Linux (>= 3.119.4)
- System.CodeDom (>= 9.0.0)
- System.IO.Packaging (>= 9.0.0)
- System.Security.Cryptography.Xml (>= 9.0.19)
- System.ServiceModel.Http (>= 8.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.3.0: LocalReport.CheckDefinition() returns each problem of a report definition (its code, item, property and expression) without rendering it. LocalReport.RestrictedCode holds the expressions and custom code of reports your application did not write to the report object model, Visual Basic's functions and .NET's text, number, date and collection types (.NET 8 and later). Toggle, Sort, FindBookmark, FindDocumentMapNode and Drillthrough are public, to build a viewer on the HTML output. PDFs carry their title and author, can be encrypted with passwords and permissions (AES-256), and can be written as PDF/A-2b. Ssrs2.License.TryRead reads a licence key without activating it; a perpetual key renders every version released until its updates date. Changed: a color name that is no color's is an error in the definition (rsInvalidColor, as in Report Viewer) and a warning from an expression; it was drawn black without a word. Details: https://ssrs2.net/