您的位置:首页 > Web前端 > JQuery

基于ASP.NET MVC 4、WebApi、jQuery和FormData的多文件上传方法

2017-05-01 18:06 866 查看
通过<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 }
);
}
}
}


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 }
);
}
}
}
2、Home控制器代码和WebApi控制器代码

如下是默认的控制器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" 属性。

上述程序在Windows7+IIS+.NET Framwwork 4.0下基于ASP.NET MVC4框架编程实现,在浏览器Firefox53+、Chrome57+、IE11和Windows Edge等测试通过。如下是实际运行的截图。



后记:本文介绍的方法在开发机器上操作没有任何问题,但发布到客户服务器上就抛出异常 Failed to execute, Failed to load XMLHttpRequest...。相关处理方法见拙文ASP.NET WebApi 上传文件时异常 Failed
to execute send on XMLHttpRequest 的一个处理方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: