0

I have a ASP.NET MVC project in which the user can upload multiple files at a time. The following code is in the View:

@using (Html.BeginForm("Edit",
            "Bacteria",
            FormMethod.Post,
            new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<!--Other fields that are posted correctly to the db-->
 <div class="">
    <label class="control-label col-md-2">Attach New Files:</label>
    <div class="col-md-10">
        <input type="file" id="Attachment" name="Attachment" class="form-control" accept=".xls,.xlsx,.csv,.CSV,.png,.jpeg,.jpg,.gif,.doc,.docx,.pdf,.PDF" multiple />
    </div>
</div>
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="submit" value="Save" class="btn btn-default" />
    </div>
</div>

The method in the controller is:

if (ModelState.IsValid)
{
    db.Entry(bacteria).State = EntityState.Modified;
    db.SaveChanges();

    foreach (string file in Request.Files)
    {
        HttpPostedFileBase hpf = Request.Files[file];
        var fileName = Path.GetFileName(hpf.FileName);
        if (fileName == null || fileName == "")
        {
            break;
        }
        var subPath = "Attachments/Bacteria/" + bacteria.ID + "/";
        bool exists = System.IO.Directory.Exists(Server.MapPath("~/" + subPath));
        if (!exists)
        {
            System.IO.Directory.CreateDirectory(Server.MapPath("~/" + subPath));
        }
        var path = Path.Combine(subPath, fileName);
        hpf.SaveAs(Server.MapPath("~/" + path));
        BacteriaAttachment a = new BacteriaAttachment()
        {
            Name = fileName,
            Bacteria = bacteria,
            Link = path
         };
         db.BacteriaAttachments.Add(a);
         db.SaveChanges();
    }
}

If I upload FileOne.png, FileTwo.png, FileThree.png; the BacteriaAttachements table will get 3 new records with all of them having the same name (such as FileOne.png), link and bacteriaID. Only their ID (the primary key) is unique. And only one file (E.g: FileOne.png) gets uploaded in the server.

So instead of the three files being uploaded, only one of them is being uploaded thrice.

Any help is much appreciated.

Thank you.

2 Answers 2

2

When you execute, foreach (string file in Request.Files), for each iteration, the value of file will be the string value "Attachment", which is the name of your file input. When user uploads multiple files from the same input, Request.Files stores all of them with the same key - the name of your input element, which is "Attachment". Now when you execute Request.Files["Attachment"], it will give you only the first item (because all items has same key). For all iterations of the loop, this is what happening.

When accessing Request.Files, do not use name based access approach, Use index based approach (Request.Files[zeroBasedindex]).

You can use a for loop to properly iterate through the collection and read Request.Files using index based approach.

for(var i = 0; i < Request.Files.Count; i++)
{
    HttpPostedFileBase hpf =  Request.Files[i];
    // Your existing code to save hpf.
}

I personally always use a collection of HttpPostedFileBase as my HttpPost action method parameter or as a property in my view model (which i will use a paramater as my HttpPost action method) and loop that. The important thing to remember is, your parameter/property name should match with the name of the input you are using for file upload.

public ActionResult Save(List<HttpPostedFileBase> attachment)
{
   foreach(var hpf in attachment)
   {
     // to do : save hpf
   }
   // to do : return something
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much. It works using the index based approach!
0

Mudassar Ahmed Khan has explained it really well here: https://www.aspsnippets.com/Articles/MVC-HttpPostedFileBase-multiple-files-Upload-multiple-files-using-HttpPostedFileBase-in-ASPNet-MVC.aspx

You should consider using List<HttpPostedFileBase> as method parameter in your controller method. And then loop through each of them. Something like below;

foreach (HttpPostedFileBase postedFile in postedFiles)
        {
            if (postedFile != null)
            {
                string fileName = Path.GetFileName(postedFile.FileName);

Hope this is helpful!

2 Comments

you need to use List<HttpPostedFileBase>. No!. Though that is an ideal way to do it, "NEED TO USE" might not be the correct language.
I wanted to use this, but the problem is that the form is posting a Model to the server and I want to have some attachments posted from the same form. The problem is solved when I used the index based approach. Thanks though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.