Reputation: 40182
I'm attempting upload multiple files in ASP.NET MVC and I have this simple foreach loop in my controller
foreach (HttpPostedFileBase f in Request.Files)
{
if (f.ContentLength > 0)
FileUpload(f);
}
The previous code generates this error:
Unable to cast object of type 'System.String' to type 'System.Web.HttpPostedFile'.
What I don't understand is why Request.Files[1] returns an HttpPostedFileBase but when it's iterated over, it returns strings (presumably the file names).
Note: I know this can be solved with a for loop. Also, I tried using HttpPostedFile, with the same error.
Upvotes: 81
Views: 92302
Reputation: 1664
You can get the HttpPostedFile
out of the HttpFileCollection
using foreach
like this:
foreach (var obj in fileCollection)
{
HttpPostedFile file = fileCollection.Get(obj.ToString());
}
Upvotes: 0
Reputation: 4935
We can use LINQ to do this and still use foreach as asked:
var files = Enumerable.Range(0, Request.Files.Count)
.Select(i => Request.Files[i]);
foreach (var file in files)
{
// file.FileName
}
As @tvanfosson said, the enumerator returns the file names as strings, not the HttpPostedFileBase
. This method HttpPostedFileBase this[string name]
returns the object we want. If HttpFileCollectionBase
implemented IEnumerable<HttpPostedFileBase>
then we could do the foreach normally. However, it implements a non-generic IEnumerable
.
Upvotes: 15
Reputation: 79
The following code worked for me.
HttpResponseMessage result = null;
var httpRequest = System.Web.HttpContext.Current.Request;
HttpFileCollection uploadFiles = httpRequest.Files;
var docfiles = new List<string>();
if (httpRequest.Files.Count > 0){
int i;
for (i = 0; i < uploadFiles.Count; i++) {
HttpPostedFile postedFile = uploadFiles[i];
var filePath = @"C:/inetpub/wwwroot/test1/reports/" + postedFile.FileName;
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
} else {
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
Upvotes: 6
Reputation: 1219
With my tab HTML is:
<input class="valid" id="file" name="file" multiple="" type="file">
Request.Files will have duplicate name in array. So you should solve like this:
for (int i = 0; i < Request.Files.Count; i++ ){
HttpPostedFileBase fileUpload = Request.Files[i];
Upvotes: 40
Reputation: 2908
Unfortunately tvanfosson's answer did not work for me. Although the files would upload just fine, and no error would be thrown, a problem would occur where only one of the files would be used, so the same file would be saved twice rather than using them both.
It seemed to be a problem with the foreach statement looping through the names of each file in the Request.Files, for some reason it wasn't working as a key for me, and only the first file would be selected every time.
HttpFileCollectionBase files = Request.Files;
for(var i = 0; i < files.Count; i++)
{
HttpPostedFileBase file = files[i];
...
}
Upvotes: 6
Reputation: 532435
The enumerator on the HttpFileCollection
returns the keys (names) of the files, not the HttpPostedFileBase
objects. Once you get the key, use the Item
([]
) property with the key (filename) to get the HttpPostedFileBase
object.
foreach (string fileName in Request.Files)
{
HttpPostedFileBase file = Request.Files[fileName];
...
}
Upvotes: 118
Reputation: 3140
You might try iterating the strings and casting them to HttpPostedFile instead, like this:
foreach (string file in Request.Files)
{
HttpPostedFile hFile = Request.Files[file] as HttpPostedFile;
if (hFile.ContentLength > 0)
FileUpload(hFile);
}
Upvotes: 6