Uploading and processing multiple files using MVC - c#

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);
}

Related

export partial view to text file

I'm writing an ASP.NET web app (university task for exam). I have a database which has columns like Id, Name, Age, SumNote. First of all I had to make a partial view with top 5 students in database:
This method to get top 5 students
public class HomeController : Controller
{
StudentContext db = new StudentContext();
public ActionResult ShowTopFive ()
{
var allStudents = db.Students.OrderByDescending(s => s.SumNote).Take(5);
return PartialView(allStudents);
}
}
This is the patrial View:
#model IEnumerable<Univercity.Models.Student>
<div id="results">
<h4>Best 5 students</h4>
<ul>
#foreach (var item in Model)
{
<li>#item.Name, Summ of notes: #item.SumNote</li>
}
</ul>
</div>
and with this one I got the list of students in my webpage
<div>
<h5>Show top 5 students</h5>
</div>
<div>
#using (Ajax.BeginForm("ShowTopFive", new AjaxOptions { UpdateTargetId = "results" }))
{
<input type="submit" value="Show"/>
}
<div id="results"></div>
</div>
the output result looks like this:
Ivanov Mikhail, Summ of notes: 16
Kozlov Pete, Summ of notes: 12
Mary Ann, Summ of notes: 11
I also need to save it as text file. Can't figure out how? May be there is a way to change something in Ajax code?
Thanks in advance. Hope someone know how to do it. Google didn't help
You could create a controller action method which uses FileStreamResult by iterating the list created from ToList() and write necessary property values into a stream, then use Controller.File() overload which accepts stream to let user download text file:
public ActionResult GetTextFile()
{
var topFiveStudents = db.Students.OrderByDescending(s => s.SumNote).Take(5).ToList();
if (topFiveStudents != null && topFiveStudents.Count > 0)
{
string fileName = "something.txt";
// create a stream
var ms = new MemoryStream();
var sw = new StreamWriter(ms);
foreach (var students in topFiveStudents)
{
// iterate the list and write to stream
sw.WriteLine(string.Format("{0}, Sum of notes: {1}", students.Name, students.SumNote));
}
sw.Flush();
ms.Position = 0;
// return text file from stream
return File(ms, "text/plain", fileName);
}
else
{
// do something else
}
}
Afterwards, create an anchor link pointed to that action method mentioned above inside partial view:
#Html.ActionLink("Export to TXT", "GetTextFile", "ControllerName")

How to show directory files in select using razor?

With my current below code I can get the files and output them in a select option but if the user submits the form without selecting a image it will give a error
" Object reference not set to an instance of an object."
I have merch_image in the model Required.
How do I make the below select using razor so it won't bypass the Required?
controller:
public ActionResult Create()
{
DirectoryInfo dirInfo = new DirectoryInfo(#"//uploads/stamp_images");
ViewBag.Message = dirInfo.GetFiles().ToList();
return View();
}
View:
<select class="form-control col-sm-3" id="merch_image" name="merch_image">
<option selected disabled="disabled">Select</option>
#foreach (var item in ViewBag.Message)
{
<option value="#item.Name"> #item.Name</option>
}
</select>
#Html.ValidationMessageFor(model => model.merch_image, "", new { #class = "text-danger" })
Try this code, first its find containing image folder and find which one you find
in folder,
string ImagePath = Server.MapPath("~/uploads/stamp_images");
string FileName = 'xyz' + ".png";
//check image file exist or not
var filters = new String[] { "png" };
var files = GetFilesFrom(ImagePath, filters, false);
foreach (var item in files)
{
if (item.Contains(FileName))
{
//return contains image
}
}

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 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();

Upload multiple files using HttpFileCollectionBase issue with C# and MVC3

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.

Categories