Reputation: 357
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.
Upvotes: 0
Views: 6546
Reputation: 1389
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!
Upvotes: 0
Reputation: 218732
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
}
Upvotes: 2