Search code examples
c#entity-frameworkasp.net-corerazor-pagesienumerable

How to retain IEnumerable outside of get method


I am trying to export a table to Excel from an ASP.NET Core Razor page. I have created an IEnumerable called Delays and used that to display a table and applied sorting.

Now I want to export that same sorted table to Excel, but that IEnumerable becomes null after exiting the Get() method. How do I retain that sorted and filtered IEnumerable after the Get() method? Or can I create another IEnumerable and copy from one another?

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using SMS_Automation.Data;
using SMS_Automation.Model;
using OfficeOpenXml;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.IO;

namespace SMS_Automation.Pages
{
 
    public class delay_viewModel : PageModel
    {
        private readonly ApplicationDbContex _db;

        public IEnumerable<Delay_Model> Delays { get; set; }

        public delay_viewModel(ApplicationDbContex db)
        {
            _db = db;
        }

        public void OnGet()
        {
            Delays = _db.Delay;
            Delays = Delays.OrderByDescending(s => s.Agency);        
        }

        public async Task<IActionResult> OnPostExportExcelAsync()
        {
            // above code loads the data using LINQ with EF (query of table), you can substitute this with any data source.
            var stream = new MemoryStream();

            using (var package = new ExcelPackage(stream))
            {
                var workSheet = package.Workbook.Worksheets.Add("Sheet1");
                workSheet.Cells.LoadFromCollection(Delays, true);
                workSheet.Column(4).Style.Numberformat.Format = "dd-MM-YYYY hh:mm";
                workSheet.Column(5).Style.Numberformat.Format = "dd-MM-YYYY hh:mm";
                workSheet.Column(10).Style.Numberformat.Format = "dd-MM-YYYY hh:mm";
                workSheet.Cells.AutoFitColumns();

                package.Save();
            }

            stream.Position = 0;

            // I define the name of the file using the current datetime
            string excelName = $"Delays-{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.xlsx";

            // This will be the actual export
            return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", excelName); 
        }
    }
}

I tried to coping one IEnumerable to another but it did not work.


Solution

  • HTTP is stateless. State instantiated in one request is not available in another. That's by design. If you want to work with data in the Post request handler, you need to instantiate it there.

    public async Task<IActionResult> OnPostExportExcelAsync()
    {
        // instantiate Delays here
        Delays = _db.Delay.OrderByDescending(s => s.Agency);
        var stream = new MemoryStream();
        using (var package = new ExcelPackage(stream))
        {
            var workSheet = package.Workbook.Worksheets.Add("Sheet1");
            workSheet.Cells.LoadFromCollection(Delays, true);
            workSheet.Column(4).Style.Numberformat.Format = "dd-MM-YYYY hh:mm";
            workSheet.Column(5).Style.Numberformat.Format = "dd-MM-YYYY hh:mm";
            workSheet.Column(10).Style.Numberformat.Format = "dd-MM-YYYY hh:mm";
            workSheet.Cells.AutoFitColumns();
            package.Save();
        }
    
        stream.Position = 0;   
        string excelName = $"Delays-{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.xlsx";
        return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", excelName); 
    }