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

本文关键字:Api Web MVC4 NET 文件 ASP 何用 一个 | 更新日期: 2023-09-27 18:04:56

如何用ASP上传一个大文件?NET MVC4 Web Api
还能取得进步吗?

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

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

    public async Task<HttpResponseMessage> 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)

我怎么能得到多少字节加载?

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

默认情况下上传到两个位置的文件大小是有限制的。一个在请求级别,第二个,如果您在IIS上托管,那么在web服务器级别。我添加了本博客中提到的几个配置,并且我能够上传一个36mb的文件而没有任何问题。我把这个片段贴在下面。

基本上

1。

  <system.web> 
    <httpRuntime maxRequestLength="2097152"/>
  </system.web>

2。

<system.webServer> 
  <security> 
      <requestFiltering> 
         <requestLimits maxAllowedContentLength="2147483648" /> 
      </requestFiltering> 
  </security><system.webServer> 

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

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

 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<string, State> _state = new ConcurrentDictionary<string, State>();
    public State Get(string id)
    {
        State state;
        if (_state.TryGetValue(id, out state))
        {
            return state;
        }
        return null;
    }

    public async Task<HttpResponseMessage> 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<string> _startUpload;
    private Action<long> _uploadProgress;
    public FileMultipartStreamProvider(string root_path, Action<string> start_upload, Action<long> 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<long> _writeBytes;
    public WriteFileStreamProxy(string file_path, Action<long> 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://))上上传文件时,进度正在工作,但在非安全协议(http://))上,进度不工作,文件被完全缓冲,我不知道的方式是这样的,我相信这是IIS到Asp.net框架之间的某个bug当请求得到处理时。

现在,因为我成功地使它工作在https与HttpModule,我相信这是有可能使它工作也与Mvc Web Api,但我目前没有时间去检查。

用于解析多部分表单数据,我使用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<Guid,UploadData> Uploads = new Dictionary<Guid,UploadData>();
    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; }
}