I'm attempting to add an Export() functionality to my MVC5 Code-First application using the EPPlus library. On my View I have a MultiSelectList with all the values for my main Model properties:
@Html.ListBox("PropertyList", typeof(InventoryTracker.Models.INV_Assets).GetProperties().Select(p => new SelectListItem { Text = p.Name, Value = p.Name, Selected = false }), new { @Id = "exportListBox" })
This renders the following HTML:
<select Id="exportListBox" id="PropertyList" multiple="multiple" name="PropertyList"><option value="Id">Id</option>
<option value="Model_Id">Model_Id</option>
<option value="Model">Model</option>
<option value="Manufacturer_Id">Manufacturer_Id</option>
<option value="Manufacturer">Manufacturer</option>
<option value="Type_Id">Type_Id</option>
<option value="Type">Type</option>
<option value="Location_Id">Location_Id</option>
<option value="Location">Location</option>
<option value="Vendor_Id">Vendor_Id</option>
<option value="Vendor">Vendor</option>
<option value="Status_Id">Status_Id</option>
<option value="Status">Status</option>
<option value="ip_address">ip_address</option>
<option value="mac_address">mac_address</option>
<option value="note">note</option>
<option value="owner">owner</option>
<option value="cost">cost</option>
<option value="po_number">po_number</option>
<option value="description">description</option>
<option value="invoice_number">invoice_number</option>
<option value="serial_number">serial_number</option>
<option value="asset_tag_number">asset_tag_number</option>
<option value="acquired_date">acquired_date</option>
<option value="disposed_date">disposed_date</option>
<option value="verified_date">verified_date</option>
<option value="created_date">created_date</option>
<option value="created_by">created_by</option>
<option value="modified_date">modified_date</option>
<option value="modified_by">modified_by</option>
</select>
This is the setup for my [Export] button (hyperlink):
@*<a href="/Export/ExportUsingEPPlus" class="btn btn-default btn-sm noDecoration exportBtn"><span class="glyphicon glyphicon-export"> Export - EPPlus</span></a>*@
<a href="#" class="btn btn-default btn-sm noDecoration exportBtn"><span class="glyphicon glyphicon-export"> Export - EPPlus</span></a>
What I can't figure out now is how to get all of the selected values in the MultiSelectList and pass them to my Controller to dictate what fields should be exported to Excel.
@section Scripts {
<script type="text/javascript">
$(document).ready(function () {
$("a.exportBtn").on("click", function (e) {
e.preventDefault();
alert("Export button clicked!");
exportSelectedAssets();
});
function exportSelectedAssets() {
}
});
</script>
}
This is what I have so far in my Controller using the EPPlus library. Currently it simply creates an .xlsx with one value in the [A1] cell. Once I pass the values from MultiSelectList into this controller, I want to loop through each value of the selected fields in my Table and output them:
public ActionResult ExportUsingEPPlus()
{
//FileInfo newExcelFile = new FileInfo(output);
ExcelPackage package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add("TestExport");
ws.Cells["A1"].Value = "Sample Export 1";
var memoryStream = new MemoryStream();
package.SaveAs(memoryStream);
string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
memoryStream.Position = 0;
return File(memoryStream, contentType, fileName);
}
I was considering JSON for posting all selected values to my Controller, but I'm not sure if this is the best route for this situation? Can someone with more experience weigh in on this?
EDIT:
Attempting Dawood's suggestion, I created a ViewModel - ExportAssetsViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace InventoryTracker.Models
{
public class ExportAssetsViewModel
{
public Dictionary<int, string> ListOfExportFields { get; set; }
public int[] SelectedFields { get; set; }
public ExportAssetsViewModel() {
ListOfExportFields = new Dictionary<int, string>() {
{1, "Model"},
{2, "Manufacturer"},
{3, "Type"},
{4, "Location"},
{5, "Vendor"},
{6, "Status"},
{7, "ip_address"},
{8, "mac_address"},
{9, "note"},
{10, "owner"},
{11, "cost"},
{12, "po_number"},
{13, "description"},
{14, "invoice_number"},
{15, "serial_number"},
{16, "asset_tag_number"},
{17, "acquired_date"},
{18, "disposed_date"},
{19, "verified_date"},
{20, "created_date"},
{21, "created_by"},
{22, "modified_date"},
{23, "modified_by"},
};
}
}
}
I then placed my MultiSelectList on my ExportController - Index View within an HTML.BeginForm():
@using (Html.BeginForm())
{
@Html.ListBox("PropertyList", typeof(InventoryTracker.Models.INV_Assets).GetProperties().Select(p => new SelectListItem { Text = p.Name, Value = p.Name, Selected = false }), new { @Id = "exportListBox" })
<input type="submit" value="ExportUsingEPPlus" />
}
and on my ExportUsingEPPlus() Action modified it as demonstrated:
[HttpPost]
public ActionResult ExportUsingEPPlus(ExportAssetsViewModel model)
{
var exportFields = new List<string>();
foreach(var selectedField in model.SelectedFields)
{
exportFields.Add(model.ListOfExportFields.First(s => s.Key == selectedField).Value);
}
//FileInfo newExcelFile = new FileInfo(output);
ExcelPackage package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add("TestExport");
ws.Cells["A1"].Value = "Sample Export 1";
var memoryStream = new MemoryStream();
package.SaveAs(memoryStream);
string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
memoryStream.Position = 0;
return File(memoryStream, contentType, fileName);
}
When I click my form input button however, my break point at the start of ExportUsingEPPlus() Controller Action is not being hit? All that occurs is the page appears to refresh and my selects get cleared out from the MultiSelectList...?
EDIT2:
Changed the @model on my Index View from InventoryTracker.Models.INV_Assets to InventoryTracker.Models.ExportAssetsViewModel, but m.SelectedFields and Model.ListOfExportFields in my ListBoxFor() are getting flagged for the model not containing a definiton for them?
@using GridMvc.Html
@using System.Collections.Generic
@using System.Web.Mvc
@using MvcCheckBoxList.Model
@model InventoryTracker.Models.ExportAssetsViewModel
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Export</h2>
@using (Html.BeginForm("ExportUsingEPPlus", "Export", FormMethod.Post))
{
@Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.LisOfExportFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" })
<input type="submit" value="ExportUsingEPPlus" />
}
EDIT3:
I noticed when hovering over the m => m in my ListBoxFor() that my View seemed to think it was still using the model INV_Assets even though I had redefined my @model as InventoryTracker.Models.ExportAssetsViewModel. I retyped my @model definition and now m simply shows as (parameter) TModel m...?
Since I created the ExportAssetsViewModel after my previous attempts using the ExportController with the idea of passing selected values via JS/AJAX, I thought I would make a new controller based upon ExportAssetsViewModel. Attempting this though led to the following error:

Now @Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.ListOfExportFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" }) flags as: "The type arguments for method 'System.Web.Mvc.Html.SelectExtensions.ListBoxFor<.....> cannot be inferred from the usage. Try specifying the type arguments explicitly."
Can anyone help with this?
EDIT4:
Disregard EDIT3. I wasn't passing ExportAssetsViewModel to the View. Fixed below:
Controller - Index Action:
public ActionResult Index()
{
//var assetList = _db.INV_Assets.ToList();
//return View(assetList);
ExportAssetsViewModel expViewMod = new ExportAssetsViewModel();
return View(expViewMod);
}
Index View:
@using System.Collections.Generic
@using System.Web.Mvc
@model InventoryTracker.Models.ExportAssetsViewModel
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Export</h2>
<p>Please select which Asset fields to Export to Excel:</p>
@using (Html.BeginForm("ExportUsingEPPlus", "Export", FormMethod.Post))
{
@Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.ListOfExportFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" })
<input type="submit" value="ExportUsingEPPlus" />
}