我们正在尝试为我们的网站创建Excel导入功能,我们提供一些用户可以填写的模板,然后我们过滤掉这些信息并最终将其发布到我们的数据库中。
首先,他们下载模板,填写然后将其上传到页面。然后我们转到控制器并在我们的模型中填写信息(这是有效的),然后我们将它作为格式化表格打印在页面上。然后当他们确认我们显示的表格与他们的Excel文档匹配时,他们点击" ConfirmCustomOrder" - 按钮。
问题: 我们如何从我们在控制器中发布的模型中获取信息?我们希望使用Model.CustomOrderList,就像在模型中一样,以便稍后验证信息并将其发布到我们的数据库中并完成导入。但是当我们按下" ConfirmCustomOrder" - 按钮时,我们得到的是我们的ExcelModel(控制器中的参数)为空。
模型
public class ExcelModel
{
// Custom class with all Custom Order fields.
public IEnumerable<CustomOrderRow> CustomOrderList { get; set; }
// Custom class with all Purchase Order fields.
public IEnumerable<PurchaseOrderRow> PurchaseOrderList { get; set; }
public bool TriggerOnLoad { get; set; }
public string TriggerOnLoadMessage { get; set; }
}
控制器
public class ExcelController : Controller
{
// GET: Excel
public ActionResult Excel()
{
if (Session["myID"] == null)
{
return ExpireSession();
}
var model = new ExcelModel
{
CustomOrderList = null,
PurchaseOrderList = null,
TriggerOnLoad = false,
TriggerOnLoadMessage = string.Empty
};
return View(model);
}
[HttpPost]
public ActionResult Excel(FormCollection formCollection, ExcelModel model)
{
if (Session["myID"] == null)
{
return ExpireSession();
}
if (!ModelState.IsValid)
return View(model);
// If the user confirmed the information displayed.
if (Request.Form.AllKeys.Contains("ConfirmCustomOrder"))
{
return ConfirmExcelDocument(model);
}
// Otherwise assume the user is trying to upload a new file.
model = new ExcelModel
{
CustomOrderList = null,
PurchaseOrderList = null,
TriggerOnLoad = false,
TriggerOnLoadMessage = string.Empty
};
// Read excel file and create the list in the ExcelModel object.
var file = Request?.Files["UploadedFile"];
if (file == null || (file.ContentLength <= 0) || string.IsNullOrEmpty(file.FileName))
return View(model);
using (var package = new ExcelPackage(file.InputStream))
{
var currentSheet = package.Workbook.Worksheets;
var workSheet = currentSheet.First();
switch (workSheet.Cells[1, 1].Value.ToString().Trim())
{
case "Custom Order":
// Custom order
IterateCustomOrder(model, workSheet);
break;
case "Purchase Order":
// Purchase order
IteratePurchaseOrder(model, workSheet);
break;
default:
model.TriggerOnLoadMessage = "Incorrect file format, please use our template.";
model.TriggerOnLoad = true;
model.CustomOrderList = null;
model.PurchaseOrderList = null;
return View(model);
}
}
return View(model);
}
[HttpPost]
public ActionResult ConfirmExcelDocument(ExcelModel model)
{
// Later we want to further validate the information here. Currently we only print the TriggerOnLoadMessage on the screen after the "Confirm"-button is pressed.
model = new ExcelModel
{
TriggerOnLoad = true,
TriggerOnLoadMessage = "YOU PRESSED THE CONFIRM BUTTON!",
PurchaseOrderList = null
};
return View(model);
}
}
查看
@{
if (Model.TriggerOnLoad && Model.CustomOrderList != null)
{
using (Html.BeginForm("Excel", "Excel", FormMethod.Post))
{
<input id="ConfirmCustomOrder" type="submit" class="standardbutton" name="ConfirmCustomOrder" value="Confirm Custom Order" formaction="Excel" />
}
<table id="logtable">
<thead>
<tr>
<th>Order</th>
<th>Customer</th>
<th>Line</th>
<th>Product</th>
<th>Quantity</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.CustomOrderList)
{
<tr>
<td>@Html.DisplayFor(modelItem => item.OrderNr)</td>
<td>@Html.DisplayFor(modelItem => item.Name)</td>
<td>@Html.DisplayFor(modelItem => item.Line)</td>
<td>@Html.DisplayFor(modelItem => item.ItemId)</td>
<td>@Html.DisplayFor(modelItem => item.Quantity)</td>
<td><input type="button" class="standardbutton extra-info-button" name="answer" value="Info" onclick="showDiv(@item.RowNum.ToString())" /></td>
</tr>
<tr>
<td id="@item.RowNum.ToString()" style="display: none;" class="answer_list" colspan="5">
<pre>
<strong>OrderNr:</strong> @item.OrderNr
<strong>Customer:</strong> @item.Customer
<strong>OrderLines:</strong> @item.OrderLines
// ...and a lot more fields in the model.
</pre> <br />
</td>
</tr>
}
</tbody>
</table>
}
修改1。
答案 0 :(得分:1)
你无法发送excel模型信息,因为你的BeginForm只包装了按钮。
无论如何,我认为即使你这样做,也会遇到问题,因为模型绑定器需要一个索引来绑定一个集合。看看这个stackoverflows条目。
MVC post a list of complex objects
答案 1 :(得分:1)
所以我意识到实际上没有好办法做我正在计划的事情。网络上的替代方案是使用隐藏字段或绑定到索引,然后重新构建列表等...两者都很难从我的理解。而且由于它是一张包含50多列的Excel表格,并且有无限行的可能性,因此它似乎不是最佳的。
我最终使用Session(感谢@AbdulG)来存储我的Model.CustomOrderList以获得我正在寻找的结果(在模型的视图中发布之后不必重新构建我的列表)
<强>控制器强>
[HttpPost]
public ActionResult Excel(FormCollection formCollection)
{
if (Session["myID"] == null)
{
return ExpireSession();
}
if (Request.Form.AllKeys.Contains("ConfirmCustomOrder"))
{
return ConfirmExcelDocument();
}
var model = new ExcelModel
{
CustomOrderList = null,
PurchaseOrderList = null,
TriggerOnLoad = false,
TriggerOnLoadMessage = string.Empty
};
if (!ModelState.IsValid)
return View(model);
var file = Request?.Files["UploadedFile"];
if (file == null || (file.ContentLength <= 0) || string.IsNullOrEmpty(file.FileName))
return View(model);
using (var package = new ExcelPackage(file.InputStream))
{
var currentSheet = package.Workbook.Worksheets;
var workSheet = currentSheet.First();
switch (workSheet.Cells[1, 1].Value.ToString().Trim())
{
case "Custom Order":
// Custom order
IterateCustomOrder(model, workSheet);
Session["CustomOrderList"] = model.CustomOrderList;
break;
case "Purchase Order":
// Purchase order
IteratePurchaseOrder(model, workSheet);
Session["PurchaseOrderList"] = model.PurchaseOrderList;
break;
default:
model.TriggerOnLoadMessage = "Incorrect file format, please use our template.";
model.TriggerOnLoad = true;
model.CustomOrderList = null;
model.PurchaseOrderList = null;
return View(model);
}
}
return View(model);
}
[HttpPost]
public ActionResult ConfirmExcelDocument()
{
var model = new ExcelModel
{
TriggerOnLoad = true,
TriggerOnLoadMessage = string.Empty,
PurchaseOrderList = null,
CustomOrderList = null
};
if (Session["CustomOrderList"] == null)
return View(model);
var list = (IEnumerable<CustomOrderRow>)Session["CustomOrderList"];
Session["CustomOrderList"] = null;
// ... Do some validating etc.
return View(model);
}