Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get jQuery's Uploadify plugin to work with ASP.NET MVC?

I'm in the process of trying to get the jQuery plugin, Uploadify, to work with ASP.NET MVC.

I've got the plugin showing up fine with the following JavaScript snippet:

<script type="text/javascript">
    $(document).ready(function() {
        $('#fileUpload').fileUpload({
            'uploader': '/Content/Flash/uploader.swf',
            'script': '/Placement/Upload',
            'folder': '/uploads',
            'multi': 'true',
            'buttonText': 'Browse',
            'displayData': 'speed',
            'simUploadLimit': 2,
            'cancelImg': '/Content/Images/cancel.png'
        });
    });
</script>

Which seems like all is well in good. If you notice, the "script" attribute is set to my /Placement/Upload, which is my Placement Controller and my Upload Action.

The main problem is, I'm having difficulty getting this action to fire to receive the file. I've set a breakpoint on that action and when I select a file to upload, it isn't getting executed.

I've tried changing the method signature based off this article:

public string Upload(HttpPostedFileBase FileData)
{
    /*
    *
    * Do something with the FileData
    *
    */
    return "Upload OK!";
}

But this still doesn't fire.

Can anyone help me write and get the Upload controller action's signature correctly so it will actually fire? I can then handle dealing with the file data myself. I just need some help getting the method action to fire.

like image 580
KingNestor Avatar asked Jun 16 '09 16:06

KingNestor


4 Answers

public string Upload(HttpPostedFileBase FileData) {}

is correct - the file uploaded by uploadify will get binded to FileData. No need to get into Request.Files to retrieve the file - which makes it harder to mock and test.

If your action isn't firing at all (i.e. try debugging and see if a breakpoint within the method is hit), then your issue is most likely the 'script' value - are you running under a virtual directory? If so you'll need to put the name of the directory in front. Uploadify is using an absolute path.

i.e. 'script: '/virtual_directory/Placement/Upload'

right now uploadify is sending to http://localhost/Placement/Upload.

also try using the route debugger (http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx) to check where your route is being mapped to.

like image 186
Justin Avatar answered Nov 08 '22 08:11

Justin


The problem might be that you need to specify that the action you are uploading to is set to Post...it won't work with the action as a Get action.

So, this:

public string Upload(HttpPostedFileBase FileData)
{
   //do something
}

Should be this:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Upload(HttpPostedFileBase FileData)
{
   //do something
}

Also, be aware that if you are using this in a "logged in" section of your site, you should take a look here for a known bug with uploadify and authentication: http://geekswithblogs.net/apopovsky/archive/2009/05/06/working-around-flash-cookie-bug-in-asp.net-mvc.aspx

Also, just an aside, there are several ways in MVC to handle file uploads (using Request.Files as per Rory Fitzpatrick's suggestion, as well as passing the HttpPostedFileBase file as an argument in the action definition). It shouldn't really matter in order to get Uploadify to work.

like image 33
dp. Avatar answered Nov 08 '22 07:11

dp.


This isn't how I had to implement file upload at all. I had an action method with no parameters that used the current Request object to dive into the collection of posted files.

Some sample code from my implementation:

[AcceptVerbs(HttpVerbs.Post)]
public ContentResult Upload() {
    if (Request.Files.Count > 0 && Request.Files[0].ContentLength > 0) {
        HttpPostedFileBase postedFile = Request.Files[0];
        // Do something with it
    }
}

Of course, writing tests for this becomes a PITA. You have to mock several objects in order to get it to work, for example:

var mockHttpContext = mocks.StrictMock<HttpContextBase>();
var mockRequest = mocks.StrictMock<HttpRequestBase>();
var postedFile = mocks.StrictMock<HttpPostedFileBase>();

var postedFileKeyCollection = mocks.StrictMock<HttpFileCollectionBase>();

mockHttpContext.Expect(x => x.Request).Return(mockRequest).Repeat.Any();
mockRequest.Expect(x => x.Files).Return(postedFileKeyCollection).Repeat.Any();

postedFileKeyCollection.Expect(x => x[0]).Return(postedFile).Repeat.Any();
postedFileKeyCollection.Expect(x => x.Count).Return(1);

postedFile.Expect(f => f.ContentLength).Return(1024);
postedFile.Expect(f => f.InputStream).Return(null);

It would be easier to create an interface into the posted files and only mock that, with a concrete implementation injected into your controller using IoC.

I think this was largely based off of this post: Implementing HTTP File Upload with ASP.NET MVC including Tests and Mocks

like image 2
roryf Avatar answered Nov 08 '22 08:11

roryf


My full solution to this might solve your problem. Hope it helps.

http://zootfroot.blogspot.com/2010/12/mvc-file-upload-using-uploadify-with.html

like image 2
James McCormack Avatar answered Nov 08 '22 08:11

James McCormack