RDLC Reports in .NET Core Web API - Complete Guide Report in (PDF, Excel, Word) - IndianTechnoEra
Latest update Android YouTube

RDLC Reports in .NET Core Web API - Complete Guide Report in (PDF, Excel, Word)

This guide provides proper, step-by-step instructions to create a .NET Core Web API project, integrate RDLC reports, and export them as PDF, Excel, and Word files. Follow each step carefully.


Table of Contents


Prerequisites

  • .NET Core SDK 5.0 or later (6.0, 7.0, or 8.0 recommended)
  • Visual Studio 2022 or later (or VS Code with C# extensions)
  • RDLC Report Designer extension for Visual Studio (optional, but helpful for designing reports)
  • Basic knowledge of C# and ASP.NET Core

Step 1: Create the .NET Core Web API Project

Open Visual Studio or your terminal and create a new ASP.NET Core Web API project.

Using Visual Studio:

  1. Go to File → New → Project.
  2. Select "ASP.NET Core Web API" template.
  3. Name the project: RDLCReportAPI.
  4. Choose a location and click Next.
  5. Select framework: .NET 6.0 (or higher).
  6. Uncheck "Use controllers" if you want minimal APIs, but for this guide we'll use controllers. Keep "Enable OpenAPI support" unchecked for simplicity.
  7. Click Create.

Using .NET CLI:

dotnet new webapi -n RDLCReportAPI
cd RDLCReportAPI
    

Step 2: Install Required NuGet Packages

Open the NuGet Package Manager Console or use the CLI to install the following essential packages:

Install-Package AspNetCore.Reporting -Version 1.0.3
Install-Package System.Drawing.Common -Version 7.0.0
Install-Package System.Text.Encoding.CodePages -Version 7.0.0
    

Explanation of packages:

  • AspNetCore.Reporting: Provides RDLC report rendering and export to PDF, Excel, Word.
  • System.Drawing.Common: Required for graphics operations during report rendering.
  • System.Text.Encoding.CodePages: Handles encoding for different report formats.

Note: If you get any compatibility issues, use the latest stable versions.


Step 3: Create the Report Model (DTO)

Create a folder named Models and add a class UserReportDto.cs. This will represent the data for our report.

File Path: RDLCReportAPI/Models/UserReportDto.cs

namespace RDLCReportAPI.Models
{
    public class UserReportDto
    {
        public string FirstName { get; set; } = string.Empty;
        public string LastName { get; set; } = string.Empty;
        public string Email { get; set; } = string.Empty;
        public string Phone { get; set; } = string.Empty;
    }
}
    

Step 4: Design the RDLC Report File

RDLC reports are XML files with a .rdlc extension. You can create them using Visual Studio or a third-party designer. Follow these steps:

  1. Right-click the project → Add → New Folder. Name it Reports.
  2. Right-click the Reports folder → Add → New Item.
  3. Search for "Report" and select "Report (.rdlc)". Name it UserDetails.rdlc.
  4. If the template is missing, you need to install the Microsoft RDLC Report Designer extension from Visual Studio Marketplace.

Designing the Report:

  1. Open UserDetails.rdlc. The designer will appear.
  2. From the Toolbox, drag a Table control onto the report body.
  3. You'll see three rows: Header, Details, Footer.
  4. Now we need to create a DataSet. Right-click on the report surface → Report Data → In the Report Data panel, click New → DataSet.
    • Name: UserDataSet
    • Data source: New → Choose Object → Select UserReportDto from your project.
    • Click OK.
  5. Now drag fields from the Report Data panel (FirstName, LastName, Email, Phone) into the table's detail row (second row).
  6. Customize column headers in the header row (first row).
  7. Adjust widths, fonts, borders as needed.
  8. Save the file.

Important Setup for RDLC file properties:

  • Right-click UserDetails.rdlc → Properties.
  • Set Copy to Output Directory to "Copy if newer" or "Copy always". This ensures the report file is available in the build output.

Step 5: Create the Report Service (Interface & Implementation)

Create a folder Services. Then add an interface and its implementation.

5.1 Create Interface: IReportService.cs

File Path: RDLCReportAPI/Services/IReportService.cs

using System.Threading.Tasks;

namespace RDLCReportAPI.Services
{
    public interface IReportService
    {
        Task<byte[]> GenerateReportAsync(string reportName, string reportType);
    }
}
    

5.2 Create Implementation: ReportService.cs

File Path: RDLCReportAPI/Services/ReportService.cs

using AspNetCore.Reporting;
using RDLCReportAPI.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace RDLCReportAPI.Services
{
    public class ReportService : IReportService
    {
        public ReportService()
        {
            // Register encoding provider to support various encodings
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            // Enable unsafe binary formatter serialization (required for Word export)
            AppContext.SetSwitch("Switch.System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", true);
        }

        public async Task<byte[]> GenerateReportAsync(string reportName, string reportType)
        {
            try
            {
                // 1. Get the path of the RDLC file from the assembly's location
                string assemblyLocation = Assembly.GetExecutingAssembly().Location;
                string assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
                string reportPath = Path.Combine(assemblyDirectory, "Reports", $"{reportName}.rdlc");

                if (!File.Exists(reportPath))
                {
                    throw new FileNotFoundException($"Report file not found: {reportPath}");
                }

                // 2. Prepare data for the report (in real scenario, fetch from database)
                List<UserReportDto> users = GetUserData();

                // 3. Load the RDLC report
                using var report = new LocalReport(reportPath);
                
                // 4. Add data source (must match the DataSet name used in RDLC)
                report.AddDataSource("UserDataSet", users);

                // 5. Determine the render type based on requested format
                RenderType renderType = GetRenderType(reportType);

                // 6. Render the report to byte array
                var result = await report.ExecuteAsync(renderType, 1, null, null);
                
                return result.MainStream;
            }
            catch (Exception ex)
            {
                throw new Exception($"Error generating report: {ex.Message}", ex);
            }
        }

        private List<UserReportDto> GetUserData()
        {
            // Static sample data. Replace with database call in production.
            return new List<UserReportDto>
            {
                new UserReportDto { FirstName = "John", LastName = "Doe", Email = "john.doe@example.com", Phone = "+1-555-123-4567" },
                new UserReportDto { FirstName = "Jane", LastName = "Smith", Email = "jane.smith@example.com", Phone = "+1-555-987-6543" },
                new UserReportDto { FirstName = "Robert", LastName = "Johnson", Email = "robert.j@example.com", Phone = "+1-555-456-7890" },
                new UserReportDto { FirstName = "Emily", LastName = "Davis", Email = "emily.davis@example.com", Phone = "+1-555-321-0987" }
            };
        }

        private RenderType GetRenderType(string reportType)
        {
            return reportType?.ToLower() switch
            {
                "pdf" => RenderType.Pdf,
                "xls" => RenderType.Excel,
                "word" => RenderType.Word,
                _ => RenderType.Pdf
            };
        }
    }
}
    

Step 6: Register the Service in Program.cs

Open Program.cs and add the dependency injection for the report service. Also configure the necessary switches for binary serialization.

File Path: RDLCReportAPI/Program.cs

using RDLCReportAPI.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); // optional

