Data Providers

Data providers connect ScreamCode.Reporting to your application data.

Interface

public interface IReportDataProvider
{
    string EntityName { get; }
    string DisplayName { get; }
    IReadOnlyList<ReportColumnDefinition> AvailableColumns { get; }
    IReadOnlyList<ReportFilterDefinition> AvailableFilters { get; }
    Task<ReportTable> GetDataAsync(ReportBuilderRequest request, CancellationToken ct = default);
    Task<int> GetCountAsync(ReportBuilderRequest request, CancellationToken ct = default);
}

Column types

TypeDescription
stringText
intInteger number
decimalDecimal number
datetimeDate and time
boolTrue/False
currencyFormatted currency

Filter types

TypeDescription
stringText contains filter
daterangeFrom/To date filter
boolTrue/False toggle
selectDropdown with predefined options

Complete example

public class InvoicesDataProvider : IReportDataProvider
{
    private readonly AppDbContext _db;
    public InvoicesDataProvider(AppDbContext db) => _db = db;

    public string EntityName => "invoices";
    public string DisplayName => "Invoices";

    public IReadOnlyList<ReportColumnDefinition> AvailableColumns =>
    [
        new() { Name = "InvoiceNumber", DisplayName = "Invoice #", Type = "string" },
        new() { Name = "CustomerName", DisplayName = "Customer", Type = "string" },
        new() { Name = "Amount", DisplayName = "Amount", Type = "currency" },
        new() { Name = "Status", DisplayName = "Status", Type = "string" },
        new() { Name = "IssuedAt", DisplayName = "Issued Date", Type = "datetime" },
        new() { Name = "IsPaid", DisplayName = "Paid", Type = "bool" }
    ];

    public IReadOnlyList<ReportFilterDefinition> AvailableFilters =>
    [
        new() { Name = "IssuedAt", DisplayName = "Issue Date", Type = "daterange" },
        new() { Name = "CustomerName", DisplayName = "Customer", Type = "string" },
        new() { Name = "Status", DisplayName = "Status", Type = "select",
                Options = ["Draft", "Sent", "Paid", "Overdue"] },
        new() { Name = "IsPaid", DisplayName = "Paid Only", Type = "bool" }
    ];

    public async Task<ReportTable> GetDataAsync(ReportBuilderRequest request, CancellationToken ct = default)
    {
        var query = _db.Invoices.AsQueryable();

        if (request.Filters?.TryGetValue("IssuedAt_from", out var from) == true
            && DateTime.TryParse(from, out var fromDate))
            query = query.Where(i => i.IssuedAt >= fromDate);

        if (request.Filters?.TryGetValue("CustomerName", out var customer) == true
            && !string.IsNullOrEmpty(customer))
            query = query.Where(i => i.CustomerName.Contains(customer));

        if (request.PageSize > 0)
            query = query.Skip((request.Page - 1) * request.PageSize).Take(request.PageSize);

        var data = await query.Select(i => new Dictionary<string, object?>
        {
            ["InvoiceNumber"] = i.InvoiceNumber,
            ["CustomerName"] = i.CustomerName,
            ["Amount"] = i.Amount,
            ["Status"] = i.Status,
            ["IssuedAt"] = i.IssuedAt,
            ["IsPaid"] = i.IsPaid
        }).ToListAsync(ct);

        return new ReportTable { Columns = AvailableColumns.ToList(), Rows = data };
    }

    public async Task<int> GetCountAsync(ReportBuilderRequest request, CancellationToken ct = default)
        => await _db.Invoices.CountAsync(ct);
}

Registering providers

builder.Services
    .AddScreamReporting(builder.Configuration)
    .AddDataProvider<InvoicesDataProvider>()
    .AddDataProvider<OrdersDataProvider>()
    .AddDataProvider<CustomersDataProvider>();

Next: Modules