在網站裡面,通常都會需要讓使用者上傳檔案,好方便前臺或者別的顯示這個資訊的地方來下載這個對應的檔案。
在Mvc裡面,有所謂的HttpPostedFileBase可以方便我們接到前端input是file的檔案。這個檔案通常會被存到Server的某一個位置之後,路勁才會儲存到DB 裡面,下次顯示的時候顯示的是這個檔案的路徑。
處理HttpPostedFileBase的邏輯其實還滿常見,如果框架能夠把這一部份也處理掉的話,又可以減少我們煩惱這些細節的部份,提升開發效率。
這一篇我們將來看一下如何做到。
同步發表於我的部落格:http://alantsai2007.blogspot.com/2014/10/BuildYourOwnApplicationFrameworkOnMvc-15-FileProcess.html
我們的Entity欄位通常會是string的形態,用來儲存這個上傳檔案的相對路徑。而檔案上傳方便做model binding是HttpPosedFileBase這個形態,因此我們將會在ViewModel增加一個對應的property用來接使用者所選取的檔案。
我們的邏輯處理規則是需要:
有了上面整體的概念之後,將會開始實作。
假設我們現在的Post需要有一個欄位用來儲存這篇文章的代表圖,因此我們會多一個欄位叫做CoverImg(在ViewModel),同樣對應到DB的Table欄位也是 CoverImg。
我們會在多一個欄位叫做CoverImgFile在ViewModel,這個欄位的主要目的是對應到View裡面的HttpPostedFileBase
因此目前Post的定義會是(標亮是新增的兩個欄位):
public partial class Create
{
public int Id { get; set; }
public string Title { get; set; }
public string PostContent { get; set; }
public System.DateTime CreateDateTime { get; set; }
public Nullable<System.DateTime> LastModifyDateTime { get; set; }
public string CoverImg { get; set; }
public HttpPostedFileBase CoverImgFile { get; set; }
}
再來,對應的View會變成:
@if(string.IsNullOrEmpty(Model.CoverImg) == false)
{
<img src="~/@Model.CoverImg" />
}
<input type="file" name="CoverImgFile" />
首先是如果檔案已經有上傳過(表示CoverImg有值),就以圖片方式顯示。
然後CoverImgFile則是實際的檔案上傳。
在Create的地方將會處理檔案上傳並且把路徑存到CoverImg:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Create post)
{
if(post.CoverImgFile != null)
{
var fileName = DateTime.Now.ToString();
post.CoverImgFile.SaveAs(fileName);
post.CoverImg = fileName;
}
if (ModelState.IsValid)
{
service.CreateViewModelToDatabase(post);
return RedirectToAction("Index");
}
return View(post);
}
這邊不管是否有驗證成功,都會把檔案儲存起來,避免Validation錯誤返回Model的時候,之前選的檔案會不存在。
到這裡之後,相信對於如何處理檔案上傳和把檔案路徑放入對應的欄位已經瞭解。
但是,相信使用上面來說不是很方便。首先,寫在Controller裡面這部份的邏輯就很不適合,再來,如果這個邏輯以後要修改或者需要通用基本上做不到。
因此,在下一篇,將會介紹如何透過Service層,把處理檔案上傳的邏輯抽出來,讓這部份的邏輯能夠共用。