// Register the report service as scoped
builder.Services.AddScoped<IReportService, ReportService>();

// Enable unsafe binary formatter serialization (required for Word reports)
AppContext.SetSwitch("Switch.System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", true);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();
    

Step 7: Create the API Controller

Add a new controller named ReportController.cs inside the Controllers folder.

File Path: RDLCReportAPI/Controllers/ReportController.cs

using Microsoft.AspNetCore.Mvc;
using RDLCReportAPI.Services;
using System.Threading.Tasks;

namespace RDLCReportAPI.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ReportController : ControllerBase
    {
        private readonly IReportService _reportService;

        public ReportController(IReportService reportService)
        {
            _reportService = reportService;
        }

        /// <summary>
        /// Generates and downloads a report in the specified format.
        /// </summary>
        /// <param name="reportName">Name of the report (without extension), e.g., "UserDetails"</param>
        /// <param name="format">Format: pdf, xls, or word</param>
        [HttpGet]
        public async Task<IActionResult> GetReport(string reportName, string format)
        {
            if (string.IsNullOrEmpty(reportName) || string.IsNullOrEmpty(format))
            {
                return BadRequest("Report name and format are required.");
            }

            // Validate format
            string[] allowedFormats = { "pdf", "xls", "word" };
            if (!allowedFormats.Contains(format.ToLower()))
            {
                return BadRequest("Invalid format. Allowed formats: pdf, xls, word.");
            }

            try
            {
                // Generate report as byte array
                byte[] reportBytes = await _reportService.GenerateReportAsync(reportName, format);
                
                // Determine content type and file extension
                string contentType = GetContentType(format);
                string fileExtension = GetFileExtension(format);
                string fileName = $"{reportName}_{System.DateTime.Now:yyyyMMddHHmmss}.{fileExtension}";
                
                // Return the file for download
                return File(reportBytes, contentType, fileName);
            }
            catch (System.Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }

        private string GetContentType(string format)
        {
            return format.ToLower() switch
            {
                "pdf" => "application/pdf",
                "xls" => "application/vnd.ms-excel",
                "word" => "application/msword",
                _ => "application/octet-stream"
            };
        }

        private string GetFileExtension(string format)
        {
            return format.ToLower() switch
            {
                "pdf" => "pdf",
                "xls" => "xls",
                "word" => "doc",
                _ => "dat"
            };
        }
    }
}
    

