基於ASP.NET MVC 4、WebApi、jQuery和FormData的多檔案上傳方法
阿新 • • 發佈:2019-02-19
通過<input type='file' />上傳檔案是網站應用系統的一個經典應用,可參考的文章較多。因為多種原因,筆者不能遠端桌面連線伺服器,只有通過網站方式上傳更新的應用系統檔案。正好五一幾天,把原來的有關構思程式設計實現,即鞏固了所學的ASP.NET MVC WebApi知識,也做一個通用的檔案上傳網站。本文不打算介紹實際的通用網站,而是用一個簡單例項主要介紹相關技術。
1、構建和初始化路由
控制器採用預設路由,WebApi採用定製路由,見如下全域性檔案Global、預設過濾器配置、預設控制器路由配置和定製WebApi路由配置程式的程式碼:
using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; namespace CSUST.Files { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() // 全域性檔案 Global.asax.cs { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); this.SetJsonFormatter(); } private void SetJsonFormatter() { GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); System.Net.Http.Headers.MediaTypeHeaderValue jsonFormatter = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Add(jsonFormatter); // 必須 } } }
using System.Web;
using System.Web.Mvc;
namespace CSUST.Files
{
public class FilterConfig // 過濾器配置 FilterConfig.cs
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
}
using System.Web.Mvc; using System.Web.Routing; namespace CSUST.Files { public class RouteConfig // 預設控制器路由配置 RouteConfig.cs { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
2、Home控制器程式碼和WebApi控制器程式碼using System.Web.Http; namespace CSUST.Files { public static class WebApiConfig // 定製WebApi路由配置 WebApiConfig.cs { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Routes.MapHttpRoute( name: "DefaultApi2", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { action = RouteParameter.Optional, id = RouteParameter.Optional } ); } } }
如下是預設的控制器HomeController程式碼以及多檔案上傳處理的WebApi程式碼
using System.Web.Mvc;
namespace CSUST.Files
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
using System;
using System.Web;
using System.Web.Http;
namespace CSUST.Files
{
public class FilesApiController : ApiController // FilesApi控制器
{
[HttpPost]
public string Upload()
{
try
{
var httpRequest = HttpContext.Current.Request;
var dirName = httpRequest.Form["DirName"]; // 獲取 FormData的鍵值
System.Text.StringBuilder ss = new System.Text.StringBuilder();
ss.Append("成功上傳檔案" + Environment.NewLine);
foreach (string key in httpRequest.Files) // 檔案鍵
{
var postedFile = httpRequest.Files[key]; // 獲取檔案鍵對應的檔案物件
var file = dirName + postedFile.FileName;
postedFile.SaveAs(file);
ss.Append(file + Environment.NewLine);
}
return ss.ToString();
}
catch (Exception err)
{
return err.Message;
}
}
}
}
3、檢視檔案Index.cshtml
下面是HomeController控制器Index方法對應的檢視檔案。
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>檔案上傳</title>
<script type="text/javascript" src='@Url.Action("jquery-1.12.4.min.js", "scripts")'></script>
<script type="text/javascript">
function Upload()
{
var dir = $("#cbDirNames").val();
var f1 = $("#tbFileName1").val();
var f2 = $("#tbFileName2").val();
if ((f1 == null || f1 == "") && (f2 == null || f2 == ""))
{
alert("至少要上傳一個檔案。");
return;
}
var formData = new FormData();
formData.append("DirName", dir);
if (f1 != null && f1 != "")
{
var files = $("#tbFileName1").get(0).files;
if (files.length > 0)
{
formData.append("File1", files[0]); // Add the uploaded image content to the form data collection
}
}
if (f2 != null && f2 != "")
{
var files = $("#tbFileName2").get(0).files;
if (files.length > 0)
{
formData.append("File2", files[0]); // Add the uploaded image content to the form data collection
}
}
$.ajax({
type: "post",
url: '@Url.Action("Upload", "Api/FilesApi")',
async: false,
data: formData,
contentType: false,
processData: false,
success: function (data, status)
{
alert(data);
},
error: function (xhr, status, err)
{
alert("ajax呼叫異常: " + status + "," + err);
}
});
}
</script>
</head>
<body>
<form id="Form1" enctype="multipart/form-data">
<div align="center">
<h2><label>檔案遠端上傳網站</label></h2>
<table style="width: 1050px;" border="1">
<tr style="height: 32px">
<td rowspan="2" style="width: 120px;text-align:center">
檔名
</td>
<td colspan="2" align="left">
<input ID="tbFileName1" name="tbFileName1" type="file" style="width: 96%;" multiple="multiple" />
</td>
</tr>
<tr style="height: 32px">
<td colspan="2" align="left">
<input ID="tbFileName2" name="tbFileName2" type="file" style="width: 96%;" multiple="multiple" />
</td>
</tr>
<tr style="height: 42px">
<td style="text-align: center">到資料夾</td>
<td style="width: 650px; text-align: left;">
<select ID="cbDirNames" style="width: 650px;">
<option>e:\temp\</option>
<option>e:\temp1\</option>
</select>
</td>
<td style="height: 42px; text-align:center;">
<input type="button" ID="bnUpload" value="上傳檔案" onclick="Upload()" style="width: 232px; height: 32px;" />
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
上述檢視檔案使用了jQuery獲取網頁三個元素的值,即上傳的資料夾名cbDirNames、上傳檔案tbFileName1和tbFileName2,該檢視使用jQuery的ajax同步提交多個檔案。需要說明如下幾點:
- @Url.Action用於產生 Url。該輔助方法可以根據路由表產生正確的相對地址,在ajax呼叫引數中也使用了該輔助方法。注意,上述程式碼的<script src=''>使用了不存在的動作jquery-1.12.4.min.js和控制器scripts,將產生一個類似MySite/scripts/jquery-1.12.4.min.js的Url。
- 資料物件FormData是一個名值表,提供了append函式增加名值對。如果是<input type='file' />元素,則自動新增檔案內容。該物件是2008年由html5引入,獲得目前主流的瀏覽器的支援。
- 在WebApi中,var httpRequest = HttpContext.Current.Request對應FormData,可以獲得名值對,也可以獲取檔名和內容。
檔案上傳網頁Index.cshtml的Form元素中必須有 enctype="multipart/form-data" 屬性。
後記:本文介紹的方法在開發機器上操作沒有任何問題,但釋出到客戶伺服器上就丟擲異常 Failed to execute, Failed to load XMLHttpRequest...。相關處理方法見拙文ASP.NET WebApi 上傳檔案時異常 Failed to execute send on XMLHttpRequest 的一個處理方法。