How to stop file transfer if browser is closed / loaded

I upload a file asynchronously with HTML5 in MVC3. If I have a large file, say 1 GB, and after the 50% download is complete, I cancel the download or close the browser, it still saves the 500 MB file in the destination folder.

How can I deal with this problem in the controller and on the client side?

Here is my controller action:

[HttpPost] public ActionResult Upload(object fileToUpload1) { var fileName = Request.Headers["X-File-Name"]; var fileSize = Request.Headers["X-File-Size"]; var fileType = Request.Headers["X-File-Type"]; Request.SaveAs("D:\\uploadimage\\" + fileName, false); if (fileToUpload1 == null) { return Json(true, JsonRequestBehavior.AllowGet); } else { return Json(false, JsonRequestBehavior.AllowGet); } // return Json(false, JsonRequestBehavior.AllowGet); } 

And here is the Javascript:

 // Uploading - for Firefox, Google Chrome and Safari xhr = new XMLHttpRequest(); // Update progress bar xhr.upload.addEventListener("progress", uploadProgress, false); function uploadProgress(evt) { if (evt.lengthComputable) { var percentComplete = Math.round(evt.loaded * 100 / evt.total); //assign value to prgress bar Div var progressBar = document.getElementById("progressBar"); progressBar.max = evt.total; progressBar.value = evt.loaded; } } // File load event xhr.upload.addEventListener("load", loadSuccess, false); function loadSuccess(evt) { $(fileParentDivobj).find(".ImgDiv").find("span").html("uploaded"); addfile(fileParentDivobj); } //handling error xhr.addEventListener("error", uploadFailed, false); xhr.addEventListener("abort", uploadCanceled, false); function uploadFailed(evt) { alert("There was an error attempting to upload the file."); } function uploadCanceled(evt) { alert("The upload has been canceled by the user or the browser dropped the connection."); } xhr.open("POST", "@Url.Action("Upload","Home")", true); // Set appropriate headers xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.setRequestHeader("Content-Type", "multipart/form-data"); xhr.setRequestHeader("X-File-Name", file.fileName); xhr.setRequestHeader("X-File-Size", file.fileSize); xhr.setRequestHeader("X-File-Type", file.type); xhr.setRequestHeader("X-File", file); // Send the file (doh) xhr.send(file); 
+4
source share
2 answers

Firstly, this is not something that should be resolved using any client scripts, since I do not believe that you will be able to make a new request when you close the browser, and this will certainly not work when the connection is interrupted due to a problem with the network.

So, I did some digging, and I did not find anything in asp.net that would tell me that the connection to the request was interrupted. However, we can check how much data we received and how much data we should have received!

 public ActionResult Upload() { // I like to keep all application data in App_Data, feel free to change this var dir = Server.MapPath("~/App_Data"); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); // extract file name from request and make sure it doesn't contain anything harmful var name = Path.GetFileName(Request.Headers["X-File-Name"]); foreach (var c in Path.GetInvalidFileNameChars()) name.Replace(c, '-'); // construct file path var path = Path.Combine(dir, name); // this variable will hold how much data we have received var written = 0; try { using (var output = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) { var buffer = new byte[0x1000]; var read = 0; // while there is something to read, write it to output and increase counter while ((read = Request.InputStream.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, read); output.Flush(); written += read; } } } finally { // once finished (or when exception was thrown) check whether we have all data from the request // and if not - delete the file if (Request.ContentLength != written) System.IO.File.Delete(path); } return Json(new { success = true }); } 

Tested with client code using asp.net dev and google chrome server.

edit: just noticed that Chuck Savage posted this principle in the comments before, so props for him :)

+4
source

Focusing on the request causes the response to be forgotten, which can determine if the client is all connected (Response.IsClientConnected).
Just by checking if there is something to read, you ignore the case of a possible long (how long?) Network delay on the client side.
Use the approach of Chunk and Lukas and enable the Response.IsClientConnected property and the Sleep stream of your choice in case there is nothing to read, but the client is still connected. Thus, you are most likely to exit your reading cycle if you do not generate WTF from a client user.

0
source

Source: https://habr.com/ru/post/1384862/


All Articles