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:

Nguyễn Ngọc Tú said...

ok , it's work , thanks

Anonymous said...

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

Mike Hadlow said...

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.

Anonymous said...

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

Mike Hadlow said...

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

Anonymous said...

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?

Mike Hadlow said...

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

Anonymous said...

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

Thanks for your help.

Anonymous said...

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.

Anonymous said...

I got it to work :

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

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

Mike Hadlow said...

Hi Ta4ka,

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

Mike

Mike Hadlow said...

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

Anonymous said...

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

Mike Hadlow said...

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.

Kostas said...

that worked great mate, thx.

Mauro said...

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 :(

Anonymous said...

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

Anonymous said...

please help me....what shall i do

Mike Hadlow said...

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.

Anonymous said...

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 .

Anonymous said...

plz help me how to do this ...

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

Unknown said...

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

Bogdan Burim said...

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.

Anonymous said...

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

Anonymous said...

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.

Ran said...

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

Amit said...

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?