0

I know that uploading multiple files works fine, because, when I comment out [ValidateAntiForgeryToken] I can select multiple files and they will get uploaded without any issue all as intended.

However when I put [ValidateAntiForgeryToken] back If I select 2 or more files, I get server 500 status error and none of the files get uploaded.

Additionally I'll add the error: Failed to load resource: the server responded with a status of 500 (Internal Server Error) the stack trace says it stopped on line 1 of Upload action

However, if I select 1 file, it gets uploaded successfully and I get status code 200.

I'm still fairly new to this - I can't tell what's wrong. I appreciate any help on this enigma. :-)

This is my controller action:

[HttpPost]
[ValidateAntiForgeryToken]   // If I comment this out, everything works as intended
public ActionResult Upload()
{
    for (int i = 0; i < Request.Files.Count; i++)
    {
        var file = Request.Files[i];

        var fileName = Path.GetFileName(file.FileName);

        var path = Path.Combine(Server.MapPath("~/Some/FilePath"), fileName);
        file.SaveAs(path);
    }

    return Json(new { success = true, responseText = "Success!" }, JsonRequestBehavior.AllowGet); //This is placeholder, I'll implement validation later
}

The HTML:

@Html.TextBoxFor(model => model.file, new { type = "file", id = "file-upload", multiple="multiple" })
@Html.ValidationMessageFor(model => model.file, "", new { @class = "text-danger" })

<div id="selectedFiles"></div>

I build my custom file Array, so I could have a fancy remove file feature. This is my how I call the UploadAjax function:

var storedFiles = [];    //this is what I pass to it.

$("#stupidTest").click(function () {
    UploadAjax(storedFiles);
});

JQuery, AJAX. This is the upload function.

function UploadAjax(storedFilesArray) {
    var formData = new FormData();

    for (let i = 0; i < storedFilesArray.length; i++) {
        let file = storedFilesArray[i];

        formData.append('__RequestVerificationToken', getToken()); //appends the value to the formData. 
        formData.append("file-upload", file);
    }
    $.ajax({
        type: "POST",
        dataType: 'json',
        cache: false,
        url: '/Home/Upload',
        data: formData,
        contentType: false,
        processData: false,
        success: function (response) {
            ...
        },
        error: function (response) {
            ...
        }
    });
}

**Edit: Found that this happened at the same second my multiple file upload request failed**

System.Web.Mvc.HttpAntiForgeryException: The anti-forgery token could not be
decrypted. If this application is hosted by a Web Farm or cluster, ensure that
all machines are running the same version of ASP.NET Web Pages and that the
<machineKey> configuration specifies explicit encryption and validation keys.
AutoGenerate cannot be used in a cluster.
  • You are only getting the last file because all the files have the same filename. It just looks like one file gets uploaded (the last one). Check the file size of the one that got uploaded and see which one is in the folder. – jdweng Feb 06 '19 at 18:44
  • Sorry, I should of told. When I select multiple files with [ValidateAntiforgeryToken], I don't get any files uploaded. Only if I select 1 file, I'll get it to be uploaded under the same circumstances. I will update the post. :) – Liudvikas Taluntis Feb 06 '19 at 18:47
  • See following : https://stackoverflow.com/questions/15087028/upload-multiple-files-in-a-single-httpwebrequest – jdweng Feb 06 '19 at 18:52

2 Answers2

2

Take this line out of the loop (and put it above or below the loop):

formData.append('__RequestVerificationToken', getToken()); //appends the value to the formData.

append will keep adding on to the __RequestVerificationToken value that gets submitted to the server. Once it has been appended to once (ie. if you've selected 2 or more files), the value won't be a valid XSRF anti-forgery token. And then it fails to validate and thus you get an error on the server.

Becuzz
  • 6,846
  • 26
  • 39
  • 1
    Oh my god! I'm so sorry - I feel stupid now not to have noticed this. Thank you very much - a fresh pair of eyes goes a long way :) Now that I understand the issue... I see that the question doesn't reflect the actual issue. I'm kind of new to S.O. what do I do? >_ – Liudvikas Taluntis Feb 06 '19 at 19:21
  • @LiudvikasTaluntis Glad it helped. As far as your question goes, it's fine. You described your problem, provided the necessary code and reproduction steps. Leave it alone. Just because the problem is obvious (and different from what you thought it was) now doesn't make the question invalid. – Becuzz Feb 06 '19 at 19:56
1

Maybe yuo should set formData.append('__RequestVerificationToken', getToken()); outside the cycle?

var formData = new FormData();
formData.append('__RequestVerificationToken', getToken()); //appends the value to the formData. 
for (let i = 0; i < storedFilesArray.length; i++) {
        let file = storedFilesArray[i];
         formData.append("file-upload", file);
    }
joostas
  • 485
  • 5
  • 10
  • 1
    Thank you for noticing this. My assumptions that that part of code was fine worked against me >_< I really appreciate the help. :) Not sure what to do with this question though - it kind of doesn't reflect the issue. Do I change it to something more relevant, or do I remove it? New to S.O. and programming in general >_ – Liudvikas Taluntis Feb 06 '19 at 19:24
  • I don't know :) Maybe mark question as answered. Maybe someone else will make similar mistake by appending `__RequestVerificationToken` to form several times. – joostas Feb 06 '19 at 19:34
  • I see :) Thanks again for your help - I wouldn't have left home without fixing this. :D – Liudvikas Taluntis Feb 06 '19 at 19:41