-
Notifications
You must be signed in to change notification settings - Fork 204
Advanced Data Sources
This page covers patterns that go beyond the standard file-based workflow: reusing existing database connections, loading RDL from non-file sources, and streaming output to custom targets.
RDLParser takes a plain string — the RDL XML. Anything that produces a string works.
// Fetch the RDL XML from a database
await using var conn = new Microsoft.Data.SqlClient.SqlConnection(connectionString);
await conn.OpenAsync();
await using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT RdlXml FROM ReportTemplates WHERE Name = @name";
cmd.Parameters.AddWithValue("@name", "SalesReport");
var rdlXml = (string)await cmd.ExecuteScalarAsync();
// Parse and render as normal
var rdlp = new RDLParser(rdlXml) { Folder = @"C:\reports" };
using var report = await rdlp.Parse();// report.rdl is an embedded resource in the assembly
var assembly = typeof(MyApp).Assembly;
using var stream = assembly.GetManifestResourceStream("MyApp.Reports.SalesReport.rdl")!;
using var reader = new StreamReader(stream);
var rdlXml = await reader.ReadToEndAsync();
var rdlp = new RDLParser(rdlXml);
using var report = await rdlp.Parse();When using Programmatic Report Creation, Create.GenerateRdl returns a Report object directly — there is no intermediate file. For other programmatic cases:
string rdlXml = BuildReportDefinition(); // your RDL-generating method
var rdlp = new RDLParser(rdlXml);
using var report = await rdlp.Parse();By default the engine opens its own connection using the connection string embedded in the RDL. To reuse an existing IDbConnection — for transaction support, connection pooling, or multi-tenant isolation — assign it to DataSource.UserConnection before calling RunGetData:
using Majorsilence.Reporting.Rdl;
RdlEngineConfig.RdlEngineConfigInit();
var rdlp = new RDLParser(await File.ReadAllTextAsync("report.rdl"));
using var report = await rdlp.Parse();
// Supply your own open connection
using var conn = new Microsoft.Data.SqlClient.SqlConnection(tenantConnectionString);
await conn.OpenAsync();
report.DataSources["DataSourceName"].UserConnection = conn;
await report.RunGetData(null);The DataSource name must match the one defined in the report. Use the designer's Data → Data Sources menu to find it.
Use cases:
- Multi-tenant apps where the connection string is determined at request time
- Sharing a connection or transaction across multiple reports
- Avoiding repeated authentication round-trips when generating multiple reports in a batch
OneFileStreamGen and MemoryStreamGen both implement IStreamGen. You can implement the interface to stream rendered output to any target without touching the disk.
public interface IStreamGen
{
Stream GetStream();
TextWriter GetTextWriter();
Stream GetIOStream(out string relativeName, string extension);
void CloseMainStream();
}public sealed class AzureBlobStreamGen : IStreamGen, IDisposable
{
private readonly MemoryStream _buffer = new();
private readonly BlobClient _blob;
public AzureBlobStreamGen(BlobClient blob) => _blob = blob;
public Stream GetStream() => _buffer;
public TextWriter GetTextWriter() => new StreamWriter(_buffer);
public Stream GetIOStream(out string relativeName, string extension)
{
relativeName = $"resource{extension}";
return _buffer;
}
public void CloseMainStream() { }
public async Task CommitAsync()
{
_buffer.Position = 0;
await _blob.UploadAsync(_buffer, overwrite: true);
}
public void Dispose() => _buffer.Dispose();
}
// Usage
var blobClient = containerClient.GetBlobClient("reports/sales-2024.pdf");
await using var sg = new AzureBlobStreamGen(blobClient);
await report.RunRender(sg, OutputPresentationType.PDF);
await sg.CommitAsync();Response.ContentType = "application/pdf";
Response.Headers["Content-Disposition"] = "attachment; filename=report.pdf";
// Use MemoryStreamGen, then copy — do not write directly to Response.Body
// while the report is still rendering, as RunRender may seek the stream.
using var ms = new MemoryStreamGen();
await report.RunRender(ms, OutputPresentationType.PDF);
var buffer = ((MemoryStream)ms.GetStream()).ToArray();
await Response.Body.WriteAsync(buffer);See Streaming PDF — ASP.NET Core for the full controller pattern.
string[] providers = RdlEngineConfig.GetProviders();
// e.g. ["Microsoft.Data.SqlClient", "PostgreSQL", "MySQL.NET", "Json", ...]Useful for building dynamic connection dialogs or validating configuration at startup.
Custom report items (barcodes, charts, QR codes) are normally declared in RdlEngineConfig.xml. You can also register them in code:
RdlEngineConfig.DeclareNewCustomReportItem("MyCustomChart", typeof(MyCustomChartRenderer));MyCustomChartRenderer must implement ICustomReportItem. This is useful for plugins and assemblies loaded at runtime.