Upload multiple files using HttpFileCollectionBase issue with C# and MVC3 - c#

I created a controller which save files.
The below code is a part of that Controller:
if ( Request.Files.Count != 0 ) {
HttpFileCollectionBase files = Request.Files;
foreach ( HttpPostedFileBase file in files ) {
if ( file.ContentLength > 0 ) {
if ( !file.ContentType.Equals( "image/vnd.dwg" ) ) {
return RedirectToAction( "List" );
}
}
}
}
in ASPX page is simple:
<input type="file" name="file" />
<input type="file" name="file" />
...// many inputs type file
The problem is foreach because it returns an error like (I know because I run in Debug mode and placed breakpoint at foreach statement):
Unable to cast object of type 'System.String' to type 'System.Web.HttpPostedFileBase'.
What is my mistake ?

Try like this:
[HttpPost]
public ActionResult Upload(IEnumerable<HttpPostedFileBase> files)
{
if (files != null && files.Count() > 0)
{
foreach (var uploadedFile in files)
{
if (uploadedFile.ContentType != "image/vnd.dwg")
{
return RedirectToAction("List");
}
var appData = Server.MapPath("~/app_data");
var filename = Path.Combine(appData, Path.GetFileName(uploadedFile.FileName));
uploadedFile.SaveAs(filename);
}
}
return RedirectToAction("Success");
}
and modify the markup so that the file inputs are named files:
<input type="file" name="files" />
<input type="file" name="files" />
...// many inputs type file

for (int i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[i];
// this file's Type is HttpPostedFileBase which is in memory
}
HttpRequestBase.Files requires an index, so use for instead of foreach.

Have a look at this post by Phil Haack which demonstrates how to process multiple file uploads using MVC. The object you are trying to use is for ASP.NET Webforms.

Related

How to upload multiple files into C# and loop through them in MVC

