首页 后端开发 C#.Net教程 ASP.NET WebAPi(selfhost)实现文件同步或异步上传

ASP.NET WebAPi(selfhost)实现文件同步或异步上传

Dec 20, 2016 pm 02:20 PM

前言
前面我们讲过利用AngularJs上传到WebAPi中进行处理,同时我们在MVC系列中讲过文件上传,本文结合MVC+WebAPi来进行文件的同步或者异步上传,顺便回顾下css和js,MVC作为客户端,而WebAPi利用不依赖于IIS的selfhost模式作为服务端来接收客户端的文件且其过程用Ajax来实现,下面我们一起来看看。

同步上传

多余的话不用讲,我们直接看页面。

<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时会获取不到文件数据。

到这里为止在MVC中操作就已经完毕,此时我们来看看在WebAPi中需要完成哪些操作。

(1)首先肯定需要判断上传的数据是否是MimeType类型。

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) 返回上传文件地址。

return Request.CreateResponse(HttpStatusCode.Created, JsonConvert.SerializeObject(savedFilePath));
分步骤解析了这么多,组装代码如下:

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:\Documents\Visual Studio 2013\Projects\WebAPiReturnHtml\WebAPiReturnHtml\upload\BodyPart_fa01ff79-4a5b-40f6-887f-ab514ec6636f ,因为此时我们重新命名了文件名称,所以需要将该文件移动到我们重新命名的文件地址。

整个过程就是这么简单,下面我们来看看演示结果。

ASP.NET WebAPi(selfhost)实现文件同步或异步上传

此时居然出错了,有点耐人寻味,在服务端是返回如下的Json字符串

List<string> savedFilePath = new List<string>();
登录后复制

此时进行反序列化时居然出错,再来看看页面上的错误信息:

ASP.NET WebAPi(selfhost)实现文件同步或异步上传

无法将字符串转换为List,这不是一一对应的么,好吧,我来看看返回的字符串到底是怎样的,【当将鼠标放上去】时查看的如下:

ASP.NET WebAPi(selfhost)实现文件同步或异步上传

【当将点击查看】时结果如下:

ASP.NET WebAPi(selfhost)实现文件同步或异步上传

由上知点击查看按钮时返回的才是正确的json,到了这里我们发现Json.NET序列化时也是有问题的,于是乎在进行反序列化时将返回的字符串需要进行一下处理转换成正确的json字符串来再来进行反序列化,修改如下:

