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字符串首末尾的\和多出的\\去掉。然后再来看看反序列的数据

最终在页面显示如下:

到这里我们的同步上传告一段落了,这里面利用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,循序渐进,你说呢!休息,休息! 

时间: 2024-09-28 08:40:17

ASP.NET WebAPi(selfhost)之文件同步或异步上传的相关文章

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

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

asp.net下实现支持文件分块多点异步上传的 Web Services_实用技巧

本文的客户端应用程序不包括 ASP.Net Web 应用程序! 本文假设 URL: http://localhost/mywebservices/updownload.asmx 共有 4 个程序文件 (Web.Config 就不赘述了) Server Side:  标题中所提到的 "异步" 其实在服务器端的程序并没有什么特殊的,而主要是通过客户端应用程序 异步调用相关 Web Method 实现的! 1. updownload.asmx ,位于 IIS 的某个 Web 共享目录,代码如

ajax-Ajax文件异步上传问题

问题描述 Ajax文件异步上传问题 使用JQuery 进行异步上传文件,想点击"提交"后展示一个动画进度条(gif图片),提示"正在上传中",请问这种效果怎么实现? 解决方案 参考:http://download.csdn.net/detail/lvyulin/1470311 解决方案二: 点击提交后,进入调用ajax异步上传的方法,创建一个div浮动窗口,并展示进度条 在ajax中的success:function(msg){}及error:function(ab

jquery实现兼容IE8的异步上传文件_jquery

案例: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <script type="text/

简述Java异步上传文件的三种方式_java

本文为大家分享了三种Java异步上传文件方式,供大家参考,具体内容如下 用第三方控件,如Flash,ActiveX等浏览器插件上传. 使用隐藏的iframe模拟异步上传. 使用XMLHttpRequest2来实现异步上传. 第一种使用浏览器插件上传,需要一定的底层编码功底,在这里我就不讲了,以免误人子弟,提出这点大家可以自行百度. 第二种使用隐藏的iframe模拟异步上传.为什么在这里说的是模拟呢?因为我们其实是将返回结果放在了一个隐藏的iframe中,所以才没有使当前页面跳转,感觉就像是异步操

asp.net中MVC借助Iframe实现无刷新上传文件实例_实用技巧

本文实例讲述了asp.net中MVC借助Iframe实现无刷新上传文件的方法.分享给大家供大家参考.具体实现方法如下: html: 复制代码 代码如下: <div id="uploadwindow" style="display: none;">     <form action="/ShopActivitys/ImportActivityItems" id="form1" name="form1&

asp.net单文件带进度条上传的解决方案_实用技巧

最近做项目中遇到很多问题,比如带进度条的文件上传,看了网上很多资料还没找到真正意义上的ASP.NET实现进度条上传(可能是我没找到),下面我来跟大家分享一下我实现的这个程序. 首先看下界面效果,当然你可以完全修改界面为你自己所用. 先解释一下这个程序,该程序采用了jquery框架,实现了小文件上传,不超过80Mb,可以在web.config文件中进行相应的配置,但是有个最大值,具体需要查看msdn.开发环境采用visual studio 2013 .net framework 4.5,运行的时候

jQuery异步上传文件插件ajaxFileUpload详细介绍

这篇文章主要介绍了jQuery异步上传文件插件ajaxFileUpload详细介绍,本文首先讲解了ajaxFileUpload的参数.错误提示等知识,然后给出了简单使用实例和ASP.NET MVC模式下的使用实例,需要的朋友可以参考下     一.ajaxFileUpload是一个异步上传文件的jQuery插件. 传一个不知道什么版本的上来,以后不用到处找了. 语法:$.ajaxFileUpload([options]) options参数说明: 1.url 上传处理程序地址. 2,fileEl

Ajax表单异步上传文件实例代码(包括文件域)_AJAX相关

1.起因 做前台页面时,需要调用WebAPI的Post请求,发送一些字段和文件(相当于把表单通过ajax异步发送出去,得到返回结果),然后得到返回值判断是否成功. 2.尝试 先是尝试了一下 "jQuery Form Plugin" ,这玩意就是的巨大的坑,实现他和jquery1.9.2兼容性就不是太好,好不容易把$.browser的问题解决了,发现用他上传文件得不到返回值. $("#view").submit( $("#view").ajaxSu