如何使用带有进度条的ASP.NET MVC4 Web Api上传大文件

如何使用ASP.NET MVC4 Web Api上传大文件
并取得进展?

我看到这篇文章,我明白如何处理上传的文件,但我如何获得进度数据? 如何接受文件POST

请不要发送链接上传产品。 我想了解如何在MVC4 Web Api中处理这个…这里是一个在MVC4 WebApi中处理文件上传的示例代码

public async Task Post() { if (Request.Content.IsMimeMultipartContent()) { var path = HttpContext.Current.Server.MapPath("~/App_Data"); var provider = new MultipartFormDataStreamProvider(path); await Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t => { if (t.IsFaulted || t.IsCanceled) throw new HttpResponseException(HttpStatusCode.InternalServerError); }); return Request.CreateResponse(HttpStatusCode.OK); } else { throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted")); } } 

现在,当

  await Request.Content.ReadAsMultipartAsync(provider) 

我怎样才能得到字节加载的方式?

默认情况下,在两个位置上传文件的大小有限制。 一个在请求级别,第二个,如果您在IIS上托管,那么在Web服务器级别。 我添加了几个配置,如本博客所述 ,我能够上传一个36mb文件没有任何问题。 我已经发布了下面的代码段。

基本上

1。

     

2。

       

如果您愿意,很容易找到加载到服务器中的文件的大小。 在你的代码中

在读取流中的filedata时,对于文件数据中的每个项目,您可以读取本地文件名,如下所示。

  string savedFile = fileData.LocalFileName; // use the file info class to derive properties of the uploaded file FileInfo file = new FileInfo(savedFile); //this will give the size of the uploaded file long size = file.length/1024 

希望这可以帮助。 我想知道为什么这会被标记下来?

我使用这个解决方案:

 public class UploadController : ApiController { private static ConcurrentDictionary _state = new ConcurrentDictionary(); public State Get(string id) { State state; if (_state.TryGetValue(id, out state)) { return state; } return null; } public async Task Post([FromUri] string id) { if (Request.Content.IsMimeMultipartContent()) { var state = new State(Request.Content.Headers.ContentLength); if (!_state.TryAdd(id, state)) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Conflict)); var path = System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data"); var provider = new FileMultipartStreamProvider(path, state.Start, state.AddBytes); await Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t => { _state.TryRemove(id, out state); if (t.IsFaulted || t.IsCanceled) throw new HttpResponseException(HttpStatusCode.InternalServerError); }); return Request.CreateResponse(HttpStatusCode.OK); } else { throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted")); } } } public class State { public long? Total { get; set; } public long Received { get; set; } public string Name { get; set; } public State(long? total = null) { Total = total; } public void Start(string name) { Received = 0; Name = name; } public void AddBytes(long size) { Received = size; } } public class FileMultipartStreamProvider : MultipartStreamProvider { private string _rootPath; private Action _startUpload; private Action _uploadProgress; public FileMultipartStreamProvider(string root_path, Action start_upload, Action upload_progress) : base() { _rootPath = root_path; _startUpload = start_upload; _uploadProgress = upload_progress; } public override System.IO.Stream GetStream(HttpContent parent, System.Net.Http.Headers.HttpContentHeaders headers) { var name = (headers.ContentDisposition.Name ?? "undefined").Replace("\"", "").Replace("\\", "_").Replace("/", "_").Replace("..", "_"); _startUpload(name); return new WriteFileStreamProxy(Path.Combine(_rootPath, name), _uploadProgress); } } public class WriteFileStreamProxy : FileStream { private Action _writeBytes; public WriteFileStreamProxy(string file_path, Action write_bytes) : base(file_path, FileMode.Create, FileAccess.Write) { _writeBytes = write_bytes; } public override void EndWrite(IAsyncResult asyncResult) { base.EndWrite(asyncResult); #if DEBUG System.Threading.Thread.Sleep(100); #endif if (_writeBytes != null) _writeBytes(base.Position); } public override void Write(byte[] array, int offset, int count) { base.Write(array, offset, count); #if DEBUG System.Threading.Thread.Sleep(100); #endif if (_writeBytes != null) _writeBytes(base.Position); } } 

和非缓冲输入流的小配置:

 config.Services.Replace(typeof(IHostBufferPolicySelector), new CustomPolicy()); 

实现了这个:

 public class CustomPolicy : System.Web.Http.WebHost.WebHostBufferPolicySelector { public override bool UseBufferedInputStream(object hostContext) { return false; } } 

我结束使用HttpModule,但即使是HttpModule也不会显示进度条我发现了一些非常有趣的东西似乎当我在安全协议(通过https://)上传文件时,进展正在运行但非安全protocl(http://)进度不起作用,文件是完全缓冲的我不知道是什么样的方式就像我认为这是IIS到Asp.net框架之间的某个错误,当请求被获取时。

现在因为我成功通过https与HttpModule一起工作我相信它可以使它与Mvc Web Api一起工作,但我目前没有时间检查它。

为解析Mutlipart表单数据,我在这里使用了Nancy HttpMultipart解析器: https : //github.com/NancyFx/Nancy/tree/master/src/Nancy刚刚抓住了这些类:
HttpMultipart.cs
HttpMultipartBoundary.cs
HttpMultipartBuffer.cs
HttpMultipartSubStream.cs

这是HttpModule来源:

 public class HttpUploadModule : IHttpModule { public static DateTime lastClean = DateTime.UtcNow; public static TimeSpan cleanInterval = new TimeSpan(0,10,0); public static readonly object cleanLocker = new object(); public static readonly Dictionary Uploads = new Dictionary(); public const int KB = 1024; public const int MB = KB * 1024; public static void CleanUnusedResources( HttpContext context) { if( lastClean.Add( cleanInterval ) < DateTime.UtcNow ) { lock( cleanLocker ) { if( lastClean.Add( cleanInterval ) < DateTime.UtcNow ) { int maxAge = int.Parse(ConfigurationManager.AppSettings["HttpUploadModule.MaxAge"]); Uploads.Where(u=> DateTime.UtcNow.AddSeconds(maxAge) > u.Value.createdDate ).ToList().ForEach(u=>{ Uploads.Remove(u.Key); }); Directory.GetFiles(context.Server.MapPath(ConfigurationManager.AppSettings["HttpUploadModule.Folder"].TrimEnd('/'))).ToList().ForEach(f=>{ if( DateTime.UtcNow.AddSeconds(maxAge) > File.GetCreationTimeUtc(f)) File.Delete(f); }); lastClean = DateTime.UtcNow; } } } } public void Dispose() { } public void Init(HttpApplication app) { app.BeginRequest += app_BeginRequest; } void app_BeginRequest(object sender, EventArgs e) { HttpContext context = ((HttpApplication)sender).Context; Guid uploadId = Guid.Empty; if (context.Request.HttpMethod == "POST" && context.Request.ContentType.ToLower().StartsWith("multipart/form-data")) { IServiceProvider provider = (IServiceProvider)context; HttpWorkerRequest wr = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest)); FileStream fs = null; MemoryStream ms = null; CleanUnusedResources(context); string contentType = wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentType); NameValueCollection queryString = HttpUtility.ParseQueryString( wr.GetQueryString() ); UploadData upload = new UploadData { id = uploadId ,status = 0, createdDate = DateTime.UtcNow }; if( !contentType.Contains("boundary=") || /*AT LAST 1KB */ context.Request.ContentLength < KB || /*MAX 5MB */ context.Request.ContentLength > MB*5 || /*IS UPLOADID */ !Guid.TryParse(queryString["upload_id"], out uploadId) || Uploads.ContainsKey( uploadId )) { upload.id = uploadId; upload.status = 2; Uploads.Add(upload.id, upload); context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); } string boundary = Nancy.HttpMultipart.ExtractBoundary( contentType ); upload.id = uploadId; upload.status = 0; Uploads.Add(upload.id, upload); try { if (wr.HasEntityBody()) { upload.bytesRemaining = upload.bytesTotal = wr.GetTotalEntityBodyLength(); upload.bytesLoaded = upload.BytesReceived = wr.GetPreloadedEntityBodyLength(); if (!wr.IsEntireEntityBodyIsPreloaded()) { byte[] buffer = new byte[KB * 8]; int readSize = buffer.Length; ms = new MemoryStream(); //fs = new FileStream(context.Server.MapPath(ConfigurationManager.AppSettings["HttpUploadModule.Folder"].TrimEnd('/')+'/' + uploadId.ToString()), FileMode.CreateNew); while (upload.bytesRemaining > 0) { upload.BytesReceived = wr.ReadEntityBody(buffer, 0, readSize); if(upload.bytesRemaining == upload.bytesTotal) { } ms.Write(buffer, 0, upload.BytesReceived); upload.bytesLoaded += upload.BytesReceived; upload.bytesRemaining -= upload.BytesReceived; if (readSize > upload.bytesRemaining) { readSize = upload.bytesRemaining; } } //fs.Flush(); //fs.Close(); ms.Position = 0; //the file is in our hands Nancy.HttpMultipart multipart = new Nancy.HttpMultipart(ms, boundary); foreach( Nancy.HttpMultipartBoundary b in multipart.GetBoundaries()) { if(b.Name == "data") { upload.filename = uploadId.ToString()+Path.GetExtension( b.Filename ).ToLower(); fs = new FileStream(context.Server.MapPath(ConfigurationManager.AppSettings["HttpUploadModule.Folder"].TrimEnd('/')+'/' + upload.filename ), FileMode.CreateNew); b.Value.CopyTo(fs); fs.Flush(); fs.Close(); upload.status = 1; context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write( context.Request.ApplicationPath.TrimEnd('/') + "/images/temp/" + upload.filename ); } } } } } catch(Exception ex) { upload.ex = ex; } if(upload.status != 1) { upload.status = 2; context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; } context.Response.End(); } } } public class UploadData { public Guid id { get;set; } public string filename {get;set;} public int bytesLoaded { get; set; } public int bytesTotal { get; set; } public int BytesReceived {get; set;} public int bytesRemaining { get;set; } public int status { get;set; } public Exception ex { get;set; } public DateTime createdDate { get;set; } }