var m = result.Content.ReadAsStringAsync().Result;
    m = m.TrimStart(&#39;\"&#39;);
    m = m.TrimEnd(&#39;\"&#39;);
    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 = $(&#39;.progress-bar&#39;);
  var percent = $(&#39;.progress-bar&#39;);
  $(&#39;form&#39;).ajaxForm({
   beforeSend: function () {
    $("#progress").show();
    var percentValue = &#39;0%&#39;;
    bar.width(percentValue);
    percent.html(percentValue);
   },
   uploadProgress: function (event, position, total, percentComplete) {
    var percentValue = percentComplete + &#39;%&#39;;
    bar.width(percentValue);
    percent.html(percentValue);
   },
   success: function (d) {
    var percentValue = &#39;100%&#39;;
    bar.width(percentValue);
    percent.html(percentValue);
    $(&#39;#fu1&#39;).val(&#39;&#39;);
   },
   complete: function (xhr) {
    if (xhr.responseText != null) {
     $("#linkAddr").prop("href", xhr.responseText);
     $("#success").show();
    }
    else {
     $("#fail").show();
    }
   }
  });
 })();
</script>
登录后复制

我们截图看下其中上传过程

上传中:

ASP.NET WebAPi(selfhost)实现文件同步或异步上传

上传完成:

当然这里的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>
登录后复制

总结

本节我们学习了如何将MVC和WebAPi隔离开来来进行上传,同时我们也发现在反序列化时Json.NET有一定问题,特此记录下,当发现一一对应时反序列化返回的Json字符串不是标准的Json字符串,我们对返回的Json字符串需要作出如下处理才行(也许还有其他方案)。

var jsonString = "返回的json字符串";
jsonString = jsonString.TrimStart(&#39;\"&#39;);
jsonString = jsonString.TrimEnd(&#39;\"&#39;);
jsonString = jsonString.Replace("\\", "");
登录后复制

   

接下来会准备系统学习下SQL Server和Oracle,循序渐进,你说呢!休息,休息!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1660
14
CakePHP 教程
1416
52
Laravel 教程
1310
25
PHP教程
1260
29
C# 教程
1233
24
C#.NET面试问题和答案:提高您的专业知识 C#.NET面试问题和答案:提高您的专业知识 Apr 07, 2025 am 12:01 AM

C#.NET面试问题和答案包括基础知识、核心概念和高级用法。1)基础知识:C#是微软开发的面向对象语言,主要用于.NET框架。2)核心概念:委托和事件允许动态绑定方法,LINQ提供强大查询功能。3)高级用法:异步编程提高响应性,表达式树用于动态代码构建。

C#.NET:探索核心概念和编程基础知识 C#.NET:探索核心概念和编程基础知识 Apr 10, 2025 am 09:32 AM

C#是一种现代、面向对象的编程语言,由微软开发并作为.NET框架的一部分。1.C#支持面向对象编程(OOP),包括封装、继承和多态。2.C#中的异步编程通过async和await关键字实现,提高应用的响应性。3.使用LINQ可以简洁地处理数据集合。4.常见错误包括空引用异常和索引超出范围异常,调试技巧包括使用调试器和异常处理。5.性能优化包括使用StringBuilder和避免不必要的装箱和拆箱。

测试C#.NET应用程序:单元,集成和端到端测试 测试C#.NET应用程序:单元,集成和端到端测试 Apr 09, 2025 am 12:04 AM

C#.NET应用的测试策略包括单元测试、集成测试和端到端测试。1.单元测试确保代码的最小单元独立工作,使用MSTest、NUnit或xUnit框架。2.集成测试验证多个单元组合的功能,常用模拟数据和外部服务。3.端到端测试模拟用户完整操作流程,通常使用Selenium进行自动化测试。

从网络到桌面:C#.NET的多功能性 从网络到桌面:C#.NET的多功能性 Apr 15, 2025 am 12:07 AM

C#.NETisversatileforbothwebanddesktopdevelopment.1)Forweb,useASP.NETfordynamicapplications.2)Fordesktop,employWindowsFormsorWPFforrichinterfaces.3)UseXamarinforcross-platformdevelopment,enablingcodesharingacrossWindows,macOS,Linux,andmobiledevices.

c#.net的持续相关性:查看当前用法 c#.net的持续相关性:查看当前用法 Apr 16, 2025 am 12:07 AM

C#.NET依然重要,因为它提供了强大的工具和库,支持多种应用开发。1)C#结合.NET框架,使开发高效便捷。2)C#的类型安全和垃圾回收机制增强了其优势。3).NET提供跨平台运行环境和丰富的API,提升了开发灵活性。

高级C#.NET教程:ACE您的下一次高级开发人员面试 高级C#.NET教程:ACE您的下一次高级开发人员面试 Apr 08, 2025 am 12:06 AM

C#高级开发者面试需要掌握异步编程、LINQ、.NET框架内部工作原理等核心知识。1.异步编程通过async和await简化操作,提升应用响应性。2.LINQ以SQL风格操作数据,需注意性能。3..NET框架的CLR管理内存,垃圾回收需谨慎使用。

c#.net适合您吗?评估其适用性 c#.net适合您吗?评估其适用性 Apr 13, 2025 am 12:03 AM

c#.netissutableforenterprise-levelapplications withemofrosoftecosystemdueToItsStrongTyping,richlibraries,androbustperraries,androbustperformance.however,itmaynotbeidealfoross-platement forment forment forment forvepentment offependment dovelopment toveloperment toveloperment whenrawspeedsportor whenrawspeedseedpolitical politionalitable,

C#作为多功能.NET语言:应用程序和示例 C#作为多功能.NET语言:应用程序和示例 Apr 26, 2025 am 12:26 AM

C#在企业级应用、游戏开发、移动应用和Web开发中均有广泛应用。1)在企业级应用中,C#常用于ASP.NETCore开发WebAPI。2)在游戏开发中,C#与Unity引擎结合,实现角色控制等功能。3)C#支持多态性和异步编程,提高代码灵活性和应用性能。

See all articles