Skip to content

GrydReports Module

GrydReports is a comprehensive report generation module for .NET applications. It provides on-demand and scheduled report generation in multiple formats (PDF, Excel, CSV) with pluggable templates, data sources, delivery channels, and multi-tenancy support.

✨ Features

FeatureDescription
📄 Multi-Format OutputGenerate reports in PDF, Excel, CSV, and HTML formats
🧩 Pluggable TemplatesCode-first template definition with type-safe data and parameters
📊 Data SourcesGeneric data sources with streaming support for large datasets
⏱️ Sync & AsyncOn-demand synchronous generation or background async processing
📅 Scheduling (Optional)Cron-based recurring generation via optional GrydReports.Scheduling.GrydJobs integration
📬 DeliveryEmail, webhook, and storage delivery channels
💾 File StorageLocal filesystem with extensible IReportFileStore (S3, Azure Blob)
🏢 Multi-TenancyBuilt-in tenant isolation for templates, executions, and files
🔍 ObservabilityOpenTelemetry metrics and activity tracing
🔐 Per-Template RBACFine-grained permissions for generate, view, download, and schedule
🎣 Lifecycle FiltersChain-of-responsibility hooks at every stage of generation
478 TestsComprehensive test coverage across all layers

📦 Packages

GrydReports follows Clean Architecture with modular packages:

📦 GrydReports
├── GrydReports.Core                  # Domain entities, abstractions, DTOs
├── GrydReports.Application           # CQRS commands, queries, MediatR handlers
├── GrydReports.Infrastructure        # EF Core, file storage, delivery (scheduling bridge included)
├── GrydReports.Scheduling.GrydJobs   # Optional recurring scheduling integration with GrydJobs
├── GrydReports.Infrastructure.QuestPdf   # QuestPDF renderer
├── GrydReports.Infrastructure.ClosedXml  # ClosedXML (Excel) renderer
├── GrydReports.Infrastructure.CsvHelper  # CsvHelper (CSV) renderer
├── GrydReports.API                   # REST controllers (15 endpoints)
└── GrydReports (meta-package)        # All packages combined

🚀 Quick Start

Installation

bash
# Install Reports core stack (without requiring Jobs)
dotnet add package GrydReports
bash
# Core abstractions only
dotnet add package GrydReports.Core

# With specific renderers
dotnet add package GrydReports.Infrastructure.QuestPdf
dotnet add package GrydReports.Infrastructure.ClosedXml
dotnet add package GrydReports.Infrastructure.CsvHelper

# Optional: only if you need recurring schedules with GrydJobs
dotnet add package GrydReports.Scheduling.GrydJobs

Basic Setup

csharp
// Program.cs
var builder = WebApplication.CreateBuilder(args);

// Register all GrydReports services (Application + Infrastructure + API)
builder.Services.AddGrydReports(
    builder.Configuration,
    db => db.UseNpgsql(builder.Configuration.GetConnectionString("GrydReports"))
);

// Optional: enable recurring scheduling via GrydJobs
// builder.Services.AddGrydJobs(...);
// builder.Services.AddGrydReportsScheduling();

// Optional: health checks
builder.Services.AddGrydReportsHealthChecks(builder.Configuration);

var app = builder.Build();

// Apply migrations + middleware
app.UseGrydReports();
await app.ApplyGrydReportsMigrationsAsync();

// Optional when using GrydJobs
// await app.ApplyGrydJobsMigrationsAsync();

app.Run();

Create Your First Report

csharp
// 1. Define the data model
public class SalesData
{
    public string Period { get; set; }
    public List<SaleItem> Items { get; set; }
    public decimal Total { get; set; }
}

// 2. Implement the data source
public class SalesDataSource : IReportDataSource<SalesData, SalesParameters>
{
    private readonly IDbContext _db;

    public SalesDataSource(IDbContext db) => _db = db;

    public async Task<SalesData> FetchDataAsync(
        SalesParameters parameters, CancellationToken ct)
    {
        var items = await _db.Sales
            .Where(s => s.Date >= parameters.FromDate && s.Date <= parameters.ToDate)
            .ToListAsync(ct);

        return new SalesData
        {
            Period = $"{parameters.FromDate:MMM yyyy}",
            Items = items,
            Total = items.Sum(i => i.Amount)
        };
    }
}

// 3. Define the template
public class MonthlySalesTemplate : IReportTemplate<SalesData>
{
    public string TemplateId => "monthly-sales";
    public string DisplayName => "Monthly Sales Report";
    public string? Description => "Summarizes sales by period";
    public IReadOnlyList<ReportFormat> SupportedFormats =>
        [ReportFormat.Pdf, ReportFormat.Excel, ReportFormat.Csv];

    public ReportMetadata GetMetadata(SalesData data) => new()
    {
        Title = $"Sales Report - {data.Period}",
        Author = "Finance Department"
    };
}

See Getting Started for the full walkthrough.

🏗️ Architecture

┌────────────────────────────────────────────────┐
│                GrydReports.API                 │
│     ReportsController  SchedulesController     │
├────────────────────────────────────────────────┤
│             GrydReports.Application            │
│       Commands + Queries (MediatR/CQRS)        │
├────────────────────────────────────────────────┤
│               GrydReports.Core                 │
│  Abstractions │ Entities │ DTOs │ Enums        │
├────────────────────────────────────────────────┤
│           GrydReports.Infrastructure           │
│  EF Core │ FileStore │ Delivery │ Scheduling   │
├──────────┬──────────────┬──────────────────────┤
│ QuestPDF │  ClosedXML   │    CsvHelper         │
│  (PDF)   │   (Excel)    │     (CSV)            │
└──────────┴──────────────┴──────────────────────┘

📋 API Endpoints

MethodEndpointDescription
GET/api/v1/reportsList available report templates
GET/api/v1/reports/historyPaginated execution history
GET/api/v1/reports/{id}Get execution details
POST/api/v1/reports/generateGenerate report synchronously
POST/api/v1/reports/generate-asyncQueue async generation
GET/api/v1/reports/{id}/downloadDownload generated file
DELETE/api/v1/reports/{id}Delete execution & file
GET/api/v1/reports/schedulesList schedules
GET/api/v1/reports/schedules/{id}Get schedule details
POST/api/v1/reports/schedulesCreate recurring schedule
PUT/api/v1/reports/schedules/{id}Update schedule
DELETE/api/v1/reports/schedules/{id}Delete schedule
POST/api/v1/reports/schedules/{id}/triggerTrigger immediate execution
POST/api/v1/reports/schedules/{id}/pausePause schedule
POST/api/v1/reports/schedules/{id}/resumeResume schedule

Released under the MIT License.