How to Create Excel File in C# Using Dataset

Cody Schneider••7 min read

Exporting data from your application into an Excel spreadsheet is a common requirement for giving users a way to analyze, report on, or simply store information. This article walks you through exactly how to create an Excel file in C# using a DataSet, a convenient way to handle structured, in-memory data. We'll use a popular library that simplifies the process, so you can skip the complex parts and get straight to a working solution.

GraphedGraphed

Build AI Agents for Marketing

Build virtual employees that run your go to market. Connect your data sources, deploy autonomous agents, and grow your company.

Watch Graphed demo video

Setting Up Your C# Excel Project

Before you can write any code, you need a way to create and manipulate Excel files without relying on having Microsoft Office installed on the server where your code runs. While there are a few options, the easiest approach is to use a third-party library designed for this purpose.

Choose the Right Tool for the Job

There are three main paths for creating Excel files programmatically in C#:

  • Microsoft.Office.Interop.Excel: This is the Microsoft-provided library that directly automates the Excel application.
  • Open XML SDK: A lower-level library from Microsoft that lets you work directly with the XML structure that makes up modern Excel files (.xlsx).
  • Third-Party Libraries (like ClosedXML): These libraries act as a user-friendly wrapper around the Open XML SDK. They give you the power of Open XML without the complexity.

For this tutorial, we will use ClosedXML. It hits the sweet spot of being powerful, easy to use, and free from external dependencies like a local Office installation.

Installing the ClosedXML Library

The easiest way to add ClosedXML to your project is through the NuGet Package Manager in Visual Studio.

  1. Right-click on your project in the Solution Explorer.
  2. Select "Manage NuGet Packages..."
  3. Click on the "Browse" tab and search for ClosedXML.
  4. Select it from the list and click "Install."

Alternatively, you can install it using the Package Manager Console:

Install-Package ClosedXML

Free PDF · the crash course

AI Agents for Marketing Crash Course

Learn how to deploy AI marketing agents across your go-to-market — the best tools, prompts, and workflows to turn your data into autonomous execution without writing code.

Populating Your DataSet with Sample Data

A DataSet is an in-memory representation of data that can contain one or more tables, each represented by a DataTable. Think of it as a small, disconnected database living in your application's memory. Before we can export anything, we need some data to work with.

For this example, let's create a DataSet that simulates having customer information in one table and their corresponding orders in another. This will also show how to handle exporting multiple tables into separate tabs (worksheets) in a single Excel file.

Here’s a simple C# method to generate our sample data:

using System,
using System.Data,

public DataSet GetSampleDataSet()
{
    // Create a new DataSet
    var dataSet = new DataSet("SampleData"),

    // Create the Customers DataTable
    var customersTable = new DataTable("Customers"),
    customersTable.Columns.Add("CustomerID", typeof(int)),
    customersTable.Columns.Add("CustomerName", typeof(string)),
    customersTable.Columns.Add("Country", typeof(string)),

    // Add some sample customer rows
    customersTable.Rows.Add(1, "Alfreds Futterkiste", "Germany"),
    customersTable.Rows.Add(2, "Ana Trujillo Emparedados y helados", "Mexico"),
    customersTable.Rows.Add(3, "Antonio Moreno Taqueria", "Mexico"),
    customersTable.Rows.Add(4, "Around the Horn", "UK"),

    // Create the Orders DataTable
    var ordersTable = new DataTable("Orders"),
    ordersTable.Columns.Add("OrderID", typeof(int)),
    ordersTable.Columns.Add("CustomerID", typeof(int)), // Foreign key
    ordersTable.Columns.Add("OrderDate", typeof(DateTime)),
    ordersTable.Columns.Add("Freight", typeof(decimal)),

    // Add some sample order rows
    ordersTable.Rows.Add(10248, 4, new DateTime(2023, 7, 4), 32.38),
    ordersTable.Rows.Add(10249, 1, new DateTime(2023, 7, 5), 11.61),
    ordersTable.Rows.Add(10250, 2, new DateTime(2023, 7, 8), 65.83),
    ordersTable.Rows.Add(10251, 3, new DateTime(2023, 7, 8), 41.34),
    ordersTable.Rows.Add(10252, 4, new DateTime(2023, 7, 9), 51.30),

    // Add both tables to the DataSet
    dataSet.Tables.Add(customersTable),
    dataSet.Tables.Add(ordersTable),

    return dataSet,
}

This code block sets up everything we need: a DataSet containing two related tables (Customers and Orders), each with columns and several rows of data.

GraphedGraphed

Build AI Agents for Marketing

Build virtual employees that run your go to market. Connect your data sources, deploy autonomous agents, and grow your company.

Watch Graphed demo video

Writing the DataSet to an Excel File with C#

Now for the main event. With your DataSet ready and ClosedXML installed, the actual export process is remarkably simple. The library handles the complex parts of building the .xlsx file structure for you.

The logic follows these basic steps:

  1. Create a new XLWorkbook object, which represents your Excel file.
  2. Loop through each DataTable in your DataSet.
  3. For each table, add a new worksheet to the workbook. Happily, ClosedXML can do this in one line, automatically creating columns and populating the data from the DataTable.
  4. Save the workbook to a file path on your disk.

Here is what that looks like in code. Imagine this is located in your Main method or another function in your application:

using ClosedXML.Excel,
using System.Data,

// Get the sample data
DataSet myDataSet = GetSampleDataSet(),

// Create a new Excel workbook
using (var workbook = new XLWorkbook())
{
    // Loop through each DataTable in the DataSet
    foreach (DataTable table in myDataSet.Tables)
    {
        // Add a worksheet for each table in the DataSet.
        // The worksheet will be named after the table's `TableName` property.
        workbook.Worksheets.Add(table),
    }
    
    // Define the file path
    string filePath = "C:\\Temp\\MyFirstExport.xlsx",
    
    // Save the workbook
    workbook.SaveAs(filePath),

    Console.WriteLine($"Excel file created at: {filePath}"),
}

That’s it! The real magic is in the workbook.Worksheets.Add(table) line. ClosedXML is smart enough to take a DataTable object, read its TableName property for the sheet name, use the column definitions for headers, and fill the rows with data, all in one simple method call. If you run this code, you'll find an Excel file at C:\Temp\ with two sheets named "Customers" and "Orders," each containing the data we created.

Enhancing Your Excel Export: Styling and Formatting

Just dumping raw data is good, but a little formatting goes a long way toward making your reports professional and readable. ClosedXML provides a straightforward API for applying styles.

Let's update our code to automatically adjust column widths and apply some styling to the header row.

Free PDF · the crash course

AI Agents for Marketing Crash Course

Learn how to deploy AI marketing agents across your go-to-market — the best tools, prompts, and workflows to turn your data into autonomous execution without writing code.

A Complete, Styled Example

This combined example builds on the previous one, adding styles just after a worksheet is created.

using ClosedXML.Excel,
using System.Data,
using System,

// Assume GetSampleDataSet() method exists from the earlier example
DataSet myDataSet = GetSampleDataSet(),

// Create a new Excel workbook
using (var workbook = new XLWorkbook())
{
    // Loop through each DataTable
    foreach (DataTable table in myDataSet.Tables)
    {
        // Add a new worksheet to the workbook
        var worksheet = workbook.Worksheets.Add(table),

        // --- STYLING ---

        // 1. Auto-adjust column widths for readability
        worksheet.Columns().AdjustToContents(),

        // 2. Style the header row
        var headerRow = worksheet.FirstRow(),
        headerRow.Style.Font.Bold = true,
        headerRow.Style.Fill.BackgroundColor = XLColor.LightGray,
        headerRow.Style.Font.FontColor = XLColor.DarkBlue,
        headerRow.Height = 20,

        // 3. (Optional) Put a freeze pane on the header row
        worksheet.SheetView.FreezeRows(1),

        // 4. (Optional) Example of formatting a specific column as currency
        // This is useful when you know a column's name
        if (table.TableName == "Orders" && worksheet.Column("Freight") != null)
        {
            worksheet.Column("Freight").Style.NumberFormat.Format = "\"$\"#,##0.00",
        }
    }

    // Define the file path
    string filePath = "C:\\Temp\\StyledExport.xlsx",
    
    // Save the workbook
    workbook.SaveAs(filePath),

    Console.WriteLine($"Styled Excel file created at: {filePath}"),
}

When you run this code, your new Excel file will be much more user-friendly:

  • Column widths are perfectly sized to fit the content.
  • Header rows stand out with a bold font, a background color, and a high-contrast font color.
  • If you scroll down, the header row stays visible because it's frozen.
  • The "Freight" column in the "Orders" sheet is now correctly formatted as USD currency.

Final Thoughts

As you can see, creating Excel files from a C# DataSet is straightforward when you use a helpful library like ClosedXML. The process involves preparing your data in one or more DataTables within a DataSet, using the library to create worksheets from those tables, and then adding simple but effective styling to improve readability before saving the final file.

While building custom reports and exports like this is sometimes necessary, we’ve found that most manual reporting is a time sink that keeps teams from focusing on strategy. Rather than writing code to export static files, tools like Graphed let you connect directly to live data sources – like databases, Google Analytics, Shopify, or SaaS platforms – and instantly generate real-time, interactive dashboards. Asking for a new report becomes a simple, natural language question instead of a development ticket, empowering your whole team to get the insights they need in seconds, not days.

Related Articles