本君已成夜貓子,本節咱們來說講ASP.NET Core MVC中的上傳,這兩天在研究批量導入功能,本節順便簡單搞搞導入、導出,等博主弄穩當了再來和你們一併分享。ajax
首先咱們來看看官網的上傳的例子,再而後進行拓展訓練,官網的表單是這樣的。數據庫
<form method="post" enctype="multipart/form-data" asp-controller="UploadFiles" asp-action="Index"> <div class="form-group"> <div class="col-md-10"> <p>Upload one or more files using this form:</p> <input type="file" name="files" multiple /> </div> </div> <div class="form-group"> <div class="col-md-10"> <input type="submit" value="上傳" /> </div> </div> </form>
在ASP.NET Core MVC中接收上傳的文件須要用 IFormFile 來接收,該接口定義以下:app
public interface IFormFile { string ContentType { get; } string ContentDisposition { get; } IHeaderDictionary Headers { get; } long Length { get; } string Name { get; } string FileName { get; } Stream OpenReadStream(); void CopyTo(Stream target); Task CopyToAsync(Stream target, CancellationToken cancellationToken = null); }
後臺控制器關於上傳的Action方法進行以下定義:async
[HttpPost("UploadFiles")] public async Task<IActionResult> Post(List<IFormFile> files) { long size = files.Sum(f => f.Length); // full path to file in temp location var filePath = Path.GetTempFileName(); foreach (var formFile in files) { if (formFile.Length > 0) { using (var stream = new FileStream(filePath, FileMode.Create)) { await formFile.CopyToAsync(stream); } } } return Ok(new { count = files.Count, size, filePath }); }
爲了很清楚地上傳文件所在目錄,咱們將官網例子進行一下改造。工具
public IActionResult UploadFiles(List<IFormFile> files) { long size = 0; foreach (var file in files) { //var fileName = file.FileName; var fileName = ContentDispositionHeaderValue .Parse(file.ContentDisposition) .FileName .Trim('"'); fileName = hostingEnv.WebRootPath + $@"\{fileName}"; size += file.Length; using (FileStream fs = System.IO.File.Create(fileName)) { file.CopyTo(fs); fs.Flush(); } } ViewBag.Message = $"{files.Count}個文件 /{size}字節上傳成功!"; return View(); }
如上經過注入 private IHostingEnvironment hostingEnv; 來獲取網站根目錄路徑。在前臺表單中請求action方法用渲染的方式,以下:post
<form method="post" enctype="multipart/form-data" asp-controller="Upload" asp-action="UploadFiles"> </form>
固然別忘記添加TagHelper:網站
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
成功上傳咱們顯示上傳字節大小,以下:ui
上傳的文件在網站根目錄下咱們可以看到,以下:this
上述咱們只是牛刀小試經過表單提交,接下來咱們進行拓展經過Ajax來提交。咱們將表單類型submit修改成button,以下:url
<div class="row"> <div class="form-group"> <div class="col-md-10"> <p>使用表單上傳多個文件</p> <input type="file" id="files" name="files" multiple /> @ViewBag.Message </div> </div> </div> <div class="row"> <div class="form-group"> <div class="col-md-10"> <input type="button" id="upload" class="btn btn-success" style="cursor:pointer;width:100px;" value="上傳" /> </div> </div> </div>
咱們經過FormData對象來獲取文件從而進行Ajax提交,以下:
$(function () { $("#upload").click(function (evt) { var fileUpload = $("#files").get(0); var files = fileUpload.files; var data = new FormData(); for (var i = 0; i < files.length ; i++) { data.append(files[i].name, files[i]); } $.ajax({ type: "POST", url: "/Upload/UploadFiles", contentType: false, processData: false, data: data, success: function (message) { alert(message); }, error: function () { alert("上傳文件出現錯誤!"); } }); }); });
此時後臺則須要進行略微修改,咱們再也不須要IFormFile接口來獲取文件,經過請求中的表單獲取,以下:
public IActionResult UploadFiles() { long size = 0; var files = Request.Form.Files; foreach (var file in files) { //var fileName = file.FileName; var fileName = ContentDispositionHeaderValue .Parse(file.ContentDisposition) .FileName .Trim('"'); fileName = hostingEnv.WebRootPath + $@"\{fileName}"; size += file.Length; using (FileStream fs = System.IO.File.Create(fileName)) { file.CopyTo(fs); fs.Flush(); } } ViewBag.Message = $"{files.Count}個文件 /{size}字節上傳成功!"; return View(); }
到這裏關於ASP.NET Core MVC中的上傳就告一段落,仍是比較簡單可是算是比較常見的需求。
項目中須要用到批量導入和導出因而進行了一點研究,.net core剛出世時還未有對於.net core中Excel的導出,可是見過園中有熱心園友分享並製做了.net core中導出Excel,可是博主發如今2月19號有老外已針對.net core的Excel導出和導入目前版本爲1.3基於EPPlus,功能和EPPlus差很少,不過是移植到了.net core中,下面咱們一塊兒來看看。首先咱們下載EPPlus.Core程序包,以下:
咱們直接上導出代碼:
[HttpGet] [Route("Export")] public string Export() { string sWebRootFolder = _hostingEnvironment.WebRootPath; string sFileName = @"Jeffcky.xlsx"; string URL = string.Format("{0}://{1}/{2}", Request.Scheme, Request.Host, sFileName); FileInfo file = new FileInfo(Path.Combine(sWebRootFolder, sFileName)); if (file.Exists) { file.Delete(); file = new FileInfo(Path.Combine(sWebRootFolder, sFileName)); } using (ExcelPackage package = new ExcelPackage(file)) { // add a new worksheet ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Jeffcky"); //sheet header worksheet.Cells[1, 1].Value = "ID"; worksheet.Cells[1, 2].Value = "Name"; worksheet.Cells[1, 3].Value = "Age"; //Add values worksheet.Cells["A2"].Value = 1000; worksheet.Cells["B2"].Value = "Jeffcky1"; worksheet.Cells["C2"].Value = 18; worksheet.Cells["A3"].Value = 1001; worksheet.Cells["B3"].Value = "Jeffcky2"; worksheet.Cells["C3"].Value = 19; package.Save(); //Save the workbook. } return URL; }
這裏咱們進行統一封裝下來進行導出只須要設置導出屬性和列表數據便可,以下:
public IActionResult Export() { var properties = new PropertyByName<Person>[] { new PropertyByName<Person>("Id",d=>d.Id), new PropertyByName<Person>("Name",d=>d.Name), new PropertyByName<Person>("Age",d=>d.Age) }; var list = new List<Person>() { new Person() {Id=1,Name="Jeffcky1",Age=18 }, new Person() {Id=2,Name="Jeffcky2",Age=19 }, new Person() {Id=3,Name="Jeffcky3",Age=20 }, new Person() {Id=4,Name="Jeffcky4",Age=21 }, new Person() {Id=5,Name="Jeffcky5",Age=22 } }; var bytes = _ExportManager.ExportToXlsx<Person>(properties, list); return new FileContentResult(bytes, MimeTypes.TextXlsx); }
說完導出咱們再來看導入,咱們來讀取剛剛導入的數據返回到頁面上:
public string Import() { string sWebRootFolder = _hostingEnvironment.WebRootPath; string sFileName = @"Jeffcky.xlsx"; FileInfo file = new FileInfo(Path.Combine(sWebRootFolder, sFileName)); try { using (ExcelPackage package = new ExcelPackage(file)) { StringBuilder sb = new StringBuilder(); ExcelWorksheet worksheet = package.Workbook.Worksheets[1]; int rowCount = worksheet.Dimension.Rows; int ColCount = worksheet.Dimension.Columns; bool bHeaderRow = true; for (int row = 1; row <= rowCount; row++) { for (int col = 1; col <= ColCount; col++) { if (bHeaderRow) { sb.Append(worksheet.Cells[row, col].Value.ToString() + "\t"); } else { sb.Append(worksheet.Cells[row, col].Value.ToString() + "\t"); } } sb.Append(Environment.NewLine); } return sb.ToString(); } } catch (Exception ex) { return "Some error occured while importing." + ex.Message; } }
此時咱們再來對導入進行統一封裝下,以下:
[HttpGet] [Route("Import")] public void Import() { string sWebRootFolder = _hostingEnvironment.WebRootPath; string sFileName = @"Jeffcky.xlsx"; FileStream fs = new FileStream(Path.Combine(sWebRootFolder, sFileName), FileMode.Open, FileAccess.Read, FileShare.Read); var list = _ImportManager.ImportPersonFromXlsx(fs); }
導入大概就介紹完畢了,要我說真正的難點不在於利用EPPlus導入和導出,難點在於批量導入,批量進行導入後對數據格式的檢驗,若是給定一個導入模板,而後再導入批量數據怎麼確保用戶給的數據格式徹底是正確的以及數據沒有重複的校驗,這兩天基本上是完成了批量的導入,大概分爲:數據必填項的校驗、數據格式的校驗、數據庫是否存在數據的校驗、數據導入部分導入失敗返回格式的用戶體驗。當利用NPOI、EPPlus來導入和導出這樣的功能再簡單不過了,可是若是遇到了不一樣的場景怎麼讓用戶體驗更好的使用這是一個問題,若是數據導入失敗咱們怎麼去提示用戶呢,還有若是Excel中有下拉框和合並的單元格數據咱們怎麼去獲取這又是一個問題,可能不少簡歷上寫着會利用NPOI和EPPlus的導入和導出,其實沒什麼看頭,兩者不過是一個工具罷了,如何利用工具去應用到複雜的場景並舉例那纔算是高級的東西。
本節咱們稍微介紹了.net core中的下載、導入和導出,若是有可能的話後續會給出關於EPPlus中高級的知識,好比如上提出的獲取合併列數據還有獲取圖片等等,咱們下節再會,哦,關於SQL Server有時間會按期進行更新,see u。