mvc upload file with model - second parameter posted file is null
Solution 1
Why not add the uploaded files to your model like this:
public class UploadFileModel
{
public UploadFileModel()
{
Files = new List<HttpPostedFileBase>();
}
public List<HttpPostedFileBase> Files { get; set; }
public string FirstName { get; set; }
// Rest of model details
}
Then change your view to this:
@using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { encType="multipart/form-data" }))
{
@Html.TextBoxFor(m => m.FirstName)
<br /><br />
@Html.TextBoxFor(m => m.Files, new { type = "file", name = "Files" })<br /><br />
<input type="submit" value="submit me" name="submitme" id="submitme" />
}
Then your files will be posted back as follows:
public ActionResult UploadFile(UploadFileModel model)
{
var file = model.Files[0];
return View(model);
}
Solution 2
For dealing with a single file input you can define a HttpPostedFileBase
property within the ViewModel:
public class SomeModel()
{
public SomeModel()
{
}
public HttpPostedFileBase SomeFile { get; set; }
}
And then implement it in the following way:
View:
@model SomeModel
@using (Html.BeginForm(
"Submit",
"Home",
FormMethod.Post,
new { enctype="multipart/form-data" }))
{
@Html.TextBoxFor(m => m.SomeFile, new { type = "file" })
<input type="submit" value="Upload"
name="UploadButton" id="UploadButton" />
}
Controller:
[HttpPost]
public ActionResult Submit(SomeModel model)
{
// do something with model.SomeFile
return View();
}
In case you need to deal with multiple files, you can either:
- create multiple properties and implement them separately just like the one above;
- change the
public HttpPostedFileBase SomeFile
property to something likepublic List<HttpPostedFileBase> SomeFiles
and then span multiple@Html.TextBoxFor(m => m.SomeFile, new { type = "file" })
controls to have them all within that list.
In case you need additional info check out this blog post that I wrote on the topic.
Solution 3
Change your name file
to fileUpload
and enctype
it's work
@using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { enctype="multipart/form-data" }))
{
@Html.TextBoxFor(m => m.FirstName)
<br /><br />
<input type="file" name="fileUpload" /><br /><br />
<input type="submit" value="submit me" name="submitme" id="submitme" />
}
[HttpPost]
public ActionResult UploadFile(UploadFileModel model, HttpPostedFileBase fileUpload)
{
// DO Stuff
return View(model);
}
Solution 4
Alternatively, (if acceptable) remove the [Required] validation annotation for your file from your model and check for the file in your Controller action, and add an error if not found:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ActionWithFileUpload(ViewModel viewModel)
{
if (ModelState.IsValid)
{
if (Request.Files.Count > 0)
{
var postedFile = Request.Files[0];
if (postedFile != null && postedFile.ContentLength > 0)
{
string imagesPath = HttpContext.Server.MapPath("~/Content/Images"); // Or file save folder, etc.
string extension = Path.GetExtension(postedFile.FileName);
string newFileName = $"NewFile{extension}";
string saveToPath = Path.Combine(imagesPath, newFileName);
postedFile.SaveAs(saveToPath);
}
}
else
{
ModelState.AddModelError(string.Empty, "File not selected.");
}
}
return RedirectToAction("Index"); // Or return view, etc.
}
Ahmed ilyas
a previous MSFT, C# MVP and have had my name published in a few books as a technical reviewer. Have my own consultancy company in the UK and the US. Used to contribute heavily on the old MSDN forums and beginning to again as well as engaging with SO from time to time. Love to help the community gain great knowledge and give out my best to them, help people learn the right from the wrong, implement best practices and get people/developers to where they want to be. I soley focus on the Microsoft platform... SOreadytohelp
Updated on October 18, 2020Comments
-
Ahmed ilyas over 3 years
I have a simple model with 1 string property which I render on a simple view.
the view looks like the following:
@using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { encType="multipart/form-data" })) { @Html.TextBoxFor(m => m.FirstName) <br /><br /> <input type="file" name="fileUpload" /><br /><br /> <input type="submit" value="submit me" name="submitme" id="submitme" /> }
Controller is this:
[HttpPost] public ActionResult UploadFile(UploadFileModel model, HttpPostedFileBase file) { // DO Stuff return View(model); }
Now, when I submit, the model DOES get populated but the second parameter being HttpPostedFileBase is null. However when doing Request.Files - it does seem to show there is a file in the Request being posted. How can I actually get the second parameter to bind?
-
Ahmed ilyas over 10 yearsInteresting. This worked. Thanks! But still makes no sense why it will not bind to the 2nd parameter. I would like an explanation for that though.
-
Jaimin over 10 years@Ahmedilyas I don't know why it's not working for you.It's perfectly working for me.
-
Ahmed ilyas over 10 yearswas just waiting for it to allow me to accept the answer - all done. I agree with you, the VM approach. It's just... mind boggling on why it wont bind the 2nd parameter.
-
DFTR about 8 yearsWhy do you use HttpPostedFileBase instead of HttpPostedFile?
-
PBMe_HikeIt over 7 yearsreference m.Files.Files is incorrect. Submitted edit
-
PBMe_HikeIt over 7 yearsneed to add HTML5 multiple attribute like so if you want to choose more than 1 file with same input control
@Html.TextBoxFor(m => m.Files, new { type = "file", multiple = "multiple", name = "Files" })
-
Hamed_gibago almost 5 years@hutchonoid what change I should make in my table in sql? It get error key not found? I think I should add a column to UploadFileModel table in database named Files, but don't know the type of column. Am I write?
-
Honza P. almost 3 yearsThis approach was what I was looking for, direct approach, the missing part in my problematic solution was "enctype="multipart/form-data" }" in BeginForm :-/.