Tuesday, March 25, 2008

File uploads with the MVC Framework

UPDATE: This post is out of date. It talks about an earlier version of the MVC Framework. Please check the ASP.NET MVC documentation for how to do file uploads.

There have been a couple of questions on the ASP.NET MVC newsgroup about this recently. It's pretty straight forward, you simply use the standard HTML input tag (type="file") in your form and then iterate through the HttpRequest's Files collection in your controller.

Here's the view's HTML:

<form action="/Document.mvc/UpdateDocument/" method="post" enctype="multipart/form-data">
   <label for="file1">Document 1</label>
   <input type="file" id="file1" name="file1" />

   <label for="file2">Document 2</label>
   <input type="file" id="file2" name="file2" />

   <label for="file3">Document 3</label>
   <input type="file" id="file3" name="file3" />
</form>

And here's the controller action:

public void SaveDocuments()
{
   foreach (string inputTagName in Request.Files)
   {
       HttpPostedFile file = Request.Files[inputTagName];
       if (file.ContentLength > 0)
       {
           string filePath = Path.Combine(@"C:\MyUploadedFiles", Path.GetFileName(file.FileName));
           file.SaveAs(filePath);
       }
   }
}

27 comments:

  1. Anonymous12:26 am

    Perfect - been hunting all day for an example on this very topic. How would you go about setting up tests for this though?

    ReplyDelete
  2. Thanks Brian, glad you found it useful.

    As for testing, the simple answer is you can't unless you use some heavyweight tool like Typemock. Although HttpRequestBase is mockable, HttpPostedFile isn't. When I write tests for a controller that does something like this, I just wrap this up in a virtual method and check that the controller calls it using a partial mock of the controller. You could also wrap it up as a service and pass it to the controller with Dependency Injection and then mock the service.

    ReplyDelete
  3. Anonymous1:01 pm

    Doesn't work! It pasess everything without errors but it doesn't save the files in c:\myuploadedfiles

    ReplyDelete
  4. Hi ta4ka,

    Pay close attention to the HTML. Your input tags must have a name attribute, the upload won't work without them, and you must put this attribute in your form tag:

    enctype="multipart/form-data"

    I hope this helps

    Mike

    ReplyDelete
  5. Anonymous3:58 pm

    I am getting an error and i saw that i don't get the value from the view to the controller. So i ask you what is form action="/Document.mvc/UpdateDocument/" for?

    ReplyDelete
  6. Ta4ka,

    /Document.mvc/UpdateDocument/

    is the URL to DocumentController's UpdateDocument Action. Your URL might be different if you've got a different routing scheme.

    Mike

    ReplyDelete
  7. Anonymous4:50 pm

    Thanks, i finally got it to work with the standard home controller and action savedocuments:
    action="/Home/SaveDocuments/"

    Thanks for your help.

    ReplyDelete
  8. Anonymous5:57 pm

    The path works only for C:\Myuploadedfile, when you put a server path like 'download\documents' it gets an error. I tried a lot of stuff with MapPath but they don't work.

    ReplyDelete
  9. Anonymous8:24 pm

    I got it to work :

    string patNekoj = HttpContext.Request.MapPath("../download/documents");

    string filePath = Path.Combine(patNekoj, Path.GetFileName(file.FileName));

    ReplyDelete
  10. Hi Ta4ka,

    That's great, I'm glad you managed to sort it out.

    Mike

    ReplyDelete
  11. Scott Hanselman has just writen a post on MVC Framework file uploads. He goes into rather more detail than I do so it's worth checking it out:

    http://www.hanselman.com/blog/ABackToBasicsCaseStudyImplementingHTTPFileUploadWithASPNETMVCIncludingTestsAndMocks.aspx

    ReplyDelete
  12. Anonymous1:36 pm

    Hi, using your code I got an error "Cannot implicitly convert type 'System.Web.HttpPostedFileBase' to 'System.Web.HttpPostedFile'" in HttpPostedFile file = Request.Files[inputTagName]; maybe anyone had the same? Thx, Sergei

    ReplyDelete
  13. Hi Anonymous, I think this is caused by a change to the MVC Framework API. Have a look at Hanselman's post I mentioned above for more info.

    ReplyDelete
  14. that worked great mate, thx.

    ReplyDelete
  15. Hello there, i couldnt be able to implement this code... i have some issues with multiple files :( and with the Request.File part... i couldnt compile the code :(

    Same problem that anonymous posted some time ago :(

    ReplyDelete
  16. Anonymous10:11 am

    hi i did the way u said but it is not giving anything in the request .files .Please tell me what i am missing.How will I do.


    thanks

    ReplyDelete
  17. Anonymous10:12 am

    please help me....what shall i do

    ReplyDelete
  18. Hi Anonymous, this post is quite out of date now. Have a look at the documentation on file uploads.

    Sorry to not be much use, but this was written when there wasn't much info about how to do this in an earlier MVC Framework preview, it should be a lot easier now.

    ReplyDelete
  19. Anonymous10:02 am

    hi mike

    i have one probleum ..
    how to convert string to 'System.Web.HttpPostedFile'.
    i have oe path of image in one variable of type string .. i want to store that path in fileupload control plz tell me hoe to do that .

    ReplyDelete
  20. Anonymous10:11 am

    plz help me how to do this ...

    i want to store the path of image from mystring(type = string)
    into file upload .. ....
    ..

    ReplyDelete
  21. does not work - does not call controller method (and what is this method?)

    ReplyDelete
  22. I would be very thankfull to you if you will give the example of checking th file`s type in order to maku sure that it is the image.

    Hope you will do it.
    Anyway, Thank you very much.

    ReplyDelete
  23. Anonymous7:34 pm

    Phil Haack has written a post here on how this can be done in MVC 2:

    http://haacked.com/archive/2010/07/16/uploading-files-with-aspnetmvc.aspx

    ReplyDelete
  24. Anonymous1:42 pm

    This works great if you have an old ASP page using the Persits Software ASP Upload. Server.CreateObject ("Persits.Upload.1") and you are migrating to a new server that doesn't support it and you don't feel like re-writing the entire app.

    ReplyDelete
  25. Thanks pro, I want to delete this file after uploaded? Please help me

    ReplyDelete
  26. It works great and so as other solutions all over the net, but i want to restrict users to select only few file types like ".jpg",".png" etc.
    Can't find any solution for this! Any idea how to do this?

    ReplyDelete

Note: only a member of this blog may post a comment.