ASP.NET MVC 4中的扩展方法HttpPost ActionResult

时间:2014-02-10 16:46:25

标签: c# asp.net asp.net-mvc asp.net-mvc-4

我有一个简单的HomeController,其中包含一个重载(GET / POST)索引方法,该方法显示HTML表格中Person个对象列表中的数据,并为用户提供一个表单可以键入工作表名称和文件名,并下载结果的Excel文件(EPPlus Excel library)并下载它们。要封装保存Excel文件所需的信息,我创建了以下视图模型:

public class ExcelDownloadView
    {
        public List<Person> Persons { get; set; }
        //ConvertToDataTable is a List extension method return converts the list and its properties
        //into a table where columns are the properties
        public DataTable DataTable { get { return Persons.ConvertToDataTable(); } }
        public string SheetName { get; set; }
        public string FileName { get; set; }
    }

以下是我的观点,在最初的GET请求中,一切都很顺利:

@model ExportToExcel.Models.ExcelDownloadView
@using ExportToExcel.Helpers
@{
    ViewBag.Title = "Index";

}
<div id="grid">
@Html.ListToTable(Model.Persons)

</div>
<div>
This is the number of rows: @Model.DataTable.Rows.Count (correct)
</div>


    @using (Html.BeginForm())
    {
        <input name="sheetName" type="text" /><br />
        <input name="fileName" type="text" /><br />
        <input type="submit" value="Click to download Excel file..." />
    }

当我尝试提交表单时,我的ConvertToDataTable方法出错:

 public static DataTable ConvertToDataTable<T>(this List<T> data)
        {
            DataTable dt = new DataTable();
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
            for (int i = 0; i < props.Count; i++)
            {
                PropertyDescriptor prop = props[i];
                dt.Columns.Add(prop.Name, prop.PropertyType);
            }
            object[] values = new object[props.Count];
            //*****error is at the start of the foreach loop
            foreach (T item in data)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = props[i].GetValue(item);
                }
                dt.Rows.Add(values);
            }
            return dt;
        }

控制器:

[HttpGet]
        public ActionResult Index()
        {
            ExcelDownloadView model = new ExcelDownloadView();
            model.Persons = Person.GetPersons().ToList();
            var dataTable = model.Persons.ConvertToDataTable();
            return View(model);
        }
        [HttpPost]
        public ActionResult Index(ExcelDownloadView viewModel)
        {
            //DataTable property takes the List<Person> of the view model and turns it into 
            //a datable for use in the following Excel-file-creating function

            /*--> if nonWorkingVersion is commented out, the program programs with a NullReferenceException*/
            //DataTable nonWorkingVersion = viewModel.DataTable;
            //if a re-seed the DataTable, everything works fine
            DataTable dt = Person.GetPersons().ToList().ConvertToDataTable();

            using (ExcelPackage pck = new ExcelPackage())
            {
                //Create the worksheet
                ExcelWorksheet ws = pck.Workbook.Worksheets.Add(viewModel.SheetName);

                //Load the datatable into the sheet, starting from cell A1. Print the column names on row 1

                ws.Cells["A1"].LoadFromDataTable(dt, true);
                //Format the header for column 1-3
                using (ExcelRange rng = ws.Cells["A1:C1"])
                {
                    rng.Style.Font.Bold = true;
                    rng.Style.Fill.PatternType = ExcelFillStyle.Solid;                      //Set Pattern for the background to Solid
                    rng.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(79, 129, 189));  //Set color to dark blue
                    rng.Style.Font.Color.SetColor(Color.White);
                }

                //Example how to Format Column 1 as numeric 
                using (ExcelRange col = ws.Cells[2, 1, 2 + dt.Rows.Count, 1])
                {
                    col.Style.Numberformat.Format = "#,##0.00";
                    col.Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
                }

                //Write it back to the client

                Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                Response.AddHeader("content-disposition", "attachment;  filename=" + viewModel.FileName);
                Response.BinaryWrite(pck.GetAsByteArray());
            }
            return View(viewModel);
        }

在Index方法的GET版本中,数据是正确的。为什么数据在我的POST版本中没有正确显示?如果我修改视图并删除对Persons属性的引用,将弹出一个diaglog框,我可以下载我想要的文件。为什么POST版本没有从GET版本接收人员数据?

1 个答案:

答案 0 :(得分:1)

首先要意识到要为两个单独的请求调用这些操作。首先在用户导航到页面时调用,第二个在用户看到页面时调用,填写表单并提交。

接下来是在ASP.NET MVC中你没有状态。您拥有的唯一信息是一个已发布的表单客户端。因此,即使在前一个请求中创建了一些对象,这个对象也与当前请求无关。在您的表单中有两个输入 - 这些是您在请求中获得的部分。

处理此问题的正确方法是您已经实施的方法。也就是说,如果您在请求期间需要进行一些数据库查询 - 通常需要在每次请求时执行此操作。