Uploading files in ASP.NET MVC

If you’ve tried creating a form that includes a file upload, you might have run into a problem of having a null value for the posted file in your controller’s action method. Take the following (Razor) view that accepts a string and a file upload as an example:

@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(model => model.SomeString)
        @Html.TextBoxFor(model => model.SomeString)
    </div>
    <div>
        <label for="fileUpload">File upload</label>
        <input type="file" id="fileUpload" name="fileUpload" />
    </div>
    <div>
        <input type="submit" value="Submit" />
    </div>
}

Now, assume the following action method on your controller class:

[HttpPost]
public ActionResult Upload(string someString, HttpPostedFileBase fileUpload)
{
   // Here's where I do something interesting with the uploaded file.
}

When we run this code we’ll find that the fileUpload variable that’s passed into our controller method is null even though the someString value is populated as expected. Why?

One of the subtle things that we have to remember (and which I have forgotten on several occasions) with file upload forms is that we have to change enctype attribute of the form tag to “multipart/form-data” (incidentally, the default value is “application/x-www-form-urlencoded”). Oh yeah, now we remember! So, let’s just add that attribute to the form tag in our view code above. But wait. There’s no form tag in the view code above. It’s being rendered by the BeginForm helper method. So now what do we do?

It turns out that there’s an overloaded version of the BeginForm method that will allow us to do exactly what we need. The revised version of the view looks like this:

@using (Html.BeginForm("Upload", "MyControllerName", FormMethod.Post, new { enctype = "multipart/form-data"}))
{
    <div>
        @Html.LabelFor(model => model.SomeString)
        @Html.TextBoxFor(model => model.SomeString)
    </div>
    <div>
        <label for="fileUpload">File upload</label>
        <input type="file" id="fileUpload" name="fileUpload" />
    </div>
    <div>
        <input type="submit" value="Submit" />
    </div>
}

See the last value we’re passing to the BeginForm method call? That’s the key! This tells the BeginForm method that we want to add the specified attribute name/value to the form tag. Now when we run the code, the fileUpload value passed in to the controller method will be fine and dandy.

Enjoy!

Advertisements

6 thoughts on “Uploading files in ASP.NET MVC

  1. Thanks for the explanation.
    I was looking for that!

    I am faced with a problem envolving Asp.Net MVC3 razor and helper. I can’t understand why my upload works with a simple html input only.

    I tried something like this in my view:

    @Html.TextBoxFor(model => model.FileName, new { @type=”file” })

    but it failed. The request at action has the file input null even I using the enctype showed above.

    Any idea?

    Thanks!
    Amanda.

    • I’m not aware of an HTML helper method for the HTML file upload control. Although what you have above might correctly render to the following HTML:

      However, you won’t be able to retrieve the file on the server side since I’m guessing Model.FileName is a string in your view model rather than a posted file.

      I think you need to use the above HTML input tag rather than using the HTML.TextBoxFor method for starters. Then, modify your action method that’s receiving the form post to accept a HttpPostedFileBase parameter called “FileUpload”. The model binder will automatically bind the uploaded file to your “FileUpload” parameter as long as the parameter name matches the name attribute of the input tag.

      Hope that helps!

  2. Hey Todd, thank you very much. I really needed this. I’d like to know if you have anything to say about persisting your data through the usage of the Entity Code First methodolgy and the respository pattern. I’d like to use my repository to store both the file and database data. I’m currently working on an social networking website that will be used to help users monitor their aquaponics systems. I’ve only started trying to implement the MVC methodology since it’s proper integration in the Visual Studio 2012 suite. This was long over due. I feel that Redmond should of done this at least a year earlier. I considered doing it in DNN but changed my mind after they did such a horrible job at integrating the ActiveSocial module into their main build.

  3. Hi Dan. Thanks for your comments. Actually, I haven’t yet worked with code first to any meaningful degree, so I’m afraid I can’t comment much on it. However, I HAVE worked a good deal with implementing the repository pattern with Entity Framework / POCO and have been very pleased with the outcomes (especially when combined with inversion of control / dependency injection to inject repositories directory into your controllers). I definitely agree with you that MVC was long overdue, and I now try to avoid Web Forms at all costs. Yes, DNN and similar products are certainly quick and handy for basic scenarios, but add a little complexity and you soon find those tools working against you.

    With regards to your second question, yes, I work a great deal with Razor and JQuery/AJAX (MVC works beautifully with AJAX) and highly recommend them. Although I’m familiar with Kendo UI, I haven’t worked with it. Have you also considered Knockout? I know others that have been pleased with it, but again, I have not worked with it yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s