我有一个简单的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版本接收人员数据?
答案 0 :(得分:1)
首先要意识到要为两个单独的请求调用这些操作。首先在用户导航到页面时调用,第二个在用户看到页面时调用,填写表单并提交。
接下来是在ASP.NET MVC中你没有状态。您拥有的唯一信息是一个已发布的表单客户端。因此,即使在前一个请求中创建了一些对象,这个对象也与当前请求无关。在您的表单中有两个输入 - 这些是您在请求中获得的部分。
处理此问题的正确方法是您已经实施的方法。也就是说,如果您在请求期间需要进行一些数据库查询 - 通常需要在每次请求时执行此操作。