Step 8: Run and Test the API

Now you can run the application and test the report generation endpoints.

  1. Press F5 or run dotnet run from the terminal.
  2. The API will start, typically at https://localhost:5001 or a similar port.
  3. Open your browser or Postman and test the following URLs:
// For PDF report:
https://localhost:5001/api/report?reportName=UserDetails&format=pdf

// For Excel report:
https://localhost:5001/api/report?reportName=UserDetails&format=xls

// For Word report:
https://localhost:5001/api/report?reportName=UserDetails&format=word
    

The browser should automatically download the file in the requested format. The report will contain the sample user data.


Troubleshooting Common Errors

Error 1: "An error occurred during local report processing"

Cause: Usually due to missing encoding provider or binary formatter serialization not enabled.

Solution: Ensure you have called Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); and set AppContext.SetSwitch("Switch.System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", true); in your service constructor or Program.cs.

Error 2: "Report file not found"

Cause: The RDLC file is not being copied to the output directory.

Solution: Set the RDLC file's "Copy to Output Directory" property to "Copy always" or "Copy if newer". Also verify the file path in the service matches the folder structure.

Error 3: "Data source name not found in the report"

Cause: The DataSet name used in AddDataSource does not match the DataSet name defined in the RDLC file.

Solution: Open the RDLC file, go to Report Data panel, check the DataSet name. In our example it is "UserDataSet". Use exactly the same name in report.AddDataSource("UserDataSet", users);

Error 4: Word export gives "Binary formatter serialization is disabled"

Solution: This is already handled in the ReportService constructor. Make sure the AppContext switch is set before the report execution.

Error 5: System.Drawing.Common is not supported on Linux

Note: If deploying to Linux, you may need to install libgdiplus. Alternatively, consider using a different reporting library for cross-platform compatibility. For Windows deployment, it works fine.


Conclusion

Congratulations! You have successfully created a .NET Core Web API that generates RDLC reports and exports them to PDF, Excel, and Word formats. This guide provided proper step-by-step instructions including:

  • Creating the Web API project.
  • Installing necessary NuGet packages.
  • Creating a DTO model.
  • Designing an RDLC report file.
  • Implementing a report service with rendering logic.
  • Registering the service and creating an API controller.
  • Testing all three export formats.

You can now extend this foundation by connecting to a real database, adding report parameters, customizing the report design with charts and subreports, and securing the API endpoints. This approach saves tremendous development time and provides a robust reporting solution for your applications.

Happy Coding!


Post a Comment

Feel free to ask your query...
Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
Oops!
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.
AdBlock Detected!
We have detected that you are using adblocking plugin in your browser.
The revenue we earn by the advertisements is used to manage this website, we request you to whitelist our website in your adblocking plugin.
Site is Blocked
Sorry! This site is not available in your country.