mvc upload file with model - second parameter posted file is null

64,695

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 like public 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.
}
Share:
64,695
Ahmed ilyas
Author by

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, 2020

Comments

  • Ahmed ilyas
    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
    Ahmed ilyas over 10 years
    Interesting. 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
    Jaimin over 10 years
    @Ahmedilyas I don't know why it's not working for you.It's perfectly working for me.
  • Ahmed ilyas
    Ahmed ilyas over 10 years
    was 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
    DFTR about 8 years
    Why do you use HttpPostedFileBase instead of HttpPostedFile?
  • PBMe_HikeIt
    PBMe_HikeIt over 7 years
    reference m.Files.Files is incorrect. Submitted edit
  • PBMe_HikeIt
    PBMe_HikeIt over 7 years
    need 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
    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.
    Honza P. almost 3 years
    This approach was what I was looking for, direct approach, the missing part in my problematic solution was "enctype="multipart/form-data" }" in BeginForm :-/.