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

简介:

同步上传

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

复制代码

<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>

复制代码

本文转自帅气的头头博客51CTO博客,原文链接http://blog.51cto.com/12902932/1926508如需转载请自行联系原作者

sshpp

相关文章
|
9月前
|
开发框架 前端开发 JavaScript
VUE3.0+Antdv+Asp.net WebApi开发学生信息管理系统(完)
VUE3.0+Antdv+Asp.net WebApi开发学生信息管理系统(完)
78 0
|
9月前
|
开发框架 前端开发 JavaScript
VUE3.0+Antdv+Asp.net WebApi开发学生信息管理系统(三)
VUE3.0+Antdv+Asp.net WebApi开发学生信息管理系统(三)
67 0
|
开发框架 JavaScript 前端开发
ASP.NET WebApi+Vue前后端分离之允许启用跨域请求
ASP.NET WebApi+Vue前后端分离之允许启用跨域请求
277 0
|
开发框架 .NET Linux
ASP.NET Core微服务之Docker容器化WebAPI
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一、Docker极简介绍 1.1 总体介绍   Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。
4369 0
|
开发框架 JSON .NET
HttpClient 调用WebAPI时—传参的三种方式(ASP.NET MVC&CORE均适用)
HttpClient 调用WebAPI时—传参的三种方式(ASP.NET MVC&CORE均适用)
234 0
|
开发框架 .NET API
版本化ASP.NET Core WebApi
版本化ASP.NET Core WebApi
115 0
|
XML 开发框架 .NET
【原创】ASP.NET WebApi接收xml文件 xml序列化
如何新建WebApi项目就不用我介绍了吧。 直接进入正题。 首先,在.net平台不论要接收什么,肯定是从Request里获取。 大家肯定对普通的参数获取非常熟悉了,下面就介绍一下如何从Request获取文件流. System.IO.Stream sm =Request.Content.ReadAsStreamAsync().Result 这个方法返回的是一个System.IO.Stream类型,如果是单纯想获得文件,到这一步你就可以把它保存到本地了。
9107 0
|
XML 开发框架 JSON
ASP.NET Core - 实现自定义WebApi模型验证
ASP.NET Core - 实现自定义WebApi模型验证  Framework时代    在Framework时代,我们一般进行参数验证的时候,以下代码是非常常见的 复制代码 [HttpPost] public async Task<JsonResult> SaveNewCus...
1662 0