Asp.net mvc 3 file uploads using the fileapi

Asp.net mvc 3 file uploads using the fileapijavascript

I was recently given the task of adding upload progress bars to some internal applications. A quick search of the internet yielded SwfUpload. Which worked…but not in the way that I wanted. So I went the route of using the new FileApi. It didn’t function the way that I’ve been used to standard file uploads. This is how I made it work in MVC3.css

Setup

First let’s just setup a basic upload form so that we have one that works in almost every browser.html

@using(Html.BeginForm("uploadfile","home",FormMethod.Post,new{ enctype ="multipart/form-data"})){<input id="files-to-upload" type="file" name="file"/><input type='submit' id='upload-files' value=' Upload Files '/>}[HttpPost]publicActionResultUploadFile(HttpPostedFileBase file){if(file !=null){Uploads.Add(file);}returnRedirectToAction("index); }

Uploads is just a static collection so that we can easily return the file if requested.java

Using the FileApi

Since this project is supposed to have a progress bar and allow multiple file uploads we’re going to make a few changes to the form.api

@using(Html.BeginForm("uploadfile","home",FormMethod.Post,new{ enctype ="multipart/form-data"})){<input id="files-to-upload" type="file" multiple name="file"/><input type='submit' id='upload-files' value=' Upload Files '/><div class='progress-bar'></div>}

Notice the multiple keyword added to the input. I’ve also added a progress-bar div for later. We need to override the submit button to use the FileApi rather than the standard POST.mvc

<scripttype="text/javascript"> $(function(){//is the file api available in this browser//only override *if* available.if(newXMLHttpRequest().upload){ $("#upload-files").click(function(){//upload files using the api//The files property is available from the//input DOM object upload_files($("#files-to-upload")[0].files);returnfalse;});}});//accepts the input.files parameterfunction upload_files(filelist){if(typeof filelist !=="undefined"){for(var i =0, l = filelist.length; i < l; i++){ upload_file(filelist[i]);}}}//each file upload produces a unique POSTfunction upload_file(file){ xhr =newXMLHttpRequest(); xhr.upload.addEventListener("progress",function(evt){if(evt.lengthComputable){//update the progress bar $(".progress-bar").css({ width:(evt.loaded / evt.total)*100+"%"});}},false);// File uploaded xhr.addEventListener("load",function(){ $(".progress-bar").html("Uploaded"); $(".progress-bar").css({ backgroundColor:"#fff"});},false); xhr.open("post","home/uploadfile",true);// Set appropriate headers// We're going to use these in the UploadFile method// To determine what is being uploaded. xhr.setRequestHeader("Content-Type","multipart/form-data"); xhr.setRequestHeader("X-File-Name", file.name); xhr.setRequestHeader("X-File-Size", file.size); xhr.setRequestHeader("X-File-Type", file.type);// Send the file xhr.send(file);}</script>

Now that we have this new upload script we’re going to have to update the back end to accommodate. I’ve created a new model called UploadedFile that will hold our upload regardless of where it came from.app

publicclassUploadedFile{publicintFileSize{get;set;}publicstringFilename{get;set;}publicstringContentType{get;set;}publicbyte[]Contents{get;set;}}

In our home controller I’ve added the following method. It checks to see where the upload came from. If it came from the normal POST the Request.Files will be populated otherwise it will be part of the post data.asp.net

privateUploadedFileRetrieveFileFromRequest(){string filename =null;string fileType =null;byte[] fileContents =null;if(Request.Files.Count>0){//they're uploading the old wayvar file =Request.Files[0]; fileContents =newbyte[file.ContentLength]; fileType = file.ContentType; filename = file.FileName;}elseif(Request.ContentLength>0){ fileContents =newbyte[Request.ContentLength];Request.InputStream.Read(fileContents,0,Request.ContentLength); filename =Request.Headers["X-File-Name"]; fileType =Request.Headers["X-File-Type"];}returnnewUploadedFile(){Filename= filename,ContentType= fileType,FileSize= fileContents !=null? fileContents.Length:0,Contents= fileContents };}

The UploadFile method will change slightly to use RetrieveFileFromRequest instead of taking directly from the Request.Files.less

[HttpPost]publicActionResultUploadFile(){UploadedFile file =RetriveFileFromRequest();if(file.Filename!=null&&!Uploads.Any(f => f.Filename.Equals(file.Filename)))Uploads.Add(file);returnRedirectToAction("index); }

It’s that simple. The only real difference between the two methods is that the HttpRequest.Files is not populated when using the FileApi. This can easily be used to create a Drag/Drop scenario by passinge.dataTransfer.files from the drop event into upload_files.ide

-Ben Dornis

http://buildstarted.com/2011/07/17/asp-net-mvc-3-file-uploads-using-the-fileapi/

相關文章
相關標籤/搜索