To provide more context, if I simply want to export my model to an Excel file in my ActionResult, I have that worked out. I learned the commends to assign values to the workbook properties and cell formatting and the exported Excel file appears correctly.
My problem is that all that code exists within the ActionResult block. I would like to move out the code that assigns property values to a separate function. The problem I encounter is the null reference error
. Below is the paste of the full ActionResult block to provide full context and in case it suggests any secondary issues I hadn't considered.
I tried creating a function in the controller private ExcelPackage AssignWorkbookProperties(ExcelPackage ep, string exportName)
, and while I had no compile time errors, there was a null argument exception. Essentially, the function either received nothing or returned nothing.
Is there some way I can move the blocked code into a helper function? (I've indicated with comment blocks in the code shown here).
public ActionResult ExportToExcel()
{
string exportName = "FourCourseAudit";
// This allows me to export only the columns I want.
var exportQuery = query.Select(t => new { t.Campus, t.Student_Name, t.Course_Count });
// epp is the model where I gather the predefined property values
var epp = new ExportToExcelProperties();
var prop = epp.WorkbookProperties.Where(t => t.ExportName == exportName);
try
{
byte[] response;
using (var excelFile = new ExcelPackage())
{
// Define worksheet data.
var worksheet = excelFile.Workbook.Worksheets.Add("Sheet1");
/* ------------------------------------------------------------------ */
/* -------------Begin: Move to helper function ---------------------- */
/* ------------------------------------------------------------------ */
// Define workbook properties.
var workbookProperties = excelFile.Workbook.Properties;
workbookProperties.Author = HttpContext.User.Identity.Name;
workbookProperties.Title = prop.Select(t => t.Title).ToString();
workbookProperties.Comments = prop.Select(t => t.Comments).ToString();
workbookProperties.Created = DateTime.Now;
workbookProperties.Category = prop.Select(t => t.Category).ToString();
// Define worksheet contextual data.
worksheet.Cells["A1"].Value = "Title: ";
worksheet.Cells["A2"].Value = "Export Date: ";
worksheet.Cells["A1:A2"].Style.Font.Bold = true;
worksheet.Cells["B1"].Value = prop.Select(t => t.Title).ToString();
worksheet.Cells["B2"].Value = DateTime.Now;
worksheet.Cells["B2"].Style.Numberformat.Format = "mm/dd/yyyy hh:mm";
worksheet.Cells["A1:B2"].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Medium);
worksheet.Cells["A1:B2"].AutoFitColumns();
Color bgColor = ColorTranslator.FromHtml("#2956B2");
worksheet.Cells["A1:B2"].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells["A1:B2"].Style.Fill.BackgroundColor.SetColor(bgColor);
worksheet.Cells["A1:B2"].Style.Font.Color.SetColor(Color.White);
worksheet.Cells["D1:F1"].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells["D1:F1"].Style.Fill.BackgroundColor.SetColor(bgColor);
worksheet.Cells["D1:F1"].Style.Font.Color.SetColor(Color.White);
/* ------------------------------------------------------------------ */
/* ---------------End: Move to helper function ---------------------- */
/* ------------------------------------------------------------------ */
worksheet
.Cells["D1"]
.LoadFromCollection(Collection: exportQuery, PrintHeaders: true)
.Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin);
worksheet.Cells["A1:F200"].AutoFitColumns();
response = excelFile.GetAsByteArray();
}
return File(response, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Export.xlsx");
}
catch (NullReferenceException) {
return ViewBag.Errormsg = "There was a null reference exception.";
}
catch (ArgumentNullException)
{
return ViewBag.Errormsg = "There was an argument null exception.";
}
}
I found a resource that helped me figure out the problem.
The problem was that my function was returning and accepting the wrong object.
I created two different functions. The first function returns type
ExcelWorksheet
and the second function returns typeOfficeProperties
. Both functions haveExcelPackage
as an input parameter.So first, this is how clean the ActionResult is now:
For now, these two functions are in the same controller. The more I work out how to generalize them, I might move them elsewhere.
This directly answers the question of how I can move the worksheet property code outside of the ActionResult, but I can clearly see there can be more done to generalize the code and make it more modular.