NOTE 23 Oct 2012
I no longer recommend the use of Uploadify with MVC. I've found benefit using javascript-only solutions such as DropZone : http://www.dropzonejs.com/
or Valum's File Uploader : https://github.com/Valums-File-Uploader/file-uploader
or Valum's File Uploader : https://github.com/Valums-File-Uploader/file-uploader
Uploadify is ace for performing file upload and image upload, but ASP.NET MVC docs were lacking, so I hope this helps someone. Critical points addressed here include:
- Uploadify flash upload button is ugly so we use CSS to make it invisible and fake an HTML button under it.
- The Uploadify flash upload doesn't pass the ASP.NET session and authentication cookies naturally, which we want for recognition and authorization, so we handle that.
Put all Uploadify files in a project folder called ClientScript/uploadify
SCRIPT
Put this code on the regular View page that performs the upload.
<script type="text/javascript" src="<%= Url.Content("~/ClientScript/jquery-1.4.2.min.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/ClientScript/uploadify/swfobject.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/ClientScript/uploadify/jquery.uploadify.v2.1.4.min.js") %>"></script> <script type="text/javascript"> $(function () { // Uploadify File Upload System // SessionSync data is sent in scriptData for security reasons, see UploadifySessionSync() in global.asax var UploadifyAuthCookie = '<% = Request.Cookies[FormsAuthentication.FormsCookieName] == null ? string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>'; var UploadifySessionId = '<%= Session.SessionID %>'; $("#fuFileUploader").uploadify({ 'hideButton' : true, // We use a trick below to overlay a fake html upload button with this hidden flash button 'wmode' : 'transparent', 'uploader': '<%= Url.Content("~/ClientScript/uploadify/uploadify.swf") %>', 'cancelImg': '<%= Url.Content("~/ClientScript/uploadify/cancel.png") %>', 'buttonText': 'Upload File', 'script': '<%= Url.Action("FileUpload", "Media") %>', 'multi': true, 'auto': true, 'scriptData' : { RequireUploadifySessionSync: true, SecurityToken: UploadifyAuthCookie, SessionId: UploadifySessionId }, 'onComplete' : function (event, ID, fileObj, response, data) { response = $.parseJSON(response); if (response.Status == 'OK') { // Put your own handler code here instead of the following... alert('File Uploaded OK!'); } } }); }); </script>
HTML
Put this HTML on the same View as the script above.
<div style="position: relative;"> <input type="button" id="btnUpload" value="Upload File" /> <div style="position: absolute; top: 4px; left: 3px;"> <input id="fuFileUploader" name="file_upload" type="file" /> </div> </div>
GLOBAL.ASAX
Add the following bits.
protected void Application_BeginRequest(Object sender, EventArgs e) { if (HttpContext.Current.Request["RequireUploadifySessionSync"] != null) UploadifySessionSync(); } /// <summary> /// Uploadify uses a Flash object to upload files. This method retrieves and hydrates Auth and Session objects when the Uploadify Flash is calling. /// </summary> /// <remarks> /// Kudos: http://geekswithblogs.net/apopovsky/archive/2009/05/06/working-around-flash-cookie-bug-in-asp.net-mvc.aspx /// More kudos: http://stackoverflow.com/questions/1729179/uploadify-session-and-authentication-with-asp-net-mvc /// </remarks> protected void UploadifySessionSync() { try { string session_param_name = "SessionId"; string session_cookie_name = "ASP.NET_SessionId"; if (HttpContext.Current.Request[session_param_name] != null) UploadifyUpdateCookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]); } catch {} try { string auth_param_name = "SecurityToken"; string auth_cookie_name = FormsAuthentication.FormsCookieName; if (HttpContext.Current.Request[auth_param_name] != null) UploadifyUpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]); } catch {} } private void UploadifyUpdateCookie(string cookie_name, string cookie_value) { HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name); if (cookie == null) cookie = new HttpCookie(cookie_name); cookie.Value = cookie_value; HttpContext.Current.Request.Cookies.Set(cookie); }
Models/MediaAssetUploadModel.cs
public class MediaAssetUploadModel { public HttpPostedFileBase fileData { get; set; } public string SecurityToken { get; set; } public string Filename { get; set; } }
Controllers/MediaController.cs
[Authorize] public ActionResult FileUpload(MediaAssetUploadModel uploadedFileMeta) { string fullFilePath = SaveUploadedFile(uploadedFileMeta); //TODO: Error handling return Json(new { Status = "OK" }); } //TODO: move this into a manager/repository class private string SaveUploadedFile(MediaAssetUploadModel uploadedFileMeta) { string fileName = Guid.NewGuid() + System.IO.Path.GetExtension(uploadedFileMeta.Filename); string fullSavePath = Path.Combine(ConfigurationManager.AppSettings["MediaAssetFolder"], fileName); uploadedFileMeta.fileData.SaveAs(fullSavePath); return fullSavePath; }
Web.config
Make following changes to upload files to c:\temp , with a max file size of 100Mb.
Change these to suit yourself - c:\temp will get automatically cleared so you have been warned.
If you create your own upload folder, remember you will need to give write perms to the ASP.NET process.
<configuration> <appSettings> <add key="MediaAssetFolder" value="c:\temp"/> </appSettings> <system.web> <httpRuntime maxRequestLength="100000" /> </system.web> </configuration>
Thanks for posting this - the write up was spot on. You saved me an enormous amount of time piecing this all together.
ReplyDeleteGreat tip. Took me all of 2 minutes from start to finish and now my MVC 2 has async file uploads.
ReplyDeleteThank you!
Oh I wish this post had been around a few months ago!! This has to be the most complete coverage around of how to get Uploadify and MVC2 to play nice together. Really great stuff. Thanks so much for this.
ReplyDeletewe tried, but it is not working... dont know why?
ReplyDeleteAfter some small modifications to accomodate Razor and to save images direct to a database, this worked a treat.. Thanks very much!
ReplyDeleteGreat post! Is this solution ajax based? Or does it cause the page to refresh?
ReplyDeleteThanks,
Calum
Yeah, Uploadify does the upload asynchronously and calls the 'onComplete' javascript function as seen in the code above. You can then hook in any other AJAX / jQuery magic you like to handle the completion event.
ReplyDeleteNo nasty refreshes! :D
Cheers James, good to know... My page kept refreshing must of not copied and pastied your project well enough :)
ReplyDeleteThe value for Request.Cookies[FormsAuthentication.FormsCookieName] always seems to be null, so the controller is never called when the [authorize] tag is applied. Do I have to set something in the web.config for this cookie to be written? Thanks
ReplyDeleteHmm, have you put breakpoints into global.asax to make sure uploadify is sending through the scriptdata correctly?
ReplyDeleteSpecifically, is HttpContext.Current.Request["RequireUploadifySessionSync"] being set in Application_BeginRequest?
Also, Firebug/Fiddler is your friend - check the cookies coming in and out.
Congratulations the code to fix the session lost it works very good, thank you
ReplyDeleteAnyway of getting this javascript in a separate file?
ReplyDeleteI hope you are as good a Daddy as you are at Code, this is so helpful! :)
ReplyDeleteI did have some questions though, hopefully you are still taking responses to this post. I was curious as to why the security tokens, cookies, etc. I am not an expert programmer, and I am learning, but I wanted to know why that was needed to upload images?
I plan on using this code to upload images to a web server, store the image paths in a database, and use them in a slideshow on a public website. Are there any caveats I need to be aware of that aren't listed here? Thanks for your time!
Dear James,
ReplyDeleteWhen i used the uploadify on ajax/jquery dialog i can't use html button instead of flash upload button.
Hi, maybe you can help me, I am using same code, but after some time the page have been loaded, upoloadify uses new session(comparing "HttpContext.Session.SessionID" in controller and "ASP.NET_SessionId" in cookie)
ReplyDeleteAny ideas? Can I invoke old session with older id in controller?
You are a hero, thanks for the good post
ReplyDeleteHi, I'm having troubles getting this to work with Windows Authentication and MVC3, I'm still getting the same old "HTTP Error" before it even hits my action...
ReplyDeleteI would really appreciate help on this please!
Thanks.. This is it.. Daddycode!.
ReplyDeletei keep getting http error ...
ReplyDeleteneed help
cool its working now
ReplyDeleteGreat Tutorial. But how can I do it with Windows Authentification?
ReplyDeleteI found this solution very smart. I am curious if anyone had tried this solution in web farm scenarios (without sessioMode as outProc).
ReplyDeleteAny help will be much apppreciated
I was able to get this to work however I had to put the parameters from the scriptData option in the URL instead since it appears that the scriptData option is no longer available in the latest version of Uploadify.
ReplyDeleteHi James,
ReplyDeleteFor me HttpContext.Current.Request["RequireUploadifySessionSync"] always comes null. So no desired optput. Nothing happen on upload button click.
Please let me know where or how to set some value to:
HttpContext.Current.Request["RequireUploadifySessionSync"]
Really great post! Thanks for sharing it with us!
ReplyDelete"The Uploadify flash upload doesn't pass the ASP.NET session and authentication cookies naturally, which we want for recognition and authorization, so we handle that." -- It works fine in IE and not in FF. So, I was just curious to know -- how IE handles session? And why It works with IE? Can you please help me to understand it?
Kiran
Excellent post - thanks for that!
ReplyDeleteCan you elaborate more on why you don't recomment Uploadify?
ReplyDeleteHi Liam, although I haven't done anything with Uploadify recently, various people in the Comments here are saying the latest version doesn't have the ScriptData option anymore. I haven't verified that, but if true, it makes the authentication workaround difficult.
DeleteMore important to me however is the fact that Uploadify relies on Flash, which is a dying technology with limited support in the mobile / tablet space. That means its time is up. HTML5 / JavaScript solutions are the way forward now.
Hello, this is not safe. Session cookies are usually protected with a flag called HTTPOnly. This flag prevents cross site scripting because it makes the cookie inaccessible for javascript. Your script publishes the cookie value as part of the page content and therefor it is accessible for javascript and so for cross site scripting.
ReplyDelete