Custom ActionResult for Files in ASP.NET MVC - ExcelResult

An action result is the standard result from an action. Action results handle the execution of the result requested by an action method. Although standard action results FileContentResult and FileStreamResult may be used for downloading files that are generated on the fly, creating a custom action result might be the best solution.

For situations that are not supported by standard action results, we may create custom action results. For example we may create custom action result for creating PDF, Excel or Word files on the fly for download or generating and returning images. 

Creating a new custom action result requires that our class inherit the abstract class System.Web.Mvc.ActionResult and override the ExecuteResult method.


As an example let's create a custom action result for exporting data to Excel files on the fly for download.


We are using FastMember package for creating DataTable from IEnumerable object and ClosedXML package for creating Excel file from the DataTable.


ExcelResult class inherits abstract ActionResult and overrides the ExecuteResult method.

public class ExcelResult<T> : ActionResult
{
    private DataTable dataTable;
    private string fileName;

    /// <summary>
    /// constructor
    /// </summary>
    /// <param name="data">data object to export</param>
    /// <param name="filename">download filename</param>
    /// <param name="columns">column names to export</param>
    public ExcelResult(IEnumerable<T> data, string filename, string[] columns)
    {
        this.dataTable = new DataTable();
        using (var reader = ObjectReader.Create(data, columns))
        {
            dataTable.Load(reader);
        }
        this.fileName = filename;
    }

    /// <summary>
    /// override the ExceuteResult method for customized action result
    /// </summary>
    /// <param name="context">controller context</param>
    public override void ExecuteResult(ControllerContext context)
    {
        if (context != null)
        {
            var response = context.HttpContext.Response;
            response.Clear();
            response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            response.AddHeader("content-disposition", string.Format(@"attachment;filename=""{0}""", fileName));
            using (XLWorkbook wb = new XLWorkbook())
            {
                wb.Worksheets.Add(dataTable, "Sheet1");
                using (MemoryStream stream = new MemoryStream())
                {
                    wb.SaveAs(stream);
                    response.BinaryWrite(stream.ToArray());
                }
            }
        }
    }
}

In the Controller use the custom ExcelResult action result as follows

[HttpGet]
public async Task<ExcelResult<MyViewModel>> ExportToExcel()
{
    var model = new Models.MyDataModel();
    var items = await model.GetItems();
    string[] columns = new string[] { "Column1", "Column2", "Column3" };
    string filename = string.Format("mydata-{0}.xlsx", DateTime.Now.ToString("yyyyMMddHHmmss"));

    return new ExcelResult<MyViewModel>(items, filename, columns);
}

Since we are downloading the file using HttpGet create an empty View without model and empty layout.

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Export to Excel</title>
</head>
<body>
    <div>
    </div>
</body>
</html>


Example Export to Excel button for firing this custom action result:

@Html.ActionLink("Export to Excel", "ExportToExcel", "MyController", null, new { id = "ExportToExcel", @class = "btn btn-primary", onclick = "return showProgress();" })







Comments

Popular posts from this blog

Filtering html select listbox items

Proper Way of Installing SharePoint Cumulative Updates