Create Excel (XLSX) or PDF file in ASP.NET Core

With GemBox.Spreadsheet you can build web applications that target ASP.NET Core 2.0 and above by simply installing it with NuGet or adding the following package reference in the project file.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="GemBox.Spreadsheet" Version="*" />

    <!--
      For saving to PDF or image format on Linux, add native assets.
    -->
    <!--<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="*" />-->
    <!--<PackageReference Include="HarfBuzzSharp.NativeAssets.Linux" Version="*" />-->
  </ItemGroup>

</Project>

The following live demos and code examples show how to use GemBox.Spreadsheet to create ASP.NET Core web applications that generate and download Excel and PDF files to your browser.

Create Excel or PDF files in ASP.NET Core MVC

The following example shows how you can create an ASP.NET Core MVC application that:

  1. Exports tabular data from a web form to an Excel workbook.
  2. Creates a file of a specified format like XLSX or PDF.
  3. Downloads the generated file with a FileStreamResult.
@model ReportModel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>GemBox.Spreadsheet in ASP.NET Core MVC application</title>
    <link rel="icon" href="~/favicon.ico" />
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-controller="Home" asp-action="Index">Home</a>
            </div>
        </nav>
    </header>

    <div class="container">
        <main class="pb-3 row">
            <h1 class="display-4 p-3">Report generator [Razor View]</h1>
            <div class="col-lg-6">
                <form asp-action="Download">
                    <table class="table-sm table-bordered">
                        <thead class="text-center">
                            <tr>
                                <th>Id</th>
                                <th>Name</th>
                                <th>Salary [$]</th>
                            </tr>
                        </thead>
                        <tbody>
                            @for (int index = 0; index < Model.Items.Count; index++)
                            {
                                <tr>
                                    <td><input asp-for="Items[index].Id" class="form-control" readonly /></td>
                                    <td><input asp-for="Items[index].Name" class="form-control" /></td>
                                    <td><input asp-for="Items[index].Salary" class="form-control" /></td>
                                </tr>
                            }
                        </tbody>
                    </table>
                    <div class="form-group">
                        Format:
                        <div class="row">
                            @foreach (string format in Model.FormatMappingDictionary.Select(item => item.Key))
                            {
                                <div class="col-3">
                                    <div class="form-check form-check-inline">
                                        <input asp-for="Format" class="form-check-input" type="radio" id="@format" value="@format">
                                        <label for="@format" class="form-check-label">@format</label>
                                    </div>
                                </div>
                            }
                        </div>
                    </div>
                    <div class="form-group"><input type="submit" value="Create" class="btn btn-primary" /></div>
                </form>
            </div>
        </main>
    </div>

    <footer class="footer border-top text-muted">
        <div class="container">&copy; GemBox Ltd. — All rights reserved.</div>
    </footer>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using SpreadsheetCoreMvc.Models;
using GemBox.Spreadsheet;

namespace SpreadsheetCoreMvc.Controllers
{
    public class HomeController : Controller
    {
        static HomeController()
        {
            // If using the Professional version, put your serial key below.
            SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
        }

        public IActionResult Index()
        {
            return View(new ReportModel());
        }

