views:

1199

answers:

3

I'm using the JQuery Form plugin to do a file upload on an ASP.NET MVC application. I've learned that since an iframe is used for file uploads (rather than XMLHttpRequest, which isn't possible), the server-side check for IsAjaxRequest fails.

I've seen a few posts related to this question but haven't come across any good solutions to work around this issue. As with the rest of my application, I'd like to be able to support both JavaScript enabled and JavaScript disabled scenarios, which is why I'd like to detect whether a request is ajax or not.

I realize that the iframe approach being used is not technically ajax, but I'm trying to mimic an ajax effect.

Any suggestions would be welcome.

+2  A: 

You need to set the "X-Requested-With" header for the IsAjaxRequest method to return true. Here's how you do it in jquery.

$(document).ready(function() {
     jQuery.ajaxSetup({
          beforeSend: function (xhr) {
                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                return xhr;
          }
     });
});
zowens
The JQuery Form plugin doesn't use XMLHttpRequest for file uploads. It uses an iframe.
goombaloon
+1  A: 

I just realized I totally did not answer the question, so I am adding to the top here, and leaving my old answer below:

The problem is when posting a file over an iFrame, the "X-Requested-With" header is not set and you cannot set specific request headers for a normal form POST in Javascript. You'll have to resort to other tricks, like sending a hidden field with your POST that contains a value, and then change or override the "IsAjaxRequest" extension method to also check for this condition. How to override an existing extension method?

Probably the best option would probably be to include your own extension method with a different name, based off the default MVC extension method code with the changes to detect your iFrame upload POST, and then use your extension method anywhere where you expect to need it.


jQuery actually sets the 'X-Requested-With' header to 'XMLHttpRequest' by default. It is quite useful as long as you are careful to do all your AJAX calls over jQuery.

Depending on your needs, it's easy to setup the detection in an action filter to use it where needed, or even build it into a controller class like so:

[jQueryPartial]
public abstract class MyController : Controller
{
   public bool IsAjaxRequest { get; set; }
}

The ActionFilterAttribute:

public class jQueryPartial : ActionFilterAttribute  
{  
    public override void OnActionExecuting(ActionExecutingContext filterContext)  
    { 
        // Verify if a XMLHttpRequest is fired.  
        // This can be done by checking the X-Requested-With  
        // HTTP header.  
        MyController myController = filterContext.Controller as MyController;
        if (myController != null)
        {
            if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != null
                && filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
            {
                myController.IsAjaxRequest = true;
            }
            else
            {
                myController.IsAjaxRequest = false;
            }
        }
    }
}

And using the implementation:

public class SomeController : MyController
{
    public ActionResult Index()
    {
          if (IsAjaxRequest)
               DoThis();
          else
               DoThat();

          return View();
    }
}
Jay
In your code, IsAjaxRequest is always true, defeating the purpose of the code.... plus that's the same functionality that exists in the extension method... so that really doesn't help you out.
zowens
Thanks for the information. Following your lead, I ended up dynamically adding a hidden form value ("isFileUploadAjaxPost") via JQuery. In the controller, I check for that form variable. If it is present, I use TempData to store this value before calling RedirectToAction to display the "edit" view for the newly uploaded file. In the receiving action method, I check both Request.IsAjaxRequest() (as I've been doing all along) as well as my TempData value to determine if the request is "ajax" or not. Works great. Thanks!
goombaloon
@zowens: I fixed the code now, but yes, I realized after making it and then looking at the IsAjaxRequest extension method that is exactly the same. I adapted the code from an ActionFilter that dynamically sets the master page based on the request type which of course is somewhat less redundant than the above code.
Jay
A: 

I just stumbled across this question and later found better solution, so here it is(for everybody who gets here from google):

jQuery form plugin has two options that might help in this case..

1) if you are using post request, it seems that it is always using the iframe, so if you don't need file uploads, setting iframe = false in the Form options helped in my case.

2) If you need iframe for fileuploads, you can use data property of the options to fool the IsAjaxRequest() setting : data: { "X-Requested-With": "XMLHttpRequest" }.

Full script with both options looks like that: $('#someform').ajaxForm( { dataType: 'json', success: onSuccess, error: onError, iframe: false data: { "X-Requested-With": "XMLHttpRequest" } } );

jhexp