asp.net MVC upload file get null in action's parameter [duplicate] - asp.net-mvc

I'm trying to do my first simple file upload in MVC 5. I'm following a bunch of examples I've found but for some reason in my "Create" ActionResult the uploadFile is always coming in as NULL so the upload code is never running. Anyone see what I might be doing wrong?
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Documents.</h2>
<h4>Upload a new document.</h4>
<div class="well">
#using (Html.BeginForm("Create", "Documents", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<h3>Select a file to upload. </h3>
<input type="file" name="files" value="" multiple="multiple" />
<input type="submit" value="Upload your file" title="Upload" />
<div style="color:Red;font-size:14px">#ViewBag.Message</div>
}
</div>
Here is my controller:
// POST: Documents/Create
[HttpPost]
public ActionResult Create(HttpPostedFileBase uploadFile)
{
try
{
if(uploadFile != null && uploadFile.ContentLength > 0)
{
string filePath = Server.MapPath("../SiteDocuments" + uploadFile.FileName);
uploadFile.SaveAs(filePath);
}
return RedirectToAction("Index");
}
catch (Exception ex)
{
return View();
}
}

Your file input element's name should match to your action method parameter name.
So update your HTML markup to have the same name attribute value.
<input type="file" name="uploadFile" value="" multiple="multiple" />
and your action method will be
[HttpPost]
public ActionResult Create(HttpPostedFileBase uploadFile)
{
// do something
}
Or change your action method parameter name to match with your file input element name.
<input type="file" name="files" value="" multiple="multiple" />
and your action method will be
[HttpPost]
public ActionResult Create(HttpPostedFileBase files)
{
if(files!= null && files.ContentLength > 0)
{
// do something
}
}
When you add multiple="multiple" attribute to the input element, the browser will allow the end user to select more than one file at a time. In that case If your action method parameter is a single instance of HttpPostedFileBase object, It will receive the first file from the selected n files. If you want all the files, You may change your parameter to a collection such as
[HttpPost]
public ActionResult Create(IEnumerable<HttpPostedFileBase> files)
{
if (files != null && files.Any())
{
foreach (var file in files)
{
if (file.ContentLength > 0)
{
//do something
}
}
}
}

Related

How can I get both a model and HttpPostedFileBase into a controller?

I've looked quite a bit online, and every example I see explains how to get IEnumerable<HttpPostedFileBase> into a controller, OR how to get a model, but not both.
What I want is something like:
<form>
<input type="text" name="Stored file name>
<input type="file" multiple="multiple" name="files>
<input type="submit">
</form>
with controller
[ActionName("Index"), HttpPost]
public ActionResult IndexPost(Models.MyModel mdl, IEnumerable<HttpPostedFileBase> files)
{
// Do some something with the data in mdl and files here
return RedirectToAction("Index");
}
But every way I try to implement this, it comes back 'no parameterless handler found'. It works fine if I don't include the model.
Am I missing something really obvious?
I guess you couldn't find Darin's this post. It's not exactly about passing model with HttpPostedFileBase but if you undrerstand the behavior the it's easy to do that.
See below example.
View
#model WebApplication2.Models.MyModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.HiddenFor(m => m.Id)
<input type="file" name="file" />
<input type="submit" value="OK" />
}
Action Method
[HttpPost]
public ActionResult Index(MyModel model, HttpPostedFileBase file)
{
if (file != null)
{
//do your stuff here
}
return View();
}

How to redirect to view with two forms from an action method?

Action Method called New inside the controller called Advert and its view running well. I just needed to embed another form into the view for image upload:
<form action="/advert/ImageUpload" method="post" enctype="multipart/form-data">
<input type="file" name="uploadfile" id="uploadfile" />
<input type="submit" value="Submit" />
</form>
This is the Action Method for that:
[HttpPost]
public ActionResult ImageUpload(HttpPostedFileBase uploadfile)
{
if (uploadfile.ContentLength > 0)
{
string filePath = Path.Combine("http://abcstorage.blob.core.windows.net/adv" + "_" + Path.GetFileName(uploadfile.FileName));
FileHelper.FileInsert(uploadfile, "adv", FileType.AdvertImage)
}
return View();
}
What should ImageUpload Method return? Apparently, not allowed to return view in this case. I just want the image to be uploaded and the keep going with the second form.
return RedirectToAction("ActionName", "Controller",(optional new { actionParam=something, etc }) );
or you can
return View("ViewName");

renaming file uploaded based on its input type's attribute(id) asp.net in mvc

View:
#using (Html.BeginForm("Edit","program","",FormMethod.Post,new {enctype = "multipart/form-data"}))
{
<div class="upload">
<input type="file" name="files" id="EpExpert"/>
<input type="file" name="files" id="EpNewbie"/>
<input type="submit" name="submit" value="submit" id="submit"/>
</div>
}
Controller:
[HttpPost]
public ActionResult Edit(tr_program program, IEnumerable<HttpPostedFileBase> files)
{
foreach (var file in files)
{
if (file != null)
{
//string extension = Path.GetExtension(file.FileName);
string path = AppDomain.CurrentDomain.BaseDirectory + "Documents/Program-PDFs/";
string filename = Path.GetFileName(file.FileName);
file.SaveAs(Path.Combine(path, filename));
}
}
}
uploaded file name should be in file-{id}.pdf
eg: file-EpNewbie.pdf
file-EpExpert.pdf
PLEASE help!!
The id is never sent to the server. You could use the name attribute instead:
#using (Html.BeginForm("Edit", "program", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="upload">
<input type="file" name="EpExpert" />
<input type="file" name="EpNewbie" />
<input type="submit" name="submit" value="submit" id="submit"/>
</div>
}
and in your controller action:
[HttpPost]
public ActionResult Edit(tr_program program)
{
string location = Server.MapPath("~/Documents/Program-PDFs");
foreach (string name in Request.Files)
{
HttpPostedFileBase file = Request.Files[name];
string filename = string.Format("file-{0}.pdf", name);
filename = Path.Combine(location, filename);
file.SaveAs(filename);
}
...
}
Obviously since you are storing all the files in the same location (~/Documents/Program-PDFs) with the same names (file-EpExpert.pdf and file-EpNewbie.pdf) if 2 users upload different files at the same time they might get overwritten. There seems to be a problem with your design and naming convention but in my answer I illustrated how you could pass the name of the file input to the controller action which could be used to build the resulting filename. Now it's up to you to take this into consideration when building your real application.
You can take an idea from here. Firstly declare id and data-id dynamic. for example
id = '#model.Id' data-id = '#model.Id'
Before submit form, use js or jquery take id value, then post form.
$("#myForm").submit(function () {
var idValue = $(this).attr('data-id');
document.getElementById('yourHiddenValue').value = idValue;
});

MVC 3 - passing two parameters from view to controller

I have an issue with passing 2 parameters from view to controller, when assigning them as a button. If I use this code in my View:
#using (Html.BeginForm("Edit", "Shift", new { lineName = item.Line, dateTime=item.Date }))
{
<input type="submit" value="Edit"/>
}
I get this string as result, which doesn't work because ampersand is replaced with &
<form action="/Shift/Edit?lineName=Line%203&dateTime=04%2F01%2F2004%2007%3A00%3A00" method="post"> <input type="submit" value="Edit"/>
</form>
So to resolve that I found I could use the Html.Raw
#using (Html.Raw(Url.Action("Edit", "Shift", new { lineName = item.Line, dateTime=item.Date })))
{
<input type="submit" value="Edit"/>
}
But this give me error:
'System.Web.IHtmlString': type used in a using statement must be implicitly convertible to 'System.IDisposable'
My Controller metdhods: (Edited)
//Displays Edit screen for selected Shift
public ViewResult Edit(string lineName, DateTime dateTime)
{
Shift shift = repository.Shifts.FirstOrDefault(s => s.Line == lineName & s.Date == dateTime);
return View(shift);
}
//Save changes to the Shift
[HttpPost]
public ActionResult Edit(Shift shift)
{
// try to save data to database
try
{
if (ModelState.IsValid)
{
repository.SaveShift(shift);
TempData["message"] = string.Format("{0} has been saved", shift.Date);
return RedirectToAction("Index");
}
else
{
//return to shift view if there is something wrong with the data
return View(shift);
}
}
//Catchs conccurency exception and displays collision values next to the textboxes
catch (DbUpdateConcurrencyException ex)
{
return View(shift);
}
}
Could you please support me with this, I spend couple of days on this one now.
Thanks
According to my understanding of your code, I suggest you following solution:
In View:
#using (Html.BeginForm("Edit", "Shift", FormMethod.Post, new { enctype = "multipart/form-data"}))
{
<input type="hidden" name="lineName" value="#item.Line"/>
<input type="hidden" name="dateTime" value="#item.Date"/>
<input type="submit" value="Edit"/>
}
In Controller :-
[HttpPost]
public ActionResult Edit(datatype lineName , datatype dateTime)
{
}
Please correct me If I am wrong.
add parameter in controller method for eg.
View :-
#using (Html.BeginForm("Edit", "Shift", new { lineName = item.Line, dateTime=item.Date }))
{
<input type="submit" value="Edit"/>
}
Controller :-
public ActionResult yourMethod(datatype lineName , datatype dateTime)