        public FileStreamResult Download(ReportModel model)
        {
            // Create new spreadsheet.
            var workbook = new ExcelFile();
            var worksheet = workbook.Worksheets.Add("Report");

            // Set styles on rows and columns.
            worksheet.Rows[0].Style.HorizontalAlignment = HorizontalAlignmentStyle.Center;
            worksheet.Rows[0].Style.Font.Weight = ExcelFont.BoldWeight;
            worksheet.Columns[0].SetWidth(40, LengthUnit.Pixel);
            worksheet.Columns[1].SetWidth(100, LengthUnit.Pixel);
            worksheet.Columns[2].SetWidth(100, LengthUnit.Pixel);
            worksheet.Columns[2].Style.NumberFormat = @"\$\ #,##0";

            // Create header row.
            worksheet.Cells["A1"].Value = nameof(ReportItemModel.Id);
            worksheet.Cells["B1"].Value = nameof(ReportItemModel.Name);
            worksheet.Cells["C1"].Value = nameof(ReportItemModel.Salary);

            // Create data rows.
            for (int r = 1; r <= model.Items.Count; r++)
            {
                ReportItemModel item = model.Items[r - 1];
                worksheet.Cells[r, 0].Value = item.Id;
                worksheet.Cells[r, 1].Value = item.Name;
                worksheet.Cells[r, 2].Value = item.Salary;
            }

            // Save spreadsheet in specified file format.
            var stream = new MemoryStream();
            workbook.Save(stream, model.Options);

            // Download file.
            return File(stream, model.Options.ContentType, $"OutputFromView.{model.Format.ToLower()}");
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel() { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

namespace SpreadsheetCoreMvc.Models
{
    public class ReportModel
    {
        public IList<ReportItemModel> Items { get; set; } = new List<ReportItemModel>()
        {
            new ReportItemModel() { Id = 100, Name = "John Doe", Salary = 3600 },
            new ReportItemModel() { Id = 101, Name = "Jane Doe", Salary = 7200 },
            new ReportItemModel() { Id = 102, Name = "Fred Nurk", Salary = 2580 },
            new ReportItemModel() { Id = 103, Name = "Hans Meier", Salary = 3200 },
            new ReportItemModel() { Id = 104, Name = "Ivan Horvat", Salary = 4100 },
            new ReportItemModel() { Id = 105, Name = "Jean Dupont", Salary = 6850 },
            new ReportItemModel() { Id = 106, Name = "Mario Rossi", Salary = 4400 }
        };
        public string Format { get; set; } = "XLSX";
        public SaveOptions Options => this.FormatMappingDictionary[this.Format];
        public IDictionary<string, SaveOptions> FormatMappingDictionary => new Dictionary<string, SaveOptions>()
        {
            ["XLSX"] = new XlsxSaveOptions(),
            ["XLS"] = new XlsSaveOptions(),
            ["ODS"] = new OdsSaveOptions(),
            ["CSV"] = new CsvSaveOptions(CsvType.CommaDelimited),
            ["PDF"] = new PdfSaveOptions(),
            ["HTML"] = new HtmlSaveOptions() { EmbedImages = true },
            ["XPS"] = new XpsSaveOptions(), // XPS is supported only on Windows.
            ["BMP"] = new ImageSaveOptions(ImageSaveFormat.Bmp),
            ["PNG"] = new ImageSaveOptions(ImageSaveFormat.Png),
            ["JPG"] = new ImageSaveOptions(ImageSaveFormat.Jpeg),
            ["GIF"] = new ImageSaveOptions(ImageSaveFormat.Gif),
            ["TIF"] = new ImageSaveOptions(ImageSaveFormat.Tiff),
            ["SVG"] = new ImageSaveOptions(ImageSaveFormat.Svg)
        };
    }

    public class ReportItemModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Salary { get; set; }
    }
}
Exporting tabular data from Razor view and generating XLSX file in ASP.NET Core MVC application
Screenshot of submitted web form and created Excel workbook

Create Excel or PDF files in ASP.NET Core Razor Pages

The following example shows how you can create an ASP.NET Core Razor Pages application that:

  1. Exports tabular data from a web form to an Excel workbook.
  2. Creates a file of a specified format like XLSX or PDF.
  3. Downloads the generated file with a FileContentResult.
@page
@model IndexModel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>GemBox.Spreadsheet in ASP.NET Core Razor Pages application</title>
    <link rel="icon" href="~/favicon.ico" />
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-page="/Index">Home</a>
            </div>
        </nav>
    </header>

    <div class="container">
        <main class="pb-3 row">
            <h1 class="display-4 p-3">Report generator [Razor Page]</h1>
            <div class="col-lg-6">
                <form method="post">
                    <table class="table-sm table-bordered">
                        <thead class="text-center">
                            <tr>
                                <th>Id</th>
                                <th>Name</th>
                                <th>Salary [$]</th>
                            </tr>
                        </thead>
                        <tbody>
                            @for (int index = 0; index < Model.Report.Items.Count; index++)
                            {
                                <tr>
                                    <td><input asp-for="Report.Items[index].Id" class="form-control" readonly /></td>
                                    <td><input asp-for="Report.Items[index].Name" class="form-control" /></td>
                                    <td><input asp-for="Report.Items[index].Salary" class="form-control" /></td>
                                </tr>
                            }
                        </tbody>
                    </table>
                    <div class="form-group">
                        Format:
                        <div class="row">
                            @foreach (string format in Model.Report.FormatMappingDictionary.Select(item => item.Key))
                            {
                                <div class="col-3">
                                    <div class="form-check form-check-inline">
                                        <input asp-for="Report.Format" class="form-check-input" type="radio" id="@format" value="@format">
                                        <label for="@format" class="form-check-label">@format</label>
                                    </div>
                                </div>
                            }
                        </div>
                    </div>
                    <div class="form-group"><input type="submit" value="Create" class="btn btn-primary" /></div>
                </form>
            </div>
        </main>
    </div>

    <footer class="footer border-top text-muted">
        <div class="container">&copy; GemBox Ltd. — All rights reserved.</div>
    </footer>
</body>
</html>
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using SpreadsheetCorePages.Models;
using GemBox.Spreadsheet;

namespace SpreadsheetCorePages.Pages
{
    public class IndexModel : PageModel
    {
        [BindProperty]
        public ReportModel Report { get; set; }

        public IndexModel()
        {
            this.Report = new ReportModel();

            // If using the Professional version, put your serial key below.
            SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
        }

        public void OnGet() { }

        public FileContentResult OnPost()
        {
            // Create new spreadsheet.
            var workbook = new ExcelFile();
            var worksheet = workbook.Worksheets.Add("Report");

            // Set styles on rows and columns.
            worksheet.Rows[0].Style.HorizontalAlignment = HorizontalAlignmentStyle.Center;
            worksheet.Rows[0].Style.Font.Weight = ExcelFont.BoldWeight;
            worksheet.Columns[0].SetWidth(40, LengthUnit.Pixel);
            worksheet.Columns[1].SetWidth(100, LengthUnit.Pixel);
            worksheet.Columns[2].SetWidth(100, LengthUnit.Pixel);
            worksheet.Columns[2].Style.NumberFormat = @"\$\ #,##0";

            // Create header row.
            worksheet.Cells["A1"].Value = nameof(ReportItemModel.Id);
            worksheet.Cells["B1"].Value = nameof(ReportItemModel.Name);
            worksheet.Cells["C1"].Value = nameof(ReportItemModel.Salary);

            // Create data rows.
            for (int r = 1; r <= this.Report.Items.Count; r++)
            {
                ReportItemModel item = this.Report.Items[r - 1];
                worksheet.Cells[r, 0].Value = item.Id;
                worksheet.Cells[r, 1].Value = item.Name;
                worksheet.Cells[r, 2].Value = item.Salary;
            }

            // Save spreadsheet in specified file format.
            var stream = new MemoryStream();
            workbook.Save(stream, this.Report.Options);

            // Download file.
            return File(stream.ToArray(), this.Report.Options.ContentType, $"OutputFromPage.{this.Report.Format.ToLower()}");
        }
    }
}

namespace SpreadsheetCorePages.Models
{
    public class ReportModel
    {
        public IList<ReportItemModel> Items { get; set; } = new List<ReportItemModel>()
        {
            new ReportItemModel() { Id = 100, Name = "John Doe", Salary = 3600 },
            new ReportItemModel() { Id = 101, Name = "Jane Doe", Salary = 7200 },
            new ReportItemModel() { Id = 102, Name = "Fred Nurk", Salary = 2580 },
            new ReportItemModel() { Id = 103, Name = "Hans Meier", Salary = 3200 },
            new ReportItemModel() { Id = 104, Name = "Ivan Horvat", Salary = 4100 },
            new ReportItemModel() { Id = 105, Name = "Jean Dupont", Salary = 6850 },
            new ReportItemModel() { Id = 106, Name = "Mario Rossi", Salary = 4400 }
        };
        public string Format { get; set; } = "PDF";
        public SaveOptions Options => this.FormatMappingDictionary[this.Format];
        public IDictionary<string, SaveOptions> FormatMappingDictionary => new Dictionary<string, SaveOptions>()
        {
            ["XLSX"] = new XlsxSaveOptions(),
            ["XLS"] = new XlsSaveOptions(),
            ["ODS"] = new OdsSaveOptions(),
            ["CSV"] = new CsvSaveOptions(CsvType.CommaDelimited),
            ["PDF"] = new PdfSaveOptions(),
            ["HTML"] = new HtmlSaveOptions() { EmbedImages = true },
            ["XPS"] = new XpsSaveOptions(), // XPS is supported only on Windows.
            ["BMP"] = new ImageSaveOptions(ImageSaveFormat.Bmp),
            ["PNG"] = new ImageSaveOptions(ImageSaveFormat.Png),
            ["JPG"] = new ImageSaveOptions(ImageSaveFormat.Jpeg),
            ["GIF"] = new ImageSaveOptions(ImageSaveFormat.Gif),
            ["TIF"] = new ImageSaveOptions(ImageSaveFormat.Tiff),
            ["SVG"] = new ImageSaveOptions(ImageSaveFormat.Svg)
        };
    }

    public class ReportItemModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Salary { get; set; }
    }
}
Exporting tabular data from Razor page and generating PDF file in ASP.NET Core Razor Pages application
Screenshot of submitted web form and created PDF file

Host and deploy ASP.NET Core

When hosting an ASP.NET Core application that uses GemBox.Spreadsheet, specific adjustments are necessary for Windows Server or Linux. Detailed instructions for these adjustments are available on the supported platforms help page.

It is recommended to review the Private Fonts example when deploying an ASP.NET Core application using GemBox.Spreadsheet on Linux to make sure that font styles and formatting are handled correctly.

GemBox.Spreadsheet follows a licensing model per individual developer, which includes royalty-free deployment. You are allowed to build an unlimited number of applications and deploy or distribute them across numerous services, servers, or end-user machines without any additional cost. For more information, read our End User License Agreement (EULA).

See also


Next steps

GemBox.Spreadsheet is a .NET component that enables you to read, write, edit, convert, and print spreadsheet files from your .NET applications using one simple API.

Download Buy