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

前言
前面我们讲过利用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 ,因为此时我们重新命名了文件名称,所以需要将该文件移动到我们重新命名的文件地址。

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

此时居然出错了,有点耐人寻味,在服务端是返回如下的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>

总结

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

var jsonString = "返回的json字符串";
jsonString = jsonString.TrimStart('\"');
jsonString = jsonString.TrimEnd('\"');
jsonString = jsonString.Replace("\\", "");

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

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

(0)

相关推荐

  • asp.net+FCKeditor上传图片显示叉叉图片无法显示的问题的解决方法

    弄了半天也没有找到原因,然后又重新到网上下载几个,还是不行,郁闷坏了,最后结合其他编辑器的用法,才知道是配置文件夹中上传文件夹的路径写错了 比如要上传到项目的根目录下的UserFiles下面,web.config的配置如下: 复制代码 代码如下: <appSettings> <add key="FCKeditor:BasePath" value="~/FCKeditor" /> <add key="FCKeditor:User

  • JQuery.uploadify 上传文件插件的使用详解 for ASP.NET

    后来朋友推荐了一个这个叫uploadify的上传插件,似乎挺好,就到官方下了个示例运行,感觉挺好,自己再稍加美化一下就OK 了..! 接下来就讲讲使用过程吧: 1. 下载 官方网站:http://www.uploadify.com/ 直接下载:jquery.uploadify-v2.1.0.rar 我的Demo: MyUpload.rar                官方网站也有demo 下载解压后: 说明:它里面有demo  但是是PHP的,还有一个帮助文档:uploadify v2.1.0

  • asp.net(c#)开发中的文件上传组件uploadify的使用方法(带进度条)

    在Web开发中,有很多可以上传的组件模块,利用HTML的File控件的上传也是一种办法,不过这种方式,需要处理的细节比较多,而且只能支持单文件的操作.在目前Web开发中用的比较多的,可能uploadify(参考http://www.uploadify.com/)也算一个吧,不过这个版本一直在变化,他们的脚本调用也有很大的不同,甚至调用及参数都一直在变化,很早的时候,那个Flash的按钮文字还没法变化,本篇随笔主要根据项目实际,介绍一下3.1版本的uploadify的控件使用,这版本目前还是最新的

  • asp.net 多文件上传,兼容IE6/7/8,提供完整代码下载

    最终效果如下:现贴出核心代码如下: aspx里的代码: 复制代码 代码如下: <div style="text-align: center"> <div style="width: 200px;"> <input type="file" size="50" name="File" /> <span id="upload"></span

  • asp.net上传图片到服务器方法详解

    ASP.NET的FileUpload控件可用于上传文件到服务器.HoverTreeTop新增了一个"阅图"功能,图片就是用FileUpload上传的. 这里要说明的是上传图片限定文件名和文件大小等代码. 文件上传功能使用用户控件实现,在HoverTreePanel项目中的HTPanel\HControl\UCPictureAdd.ascx 控件, HoverTreeTop上传的图片文件暂时限定为jpg.png和gif.代码为: <asp:FileUpload runat=&quo

  • asp.net下文件上传和文件删除的代码

    文件上传 HttpPostedFile postFile = Request.Files["imgFile"]; if(postFile.FileName!=String.Empty){        ex=postFile.FileName.Substring(postFile.FileName.LastIndexOf("."));        fileName= DateTime.Now.ToString("yyyyMMdd") + ex;

  • ASP.NET实现上传Excel功能

    这几天正好用到上传Excel,并根据Excel中的数据做相应的处理,故整理以备用. 用到的资源: (1)NOPI 2.2.0.0 可自己官网下载,也可点击:http://pan.baidu.com/s/1b1EMdg (2)用到一些常见处理文件的公共方法类,可以添加到项目中:http://pan.baidu.com/s/1bJpHuQ 如过上述连接因故无法使用,可在评论留下邮箱,我打包发送过去,如有更好的建议,欢迎指导. 后台的提示方法ShowMsgHelper,根据自己的改写即可. 前台代码:

  • ASP.NET中上传并读取Excel文件数据示例

    在CSDN中,经常有人问如何打开Excel数据库文件.本文通过一个简单的例子,实现读取Excel数据文件. 首先,创建一个Web应用程序项目,在Web页中添加一个DataGrid控件.一个文件控件和一个按钮控件. 复制代码 代码如下: <INPUT id="File1" type="file" name="File1" runat="server"> <asp:Button id="Button1&

  • Asp.net MVC中使用JQuery插件ajaxFileUpload上传文件

    0 ajaxFileUpload简介 ajaxFileUpload插件是一个非常简单的基于Jquery的异步上传文件的插件,使用过程中发现很多与这个同名的,基于原始版本基础之上修改过的插件,文件版本比较多,我把我自己使用的ajaxFileUpload文件上传到博客园上了,想要使用的朋友可以下载:http://xiazai.jb51.net/201611/yuanma/ajaxfileupload(jb51.net).rar. 整个插件源码不到200行,实现非常简单,大致原理就是通过js动态创建隐

  • asp.net MVC实现无组件上传图片实例介绍

    例子: 如我想上传一个图片到服务器端:asp页面 复制代码 代码如下: <form id="form1" runat="server" action="/bookIndex/fileUpLoad/(你准备处理的 ActionResult)" method="post" enctype="multipart/form-data"> <input type="file" i

随机推荐