We are using NPOI library here, which will help to perform import and export operations. In order to see how to create a .NET Core Web Application with Razor Pages and retrieve data from SQL Server using Entity Framework, you can visit my previous article.
Below are the software/concepts used in this document.
- Visual Studio 2019
- NPOI Library
- NuGet Packages
- Razor Pages
- .NET Core 2.0
- .NETCore Web Application
- C# Language
Brief description of NPOI
NPOI is an open source project which can help you read/write XLS, DOC, PPT file extensions. This tool is the .NET version of POI Java project (http://poi.apache.org/). It covers most of the features of Excel like styling, formatting, data formulas, extract images, etc. The good thing is that it does not require Microsoft Office on the server. For example, you can use it to -
- Generate an Excel report without Microsoft Office suite installed on your Server, which is more efficient than calling Microsoft Excel ActiveX in the background.
- Extract text from Office documents to help you implement full-text indexing feature (most of the times, this feature is used to create search engines).
- Extract images from Office documents.
- Generate Excel sheets which contain formulas.
How Razor Pages handle incoming HTTP Requests
Razor pages use handler methods to deal with the incoming HTTP request (GET/POST/PUT/Delete). They are prefixed with “On” and the name of HTTP verbs like -
- OnGet
- OnPost
- OnPut
- OnGetAsync
- OnPostAsync
- OnPutAsync
Besides these default handlers, we can also specify custom names. The custom name must come after the followed naming convention like, for example -
- OnGetCountries()
- OnPostUserMaster()
- OnPostUserDetails()
We will be using custom names for our Import and Export handler methods.
Open your project in Visual Studio 2019
In my case, I am opening the earlier created project where Razor pages are present.

Add NuGet Packages to the above-created project
In the Visual Studio menu, browse to Tools >> NuGet Package Manager >> Package Manager Console.

Then, execute the following command to install the NPOI.
Export to Excel by creating Excel (.xlsx/.xls) with dummy data
Open the Index page (Razor page) where the data is present. In my example, I am opening Index.cshtml under “Customers” folder where my customer data is displayed.
- <form method="post" enctype="multipart/form-data">
- <div class="row">
- <div class="col-md-8" style="padding-top:10px;">
- <button asp-page-handler="ExporttoExcel">Export to Excel</button>
- </div>
- </div>
- <div id="divData"></div>
- </form>
- private IHostingEnvironment _hostingEnvironment;
- public IndexModel(IHostingEnvironment hostingEnvironment)
- {
- _hostingEnvironment = hostingEnvironment;
- }
- public async Task<IActionResult> OnPostExporttoExcel()
- {
- string webRootPath = _hostingEnvironment.WebRootPath;
- string fileName = @"Testingdummy.xlsx";
- string URL = string.Format("{0}://{1}/{2}", Request.Scheme, Request.Host, fileName);
- FileInfo file = new FileInfo(Path.Combine(webRootPath, fileName));
- var memoryStream = new MemoryStream();
- // --- Below code would create excel file with dummy data----
- using (var fs = new FileStream(Path.Combine(webRootPath, fileName), FileMode.Create, FileAccess.Write))
- {
- IWorkbook workbook = new XSSFWorkbook();
- ISheet excelSheet = workbook.CreateSheet("Testingdummy");
- IRow row = excelSheet.CreateRow(0);
- row.CreateCell(0).SetCellValue("ID");
- row.CreateCell(1).SetCellValue("Name");
- row = excelSheet.CreateRow(1);
- row.CreateCell(0).SetCellValue(1);
- row.CreateCell(1).SetCellValue("Mike");
- row = excelSheet.CreateRow(2);
- row.CreateCell(0).SetCellValue(2);
- row.CreateCell(1).SetCellValue("James");
- workbook.Write(fs);
- }
- using (var fileStream = new FileStream(Path.Combine(webRootPath, fileName), FileMode.Open))
- {
- await fileStream.CopyToAsync(memoryStream);
- }
- memoryStream.Position = 0;
- return File(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
- }

Export to Excel by taking data from the screen
Open the Index page (Razor page) where the data is present. In my example, I am opening Index.cshtml under “Customers” folder where my customer data is displayed.
- Repeat the two steps from above (where we put Form and IHostingEnvironment code on the index.cshtml and index.cshtml.cs pages).
- My data already gets loaded on the page and the same data I want to export to the Excel.

- The NPOI package supports both “xls” and “xlsx” extensions using HSSFWorkbook and XSSFWorkbook classes. In my example, I would be using XSSFWorkbook class, as I will work with .xlsx file. In Index.cshtml.cs file, put the following code. Also, since I have 4 columns of data to be exported to Excel, in my example, I will have 4 columns.
- public async Task<IActionResult> OnPostExporttoExcel()
- {
- string webRootPath = _hostingEnvironment.WebRootPath;
- string fileName = @"Testingdummy.xlsx";
- string URL = string.Format("{0}://{1}/{2}", Request.Scheme, Request.Host, fileName);
- FileInfo file = new FileInfo(Path.Combine(webRootPath, fileName));
- var memoryStream = new MemoryStream();
- // --- Below code would create excel file with dummy data----
- using (var fs = new FileStream(Path.Combine(webRootPath, fileName), FileMode.Create, FileAccess.Write))
- {
- IWorkbook workbook = new XSSFWorkbook();
- ISheet excelSheet = workbook.CreateSheet("Testingdummy");
- IRow row = excelSheet.CreateRow(0);
- row.CreateCell(0).SetCellValue("CustomerId");
- row.CreateCell(1).SetCellValue("FirstName");
- row.CreateCell(2).SetCellValue("LastName");
- row.CreateCell(3).SetCellValue("Email");
- cust = from s in _context.Customers select s;
- int counter = 1;
- foreach(var customer in cust)
- {
- string FirstName = string.Empty;
- if (customer.FirstName.Length > 100)
- FirstName = customer.FirstName.Substring(0, 100);
- else
- FirstName = customer.FirstName;
- row = excelSheet.CreateRow(counter);
- row.CreateCell(0).SetCellValue(customer.CustomerId);
- row.CreateCell(1).SetCellValue(FirstName);
- row.CreateCell(2).SetCellValue(customer.LastName);
- row.CreateCell(3).SetCellValue(customer.Email);
- counter++;
- }
- workbook.Write(fs);
- }
- using (var fileStream = new FileStream(Path.Combine(webRootPath, fileName), FileMode.Open))
- {
- await fileStream.CopyToAsync(memoryStream);
- }
- memoryStream.Position = 0;
- return File(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
- }
- Test the files by right-clicking on the Index file and opening it with browser. Then, click on the “Export to Excel” button. The “Testingdummy.xlsx” file is downloaded.

Import data from Excel (.xls or .xlsx) and display it on the screen
I would read the data from Excel and perform the client-side validation for file selection and extension checking. Once the request is successful, it appends the server response to the HTML and displays it on the screen in tabular format.
- Create a dummy Excel with the name “Testingdummy.xlsx”. In my example, I have four columns “CustomerID”, “FirstName”, “LastName” and “Email”.

- Open the Index page (Razor page) where the data is present. In my example, I am opening Index.cshtml under “Customers” folder where my customer data is displayed.
- Put the below code inside the Index.cshtml page.
- <form method="post" enctype="multipart/form-data">
- @* New code to add file Upload and button for importing the data from excel *@
- <div class="row">
- <div class="col-md-4">
- <input type="file" id="fileUpload" name=" fileUpload" class="form-control" />
- </div>
- <div class="col-md-8">
- <input type="button" id="btnUpload" value="Upload File" />
- </div>
- </div>
- @*--- Existing code for exporting data to excel----*@
- <div class="row">
- <div class="col-md-8" style="padding-top:10px;">
- <button asp-page-handler="ExporttoExcel">Export to Excel</button>
- </div>
- </div>
- <div id="divData"></div>
- </form>
- $(document).ready(function () {
- $('#btnUpload').on('click', function () {
- var fileExtension = ['xls', 'xlsx'];
- var filename = $('#fileUpload’).val();
- //--- Validation for excel file---
- if (filename.length == 0) {
- alert("Please select a file.");
- return false;
- }
- else {
- var extension = filename.replace(/^.*\./, '');
- if ($.inArray(extension, fileExtension) == -1) {
- alert("Please select only excel files.");
- return false;
- }
- }
- var filedata = new FormData();
- var fileUpload = $("#fileUpload").get(0);
- var files = fileUpload.files;
- filedata.append(files[0].name, files[0]);
- $.ajax({
- type: "POST",
- url: "/Index?handler=ImportFromExcel",
- beforeSend: function (xhr) {
- xhr.setRequestHeader("XSRF-TOKEN",
- $('input:hidden[name="__RequestVerificationToken"]').val());
- },
- data: filedata,
- contentType: false,
- processData: false,
- success: function (response) {
- if (response.length == 0)
- alert(Error occurred while uploading the excel file');
- else {
- $('#divData').html(response);
- }
- },
- error: function (e) {
- $('#divData').html(e.responseText);
- }
- });
- })
- });
- public ActionResult OnPostImportFromExcel()
- {
- IFormFile file = Request.Form.Files[0];
- string folderName = "Upload";
- string webRootPath = _hostingEnvironment.WebRootPath;
- string newPath = Path.Combine(webRootPath, folderName);
- StringBuilder sb = new StringBuilder();
- if (!Directory.Exists(newPath))
- Directory.CreateDirectory(newPath);
- if (file.Length > 0)
- {
- string sFileExtension = Path.GetExtension(file.FileName).ToLower();
- ISheet sheet;
- string fullPath = Path.Combine(newPath, file.FileName);
- using (var stream = new FileStream(fullPath, FileMode.Create))
- {
- file.CopyTo(stream);
- stream.Position = 0;
- if (sFileExtension == ".xls")//This will read the Excel 97-2000 formats
- {
- HSSFWorkbook hssfwb = new HSSFWorkbook(stream);
- sheet = hssfwb.GetSheetAt(0);
- }
- else //This will read 2007 Excel format
- {
- XSSFWorkbook hssfwb = new XSSFWorkbook(stream);
- sheet = hssfwb.GetSheetAt(0);
- }
- IRow headerRow = sheet.GetRow(0);
- int cellCount = headerRow.LastCellNum;
- // Start creating the html which would be displayed in tabular format on the screen
- sb.Append("<table class='table'><tr>");
- for (int j = 0; j < cellCount; j++)
- {
- NPOI.SS.UserModel.ICell cell = headerRow.GetCell(j);
- if (cell == null || string.IsNullOrWhiteSpace(cell.ToString())) continue;
- sb.Append("<th>" + cell.ToString() + "</th>");
- }
- sb.Append("</tr>");
- sb.AppendLine("<tr>");
- for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
- {
- IRow row = sheet.GetRow(i);
- if (row == null) continue;
- if (row.Cells.All(d => d.CellType == CellType.Blank)) continue;
- for (int j = row.FirstCellNum; j < cellCount; j++)
- {
- if (row.GetCell(j) != null)
- sb.Append("<td>" + row.GetCell(j).ToString() + "</td>");
- }
- sb.AppendLine("</tr>");
- }
- sb.Append("</table>");
- }
- }
- return this.Content(sb.ToString());
- }

That is it. I hope you have learned something new from this article and will utilize this in your work.

Greg HowleyPosted Jul 26, 2022, 5:14 PM
It turns out that the issue with File() was due to the fact that I was coding outside the controller. https://stackoverflow.com/questions/35936628/non-invocable-member-file-cannot-be-used-like-a-method-while-generating-report
Greg HowleyPosted Jul 26, 2022, 3:12 PM
Hi - first off, thanks for putting up this useful content. I'm about to complain about it not working, but in the end, this is all helpful and I don't want to come across as one of the internet's ubiquitous trolls. :-)So firstly, in your #3, I'm seeing you create a filestream fs and then never use it. You then create a second filestream named filestream and copy it to the returned memorystream without using fs or workbook. Is this correct? Secondly, I'm trying to use "return File(...)" and I'm seeing CS1955: Non-invocable member 'File' cannot be used like a method. I'm on VS2022, .NET 6.0 and not sure what I'm doing wrong.
Hemant SharmaPosted May 15, 2019, 7:36 AM
Please suggest the coding to get the activeCell no. from Excel (.xls) with NPOI DLL in C#.