I'm having a problem with uploading multiple files to C# and loop through them. I found a question with a similar problem but nobody answered it.
I upload multiple files through an html input. The file count passes through to my controller with the correct amount relative to the amount of files I selected. However when I try to loop through each of my files it loops through the first file relative to the file count. For example if I upload 3 files it loops through the first file 3 times or if I upload 5 files it loops through the first file 5 times. It should not do this. I want it to loop through each file individually. Please help!!! here is my code:
Razor View(I'm using a bootstrap library for fileinputs called bootstrap-filestyle):
#using (Html.BeginForm("Initial", "DataCapture", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
<h4>Select files</h4>
<input type="file" multiple="multiple" id="fileToUpload" name="file">
</div>
<div>
<input type="submit" value="Capture" class="btn btn-default" />
</div>
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Initial(ClaimModel claimModel)
{
if (ModelState.IsValid)
{
//OtherCode
handleFile(Request.Files, c.ClaimID);
return RedirectToAction("Index", "ClaimFiles", new { id = c.ClaimID });
}
//OtherCode
}
private void handleFile(HttpFileCollectionBase Files, int ClaimID)
{
foreach (string fileName in Files)
{
HttpPostedFileBase file = Request.Files[fileName];
//OtherCode
}
//OtherCode
}
I put break points on handleFile(Request.Files, c.ClaimID); and inside foreach (string fileName in Files){...}. As I said it correctly passes through the file count if I upload 3, 4, 5 or any amount of files however it only loops through the first file that amount of times and returns the first file multiple times as well. I need it to loop through and return each file individually. How do I do this correctly?
Use Request from server, here is one example:
for (int i = 0; i < Request.Files.Count; i++)
{
var fileDoc = Request.Files[i];
}
Or you can try something like this:
HttpPostedFileBase hpf = null;
foreach (string file in Request.Files)
{
hpf = Request.Files[file] as HttpPostedFileBase;
}

uploading multiple files with ng-file-upload

I am trying to upload multiple files using ng-file-upload and I just can't seem to get it to work.
My html is
<input ngf-select ng-model="files" ngf-multiple="true" id="files" name="files" type="file" value="Choose File(s)" />
and a button once the files have been added
<button ng-click="uploadFiles(files)">Upload</button>
My controller is similar to the examples provided on github and jsfiddle.
$scope.uploadFiles = function (files) {
if (files && files.length) {
angular.forEach(files, function (file) {
$log.warn("counter");
if (files && !file.$error) {
file.upload = Upload.upload({
url: "FileUpload.ashx",
file: file,
fields: {
FormInstanceGuid: $scope.model.FormInstanceGuid,
FormName: $scope.model.Template.Name
}
});
file.upload.then(function (response) {
$log.info("We have succeeded in our call!");
$log.info(response);
}, function (reason) {
$log.info("We have failed in our call!");
$log.info(reason);
});
}
});
My problem comes down to the fact that the UploadHandler (on the server) is only called once and there is only ever 1 file coming in. My thinking is that it should be called once for each file as it's inside a forEach loop.
if (context.Request.Files.Count > 0) //This is never greater than 1
{
HttpFileCollection SelectedFiles = context.Request.Files;
for (int i = 0; i < SelectedFiles.Count; i++) {
HttpPostedFile file = SelectedFiles[i];
}
}
I've checked the network tab, and each file is in its own POST.

Uploading and processing multiple files using MVC

I am trying to upload multiple files on my web application. Hence I am using IEnumerable<HttpPostedFileBase> class to loop inside each file. But I am getting an error stating -
Error System.Collections.Generic.IEnumerable<System.Web.HttpPostedFileBase> does not contain a definition for 'ContentLength' and no extension method 'ContentLength' accepting a first argument of type System.Collections.Generic.IEnumerable<System.Web.HttpPostedFileBase' could be found (are you missing a using directive or an assembly reference?)
This error is for all the properties present in the HttpPostedFileBase class. I am trying to edit that class but it doesnt allow. I tried creating a IEnumerable of HttpPostedFileBase class in my ViewModel, but it fails again. What am I missing here?
Update - Code:
View
<div class="col-sm-8">
<input type="file" name="Files" id="file1" class="form-control" />
<input type="file" name="Files" id="file2" class="form-control" />
<input type="submit" value="Save" class="btn btn-default" name="Command"/>
</div>
Controller
public ActionResult UploadFile(IEnumerable<HttpPostedFileBase> Files)
{
foreach (var item in Files)
{
if (Files != null && Files.ContentLength > 0)
{
FileUpload up = new FileUpload();
up.PersonId = model.PersonId;
up.FileName = System.IO.Path.GetFileName(Files.FileName);
up.MimeType = Files.ContentType;
up.FileContent = Files.Content;
bll.AddFileUpload(up);
}
}
return View();
}
The problem is here:
foreach (var item in Files)
if (Files != null && Files.ContentLength > 0)
You're using foreach to iterate the collection, but you still check the IEnumerable called File instead of each item. What you want is:
foreach (var item in Files)
if (item != null && item.ContentLength > 0)
As a side note, you can filter out items using Enumerable.Where:
foreach (var item in Files.Where(file => file != null && file.ContentLength > 0))
{
FileUpload up = new FileUpload
{
PersonId = model.PersonId,
FileName = System.IO.Path.GetFileName(item.FileName),
MimeType = item.ContentType,
FileContent = item.Content,
};
bll.AddFileUpload(up);
}
You're trying to call .ContentLength on the collection, instead of on a file in that collection. Instead, try something like:
// given postedFiles implements IEnumerable<System.Web.HttpPostedFileBase
foreach(var postedFile in postedFiles) {
var len = postedFile.ContentLength
}
your code trying to access collection itself, but you need to access to collection item like this:
foreach (var item in Files)
{
FileUpload up = new FileUpload();
up.PersonId = model.PersonId;
up.FileName = System.IO.Path.GetFileName(item.FileName);
up.MimeType = Files.ContentType;
up.FileContent = item.Content;
bll.AddFileUpload(up);
}

Uploading File Using jQuery Submit Method

I have a Html Form with several FileUpload elements, which I want to submit it with jQuery submit method, The problem is when the Form submitted It does not send those Files which I want to upload. I don't know what is the problem and How should I solve that. The following code shows what is going on my code:
#using (Html.BeginForm("Create", "Personel", new { #enctype = "multipart/form-data" }))
{
<input type="file" id="personelPhoto" name="personelPhoto" />
}
if (form["personelPhoto"] != null)
{
// Request's files count is 0
}
Any advice will be helpful.
If you use a generic form submit and have the below as your backend c#(4.0) code it should work
if (Request.Files.Count > 0)
{
for (int i = 0; i < Request.Files.Count; i++)
{
HttpPostedFileBase hpfTest = Request.Files[i] as HttpPostedFileBase;
if (hpfTest.ContentLength == 0)
continue;
string savedFileName = Path.Combine(Server.MapPath("~") + "\\Files\\",Request.Form["name"]);
hpfTest.SaveAs(savedFileName);
}
}
Or you could use the "HttpFileCollection" in other versions of .net
HttpFileCollection files = Context.Request.Files;
files[0].SaveAs();

Validate File size before upload

I need to validate the file which is to be uploaded to the server. The validation must be done before uploading it. i.e., validation completed at client side. This task should be accomplished in ASP.NET MVC3 Webpage. It should also work with all browsers. IE9,8,7/FF/Chrome. I came to know that IE doesn't have FileReader API.
My Question is, How to Validate file size before Uploading in a MVC3 Webpage.
You can achieve by using jquery:
#
<span>
<b>Attachment</b> (8 MB only)<label id="attached" style="color:red; margin-left:5px"></label>
</span>
<input type="file" id="Attachment" name="Attachment" class="admin_textfeildmedium" value="" style="width:551px" accept="image/*">
#
jQuery(document).ready(function () {
jQuery('#Attachment').bind('change', function () {
//fileUpload = 0;
var iSize = (this.files[0].size / 1024);
if (iSize / 1024 > 1) {
if (((iSize / 1024) / 1024) > 1) {
fileUpload = 0;
} else {
iSize = (Math.round((iSize / 1024) * 100) / 100);
if (iSize <= 8) {
fileUpload = 1;
} else {
fileUpload = 0;
}
}
} else {
fileUpload = 1;
}
if (fileUpload == 0) {
// alert("Your attachment exceeded 8MB.");
jQuery('#attached').html('Your attachment exceeded 8MB.');
jQuery('#Attachment').val('');
}
});
});
.Net MVC Solution:
I am using the data type of HttpPostedFileBase
In your Views > Shared Folder, create a new folder called "EditorTemplates" and use this:
#model HttpPostedFileBase
#Html.TextBox("", null, new { type = "file" })
I then pass this HttpPostedFileBase object from the controller to a method that does the following:
public Files Upload(HttpPostedFileBase files)
{
if (files.ContentLength > 0) {
.....
}
The ContentLength property on the HttpPostedFileBase class contains the number of bytes in the posted file
This will make it so you have a file uploading box available.
On the ASP.NET WebForms Solution:
<asp:FileUpload ID="fuPictures" runat="server" />
Make a button with a OnClick or OnCommand event that does something like this:
if (fuPictures.HasFile == true)
{
int fileSize = fuPictures.FileBytes;
}
That will give you the file size. Hope this helps.
When it comes for a browser that supports HTML 5, it can be easily achieved with simple javascript:
Html Syntax
<input type="file" id="myFile" />
Javascript syntax
//gets the element by its id
var myFile = document.getElementById('myFile');
//binds to onchange event of the input field
myFile.addEventListener('change', function() {
//this.files[0].size gets the size of your file.
alert(this.files[0].size);
});
BUT, when it comes to an older browser (and we are all looking to you, Internet Explorer), the only way to do that on the client side is by using ActiveX:
var myFile = document.getElementById('myFile');
var myFSO = new ActiveXObject("Scripting.FileSystemObject");
var filepath = myfile.file.value;
var thefile = myFSO.getFile(filepath);
var size = thefile.size;
alert(size + " bytes");

Categories