ASP.NET MVC Two file upload, different destinations

I'm trying to upload two different files into two different database fields on same form.
------------------------------------
reportid | name | image | template |
------------------------------------
this is the table look. So I want to upload files to image and template. My model:
public class Report
{
[Key]
public int ReportID { get; set; }
[Required]
public string Name { get; set; }
public byte[] Image { get; set; }
public byte[] Template { get; set; }
}
My Create method in controller:
public ActionResult Create(Report report, HttpPostedFileBase file, HttpPostedFileBase temp)
{
if (ModelState.IsValid)
{
if (file != null && file.ContentLength > 0)
{
using (MemoryStream ms = new MemoryStream())
{
file.InputStream.CopyTo(ms);
report.Image = ms.GetBuffer();
}
}
if (temp != null && temp.ContentLength > 0)
{
using (MemoryStream ms1 = new MemoryStream())
{
temp.InputStream.CopyTo(ms1);
report.Template = ms1.GetBuffer();
}
}
db.Reports.Add(report);
db.SaveChanges();
db.Configuration.ValidateOnSaveEnabled = true;
return RedirectToAction("Index");
}
And part of view concerning uploads:
<div class="editor-label">
<%:Html.LabelFor(model => model.Image) %>
</div>
<div class="editor-field">
<input type="file" id="fuImage" name="file" />
</div>
<div class="editor-label">
<%:Html.Label("Template") %>
</div>
<div class="editor-field">
<input type="file" id="temp" name="temp"/>
</div>
<p>
<input type="submit" value="Create" />
</p>
I'm quite stuck in this since I can not use IEnumerable<HttpPostedFileBase> files as a parameter in Create method because I need to save it in a different field, or can I? How should I approach this? Please help :S
Note: Image upload works fine.
Why not use IEnumerable<HttpPostedFileBase> ? You may use it like this.
[HttpPost]
public ActionResult Create(Report report, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
//Let's take first file
if(files.ElementAt(0)!=null)
{
var file1=files.ElementAt(0);
if (file1!= null && file1.ContentLength > 0)
{
//do processing of first file
}
}
//Let's take the second one now.
if(files.ElementAt(1)!=null)
{
var temp =files.ElementAt(1);
if (temp!= null && temp.ContentLength > 0)
{
//do processing of second file here
}
}
}
//Do your code for saving the data.
return RedirectToAction("Index");
}
EDIT : After seeing your View Markup in your EDIT.
The name of the file input element should be same as the parameter name in your action method. (files in this example)
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<b>File 1</b>
<input type="file" name="files" id="file1" />
<b>File 2</b>
<input type="file" name="files" id="file2" />
<input type="submit" />
}
This code assumes that read ONLY the first 2 entries from the collection.Since you wanted only 2 files, i hardcoded the indexes.
Phil has a nice blog post explaining about it very nicely.

Resources