<div class="container"> <div>@if (ViewBag.Success != null){ <div class="alert alert-danger" role="alert"><strong>成功啦 !</strong> 成功上传. <a href="@ViewBag.Success" target="_blank">open file</a> </div>}else if (ViewBag.Failed != null){ <div class="alert alert-danger" role="alert"><strong>失败啦 !</strong> @ViewBag.Failed </div>} </div> @using (Html.BeginForm("SyncUpload", "Home", FormMethod.Post, new { role = "form", enctype = "multipart/form-data", @style = "margin-top:50px;" })) {<div class="form-group"> <input type="file" id="file" name="file" /></div><input type="submit" value="Submit" class="btn btn-primary" /> }</div>上述我们直接上传后通过上传的状态来显示查看上传文件路径并访问,就是这么简单。下面我们来MVC后台逻辑
[HttpPost]public ActionResult SyncUpload(HttpPostedFileBase file){ using (var client = new HttpClient()) {using (var content = new MultipartFormDataContent()){ byte[] Bytes = new byte[file.InputStream.Length + 1]; file.InputStream.Read(Bytes, 0, Bytes.Length); var fileContent = new ByteArrayContent(Bytes); //设置请求头中的附件为文件名称,以便在WebAPi中进行获取 fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = file.FileName }; content.Add(fileContent); var requestUri = "http://localhost:8084/api/upload/post"; var result = client.PostAsync(requestUri, content).Result; if (result.StatusCode == System.Net.HttpStatusCode.Created) { //获取到上传文件地址,并渲染到视图中进行访问var m = result.Content.ReadAsStringAsync().Result;var list = JsonConvert.DeserializeObject<List<string>>(m);ViewBag.Success = list.FirstOrDefault(); } else {ViewBag.Failed = "上传失败啦,状态码:" + result.StatusCode + ",原因:" + result.ReasonPhrase + ",错误信息:" + result.Content.ToString(); }} } return View();}注意:上述将获取到文件字节流数组需要传递给 MultipartFormDataContent ,要不然传递到WebAPi时会获取不到文件数据。
if (!Request.Content.IsMimeMultipartContent()) {throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); }(2)我们肯定是需要重新生成一个文件名称以免重复,利用Guid或者Date或者其他。
string name = item.Headers.ContentDisposition.FileName.Replace(""", ""); string newFileName = Guid.NewGuid().ToString("N") + Path.GetExtension(name);(3)我们需要利用此类 MultipartFileStreamProvider 设置上传路径并将文件写入到这个里面。
var provider = new MultipartFileStreamProvider(rootPath); var task = Request.Content.ReadAsMultipartAsync(provider).....(4) 返回上传文件地址。
public Task<HttpResponseMessage> Post(){ List<string> savedFilePath = new List<string>(); if (!Request.Content.IsMimeMultipartContent()) {throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } var substringBin = AppDomain.CurrentDomain.BaseDirectory.IndexOf("bin"); var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, substringBin); string rootPath = path + "upload"; var provider = new MultipartFileStreamProvider(rootPath); var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(t =>{ if (t.IsCanceled || t.IsFaulted) {Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception); } foreach (MultipartFileData item in provider.FileData) {try{ string name = item.Headers.ContentDisposition.FileName.Replace(""", ""); string newFileName = Guid.NewGuid().ToString("N") + Path.GetExtension(name); File.Move(item.LocalFileName, Path.Combine(rootPath, newFileName)); //Request.RequestUri.PathAndQury为需要去掉域名的后面地址 //如上述请求为http://localhost:80824/api/upload/post,这就为api/upload/post //Request.RequestUri.AbsoluteUri则为http://localhost:8084/api/upload/post Uri baseuri = new Uri(Request.RequestUri.AbsoluteUri.Replace(Request.RequestUri.PathAndQuery, string.Empty)); string fileRelativePath = rootPath +"\"+ newFileName; Uri fileFullPath = new Uri(baseuri, fileRelativePath); savedFilePath.Add(fileFullPath.ToString());}catch (Exception ex){ string message = ex.Message;} } return Request.CreateResponse(HttpStatusCode.Created, JsonConvert.SerializeObject(savedFilePath));}); return task;}注意:上述item.LocalFileName为 E:DocumentsVisual Studio 2013ProjectsWebAPiReturnHtmlWebAPiReturnHtmluploadBodyPart_fa01ff79-4a5b-40f6-887f-ab514ec6636f ,因为此时我们重新命名了文件名称,所以需要将该文件移动到我们重新命名的文件地址。
此时居然出错了,有点耐人寻味,在服务端是返回如下的Json字符串
复制代码 代码如下: List<string> savedFilePath = new List<string>();
此时进行反序列化时居然出错,再来看看页面上的错误信息:
无法将字符串转换为List<string>,这不是一一对应的么,好吧,我来看看返回的字符串到底是怎样的,【当将鼠标放上去】时查看的如下:
【当将点击查看】时结果如下:
由上知点击查看按钮时返回的才是正确的json,到了这里我们发现Json.NET序列化时也是有问题的,于是乎在进行反序列化时将返回的字符串需要进行一下处理转换成正确的json字符串来再来进行反序列化,修改如下:
var m = result.Content.ReadAsStringAsync().Result;m = m.TrimStart(""");m = m.TrimEnd(""");m = m.Replace("\", "");var list = JsonConvert.DeserializeObject<List<string>>(m);
最终在页面显示如下:
到这里我们的同步上传告一段落了,这里面利用Json.NET进行反序列化时居然出错问题,第一次遇到Json.NET反序列化时的问题,比较奇葩,费解。
异步上传
所谓的异步上传不过是利用Ajax进行上传,这里也就是为了复习下脚本或者Razor视图,下面的内容只是将视图进行了修改而已,对于异步上传我利用了jquery.form.js中的异步api,请看如下代码:
<script src="~/Scripts/jquery-1.10.2.min.js"></script><script src="~/Scripts/jquery.form.js"></script><script src="~/Scripts/bootstrap.min.js"></script><link href="~/Content/bootstrap.min.css" rel="stylesheet" /><div class="container" style="margin-top:30px"> <div id="success" style="display:none;"><div class="alert alert-danger" role="alert"> <strong>上传成功</strong><span style="margin-right:50px;"></span><a href="" target="_blank" id="linkAddr">文件访问地址</a></div> </div> <div id="fail" style="display:none;"><div class="alert alert-danger" role="alert"> <strong>上传失败</strong></div> </div></div>@using (Ajax.BeginForm("AsyncUpload", "Home", new AjaxOptions() { HttpMethod = "POST" }, new { enctype = "multipart/form-data",@style="margin-top:10px;" })){ <div class="form-group"><input type="file" name="file" id="fu1" /> </div> <div class="form-group"><input type="submit" class="btn btn-primary" value="上传" /> </div>}<div class="form-group"> <div class="progress" id="progress" style="display:none;"><div class="progress-bar">0%</div> </div> <div id="status"></div></div><style> .progress {position: relative;width: 400px;border: 1px solid #ddd;padding: 1px; } .progress-bar {width: 0px;height: 40px;background-color: #57be65; }</style><script> (function () {var bar = $(".progress-bar");var percent = $(".progress-bar");$("form").ajaxForm({ beforeSend: function () {$("#progress").show();var percentValue = "0%";bar.width(percentValue);percent.html(percentValue); }, uploadProgress: function (event, position, total, percentComplete) {var percentValue = percentComplete + "%";bar.width(percentValue);percent.html(percentValue); }, success: function (d) {var percentValue = "100%";bar.width(percentValue);percent.html(percentValue);$("#fu1").val(""); }, complete: function (xhr) {if (xhr.responseText != null) { $("#linkAddr").prop("href", xhr.responseText); $("#success").show();}else { $("#fail").show();} }}); })();</script>我们截图看下其中上传过程
上传完成:
当然这里的100%不过是针对小文件的实时上传,如果是大文件肯定不是实时的,利用其它组件来实现更加合适,这里我只是学习学习仅此而已。
注意:这里还需重申一遍,之前在MVC上传已经叙述过,MVC默认的上传文件是有限制的,所以超过其限制,则无法上传,需要进行如下设置
(1)在IIS 5和IIS 6中,默认文件上传的最大为4兆,当上传的文件大小超过4兆时,则会得到错误信息,但是我们通过如下来设置文件大小。
<system.web> <httpRuntime maxRequestLength="2147483647" executionTimeout="100000" /></system.web>(2)在IIS 7+,默认文件上传的最大为28.6兆,当超过其默认设置大小,同样会得到错误信息,但是我们却可以通过如下来设置文件上传大小(同时也要进行如上设置)。
<system.webServer> <security><requestFiltering> <requestLimits maxAllowedContentLength="2147483647" /></requestFiltering> </security></system.webServer>总结
var jsonString = "返回的json字符串";jsonString = jsonString.TrimStart(""");jsonString = jsonString.TrimEnd(""");jsonString = jsonString.Replace("\", "");接下来会准备系统学习下SQL Server和Oracle,循序渐进,你说呢!休息,休息!