在.NET开发中,经常需要实现将数据导出到Excel文件的功能。本文将介绍如何使用C#和NPOI库在ASP.NET MVC环境中实现这一功能。
在开始之前,需要了解本文的核心概念:通过引入NPOI库,可以轻松地将数据导出到Excel文件。为了实现这一功能,将创建两个C#文件,并将它们包含在示例项目中。
为了更好地理解实现过程,创建了一个GitHub仓库,其中包含了使用ASP.NET MVC的代码示例。可以通过以下链接访问这个仓库:
使用NPOI DLL来实现Excel导出功能,这是免费的。可以在NPOI的NuGet页面找到更多详细信息。
在开发过程中,经常需要实现将数据导出到Excel的功能。许多人通常会使用StringBuilder,然后将其转换为Excel,或者使用Interop、ITextSharp或NPOI等其他方法来实现。这些方法在各自的上下文中都是正确的,但如果有一种方法可以像传递对象一样简单,就可以得到所需的输出,生活将变得更加轻松。
首先,有一个名为Export()的实用函数,它将C#List对象转换为NPOI对象,然后最终提供HttpResponseMessage类型,这可以在WEB API Action中使用。
为了实现这一点,需要两个文件,可以在本文附加的解决方案中找到它们:
让从第一个文件AbstractDataExport.cs开始。
创建一个新的Excel对象:
_workbook = new XSSFWorkbook();
创建一个新的Excel工作表对象:
_sheet = _workbook.CreateSheet(_sheetName);
调用WriteData() - 稍后解释
最后,创建并返回MemoryStream对象:
using (var memoryStream = new MemoryStream())
创建MemoryStream
在AbstractDataExport.cs中,定义了一个接口IAbstractDataExport,它包含一个Export方法,用于导出数据。还定义了一个抽象类AbstractDataExport,它实现了这个接口。
现在,让继续第二个也是最后一个文件,即AbstractDataExportBridge.cs。以下是WriteData(List exportData)的解释:
将List转换为DataTable,使用Reflection读取属性名称,列标题将来自这里。遍历DataTable以创建Excel行。
在这个过程中,有一些改进的余地,可以根据需要进行必要的更改,例如完全去除DataTable。
以下是AbstractDataExport.cs的代码示例:
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
namespace GenericExcelExport.ExcelExport
{
public interface IAbstractDataExport
{
HttpResponseMessage Export(List exportData, string fileName, string sheetName);
}
public abstract class AbstractDataExport : IAbstractDataExport
{
protected string _sheetName;
protected string _fileName;
protected List _headers;
protected List _type;
protected IWorkbook _workbook;
protected ISheet _sheet;
private const string DefaultSheetName = "Sheet1";
public HttpResponseMessage Export(List exportData, string fileName, string sheetName = DefaultSheetName)
{
_fileName = fileName;
_sheetName = sheetName;
_workbook = new XSSFWorkbook();
_sheet = _workbook.CreateSheet(_sheetName);
var headerStyle = _workbook.CreateCellStyle();
var headerFont = _workbook.CreateFont();
headerFont.IsBold = true;
headerStyle.SetFont(headerFont);
WriteData(exportData);
Header
var header = _sheet.CreateRow(0);
for (var i = 0; i < _headers.Count; i++)
{
var cell = header.CreateCell(i);
cell.SetCellValue(_headers[i]);
cell.CellStyle = headerStyle;
_sheet.AutoSizeColumn(i);
}
using (var memoryStream = new MemoryStream())
{
_workbook.Write(memoryStream);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memoryStream.ToArray())
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"{_fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
};
return response;
}
}
public abstract void WriteData(List exportData);
}
}
以下是AbstractDataExportBridge.cs的代码示例:
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text.RegularExpressions;
namespace GenericExcelExport.ExcelExport
{
public class AbstractDataExportBridge : AbstractDataExport
{
public AbstractDataExportBridge()
{
_headers = new List();
_type = new List();
}
public override void WriteData(List exportData)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
{
var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
_type.Add(type.Name);
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
string name = Regex.Replace(prop.Name, "([A-Z])", "$1").Trim();
_headers.Add(name);
}
foreach (T item in exportData)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
IRow sheetRow = null;
for (int i = 0; i < table.Rows.Count; i++)
{
sheetRow = _sheet.CreateRow(i + 1);
for (int j = 0; j < table.Columns.Count; j++)
{
ICell Row1 = sheetRow.CreateCell(j);
string cellvalue = Convert.ToString(table.Rows[i][j]);
if (string.IsNullOrWhiteSpace(cellvalue))
{
Row1.SetCellValue(string.Empty);
}
else if (_type[j].ToLower() == "string")
{
Row1.SetCellValue(cellvalue);
}
else if (_type[j].ToLower() == "int32")
{
Row1.SetCellValue(Convert.ToInt32(table.Rows[i][j]));
}
else if (_type[j].ToLower() == "double")
{
Row1.SetCellValue(Convert.ToDouble(table.Rows[i][j]));
}
else if (_type[j].ToLower() == "datetime")
{
Row1.SetCellValue(Convert.ToDateTime(table.Rows[i][j]).ToString("dd/MM/yyyy hh:mm:ss"));
}
else
{
Row1.SetCellValue(string.Empty);
}
}
}
}
}
}
当需要为20多个表单提供Excel导出功能时,遇到了这个解决方案,不愿意使用传统的方法,因为这将非常耗时。
在所有事物中,总有改进的余地。如果看到任何改进的地方,请在评论中更新。