File input for forms in ASP.NET MVC

fileI’m not sure why ASP.NET MVC was shipped without a file input type for forms. Maybe it’ll come in MVC 2.0 or 3.0. Meanwhile, I created one. I spent two or three hours trying to figure out how to go from Object to IDictionary<String, Object> to follow the same ASP.NET MVC style where you have methods like:

TextBox(HtmlHelper, String, Object, IDictionary);
TextBox(HtmlHelper, String, Object, Object);

which are essentially the same. The last argument is a dictionary of extra HTML attributes, like style=”float: left;”. The good thing about accepting Object Is that you can call it this way:

Html.TextBox("email", new { style="float: left;" })

which is very handy for forms. The bad thing is that it is a pain in the ass to do that hocus pocus in C# using reflection. Thankfully ASP.NET MVC is open source. I downloaded the source and after 15 minutes I got it working nicely (and without manually using reflection). Use the source Luke!

In a recent episode of Hansel Minutes podcast someone argued what was the value of releasing the code of ASP.NET MVC at all. Well, this is the value. You help developers, you build a better developing community.

Without further ado, here’s the code:

public static class HtmlHelperExtensions {
   /// <summary>
   /// Returns a file input element by using the specified HTML helper and the name of the form field.
   /// </summary>
   /// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
   /// <param name="name">The name of the form field and the <see cref="member">System.Web.Mvc.ViewDataDictionary</see> key that is used to look up the validation errors.</param>
   /// <returns>An input element that has its type attribute set to "file".</returns>
   public static string FileBox(this HtmlHelper htmlHelper, string name) {
       return htmlHelper.FileBox(name, (object)null);
   }

    /// <summary>
    /// Returns a file input element by using the specified HTML helper, the name of the form field, and the HTML attributes.
    /// </summary>
    /// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
    /// <param name="name">The name of the form field and the <see cref="member">System.Web.Mvc.ViewDataDictionary</see> key that is used to look up the validation errors.</param>
    /// <param name="htmlAttributes">An object that contains the HTML attributes for the element. The attributes are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax.</param>
    /// <returns>An input element that has its type attribute set to "file".</returns>
    public static string FileBox(this HtmlHelper htmlHelper, string name, object htmlAttributes) {
        return htmlHelper.FileBox(name, new RouteValueDictionary(htmlAttributes));
    }

    /// <summary>
    /// Returns a file input element by using the specified HTML helper, the name of the form field, and the HTML attributes.
    /// </summary>
    /// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
    /// <param name="name">The name of the form field and the <see cref="member">System.Web.Mvc.ViewDataDictionary</see> key that is used to look up the validation errors.</param>
    /// <param name="htmlAttributes">An object that contains the HTML attributes for the element. The attributes are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax.</param>
    /// <returns>An input element that has its type attribute set to "file".</returns>
    public static string FileBox(this HtmlHelper htmlHelper, string name, IDictionary<String, Object> htmlAttributes) {
        var tagBuilder = new TagBuilder("input");
        tagBuilder.MergeAttributes(htmlAttributes);
        tagBuilder.MergeAttribute("type", "file", true);
        tagBuilder.MergeAttribute("name", name, true);
        tagBuilder.GenerateId(name);

        ModelState modelState;
        if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) {
            if (modelState.Errors.Count > 0) {
                tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
            }
        }

        return tagBuilder.ToString(TagRenderMode.SelfClosing);
    }
}

Reviewed by Daniel Magliola. Thank you!

You may also like:


6 responses to “File input for forms in ASP.NET MVC”

  1. Fabio Milheiro Avatar

    Hi,

    I am sure that this is the help that many people need and you did a very wise thing.

    Only I am not so smart, therefore, I can’t see what is going wrong with my code. Can you please help?

    I have a field of type image which is mapped as binary in my model (ADO.NET Entity Framework).

    But somehow the image that I get from the filebox is not being passed to the object. I know this because I debuged my action and the object Language (the image I trying to upload to the database is a flag) has the property Flag set to null and that is very bad! It should contain the image uploaded. Do I have to do something else?

    Below is my form html code and my action code:

    Fields

    Id:

    Name:

    Flag:

    IsDefault:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Language language)
    {
    if (!ModelState.IsValid || !_service.CreateLanguage(language))
    {
    return View(“Create”, language);
    }

    return RedirectToAction(“Index”);
    }

    Thank you!

  2. Fabio Milheiro Avatar

    The html code can’t be seen probably because it wasn’t encoded before being displayed, but I think you get the idea.

    If you please answer here or in the overstackflow.com post that I have just created, I would be very grateful to you.

    http://stackoverflow.com/questions/1391791/file-input-box-upload-image-to-database

    Good night!

  3. Rich Avatar

    Perhaps I missed something here. How would I call this function in the View .aspx page?

    What do I pass as the HtmlHelper object when I create the object?

  4. Pablo Avatar

    Rich, you just call it like any other Html Helper:

    You have to be sure that whatever namespace you put your the class I’ve described here is included for the views. This view: http://stackoverflow.com/questions/352118/asp-net-mvc-name-space-in-view

  5. Rich Avatar

    Pablo,

    Thanks. I got that part figured out and now I am calling it. I was trying to get the value out of a Form POST call, so my problem isn’t related directly to your example, but to dealing with the returned value.

    Here is my .cs code:

    [AcceptVerbs(HttpVerbs.Post)]

    public ActionResult Import(HttpPostedFile input_xml_file)
    {
    ViewData[“Message1”] = “This is your input file:”;
    ViewData[“Message2”] = input_xml_file.FileName;
    return View();
    }

    and my aspx code:

    I know I am doing something just a bit off somewhere obvious, but for the life of me, I cannot find it.

    Thanks again for the help and the code.

  6. Rich Avatar

    ah, found it.

    public ActionResult Import(HttpPostedFile input_xml_file)

    should be

    public ActionResult Import(string input_xml_file)

    then I have access to the file location and can open the file to do whatever with it as I need.

Leave a Reply

Hi, I'm Pablo, this is my web site. You can follow me or connect with me:

Or get new content delivered directly to your inbox.

Join 4,025 other subscribers

I'm writing a book

Stack of copies of How to Hire and Manage Remote Teams

How to Hire and Manage Remote Teams, where I distill all the techniques I've been using to build and manage distributed teams for the past 10 years.

I write about:

announcement blogging book book review book reviews books building Sano Business C# Clojure ClojureScript Common Lisp database Debian Esperanto Git history idea Java Kubuntu Lisp music Non-Fiction OpenID programming Python Rails rant re-frame release Ruby Ruby on Rails Sano science science fiction security self-help Star Trek startups technology Ubuntu video web Windows WordPress

I've been writing for a while:

%d bloggers like this: