views:

834

answers:

4

I prefer to use jQuery with my ASP.NET MVC apps than the Microsoft Ajax library. I have been adding a parameter called "mode" to my actions, which I set in my ajax calls. If it is provided, I return a JsonViewResult. If it isn't supplied, I assume it was a standard Http post and I return a ViewResult.

I'd like to be able to use something similar to the IsMvcAjaxRequest in my controllers when using jQuery so I could eliminate the extra parameter in my Actions.

Is there anything out there that would provide this capability within my controllers or some simple way to accomplish it? I don't want to go crazy writing code since adding a single parameter works, it just isn't ideal.

+4  A: 

See Simons answer below. The method I describe here is no longer needed in the latest version of ASP.NET MVC.

The way the IsMvcAjaxRequest extension method currently works is that it checks Request["__MVCASYNCPOST"] == "true", and it only works when the method is a HTTP POST request.

If you are making HTTP POST requests throug jQuery you could dynamically insert the __MVCASYNCPOST value into your request and then you could take advantage of the IsMvcAjaxRequest extension method.

Here is a link to the source of the IsMvcAjaxRequest extension method for your convenience.

Alternatively, you could create a clone of the IsMvcAjaxRequest extension method called IsjQueryAjaxRequest that checks Request["__JQUERYASYNCPOST"] == "true" and you could dynamically insert that value into the HTTP POST.

Update

I decided to go ahead and give this a shot here is what I came up with.

Extension Method

public static class HttpRequestBaseExtensions
{
    public static bool IsjQueryAjaxRequest(this HttpRequestBase request)
    {
        if (request == null)
            throw new ArgumentNullException("request");

        return request["__JQUERYASYNCPOST"] == "true";
    }
}

Checking from an action if a method is a jQuery $.ajax() request:

if (Request.IsjQueryAjaxRequest())
    //some code here

JavaScript

$('form input[type=submit]').click(function(evt) {
    //intercept submit button and use AJAX instead
    evt.preventDefault();

    $.ajax(
        {
            type: "POST",
            url: "<%= Url.Action("Create") %>",
            dataType: "json",
            data: { "__JQUERYASYNCPOST": "true" },
            success: function(data) {alert(':)');},
            error: function(res, textStatus, errorThrown) {alert(':(');}
        }
    );
});
spoon16
So would I pass the __JQUERYASYNCPOST just like any other parameter in my post data when using "$.post"? If so, that would give me the same basic setup without the extra parameter, which would be perfect.
Andrew Van Slaars
Perfect, Thanks!
Andrew Van Slaars
Yes, pass the values in the data parameter of $.post(). I would test first with __MVCASYNCPOST to make sure it works with the existing extension methods. If it does then you can implement your own extension method and change it to __JQUERYASYNCPOST.
spoon16
Thanks again, I just implemented the code in a project I'm working on. Had I looked here again before writing it, I could have just done a copy-paste :)
Andrew Van Slaars
please see my answer below for important changes in RC1
Simon_Weaver
A: 

Ok, I have taken this one step farther and modified my jQuery file to load the additional parameter into the post data, so I don't have to repeat the "__JQUERYASYNCPOST: true" for every call to post. For anybody that's interested, here's what my new definition for $.post looks like:

post: function(url, data, callback, type) {
            var postIdentifier = {};
            if (jQuery.isFunction(data)) {
                callback = data;
                data = {};
            }
            else {
                postIdentifier = { __JQUERYASYNCPOST: true };
                jQuery.extend(data, postIdentifier);
            }

            return jQuery.ajax({
                type: "POST",
                url: url,
                data: data,
                success: callback,
                dataType: type
            });
        }

I added the "postIdentifier" variable as well as the call to jQuery.extend. Now the Helper explained in spoon16's response works without having to add any thing special to my page-level jQuery code.

Andrew Van Slaars
nice... this is one of the most complete QA's on SO :)
spoon16
What if you extended 'ajax()'? Wouldn't that be better as all of the other methods like 'post()' just call through to 'ajax'?
spoon16
I could have extended ajax, but my main concern is post. Typically, I only use get for Ajax if it's an ajax-only feature, such as an autocomplete lookup or similar functionality that wouldn't be available without ajax, so for those things, I use JsonResult anyway.
Andrew Van Slaars
+3  A: 

Why don't you simply check the "X-Requested-With" HTTP header sent automatically by most Javascript libraries (like jQuery) ?

It has the value 'XMLHttpRequest' when a GET or POST request is sent.

In order to test it you should just need to check the "Request.Headers" NameValueCollection in your action, that is :

if (Request.Headers["X-Requested-With"] == "XMLHttpRequest")
    return Json(...);
else
    return View();

This way, you can simply differentiate regular browser requests from Ajax requests.

Franck
Great idea. I am going to refrain from changing my answer so that you can get as much rep as possible :)
spoon16
I wasn't aware that the requested-with header was even there. I will check that out and give it a try, maybe I'll update the extension method to check that instead. Any idea why MSFT wouldn't have done this to begin with?
Andrew Van Slaars
Actually, to my knowledge there is a lack of standardization regarding this topic. All libraries construct their headers differently (some are specifying the library version), but thankfully most have adopted 'X-Requested-With', I can't tell why Microsoft hasn't.
Franck
@sork well they recognize it now since RC1
Simon_Weaver
+11  A: 

Here's an except from MVC RC1 release notes - Jan 2009

IsMvcAjaxRequest Renamed to IsAjaxRequest

The IsMvcAjaxRequest method been renamed to IsAjaxRequest. As part of this change, the IsAjaxRequest method was updated to recognize the X-Requested-With HTTP header. This is a well known header sent by the major JavaScript libraries such as Prototype.js, jQuery, and Dojo.

The ASP.NET AJAX helpers were updated to send this header in requests. However, they continue to also send it in the body of the form post in order to work around the issue of firewalls that strip unknown headers.

In other words - it was specifically renamed to be more 'compatible' with other libraries.

In addition, for anyone who hasnt read the full release notes but has been using previous versions - even as recent as the beta - I STRONGLY recommend you read them in full. It will save you time in future and most likely excite you with some of the new features. Its quite surprising how much new stuff is in there.

Important note: You will need to make sure you upgrade the .js file for MicrosoftAjax.MVC (not the exact name) if upgrading to RC1 from the Beta - otherwise this method won't work. It isn't listed in the release notes as a required task for upgrading so don't forget to.

Simon_Weaver
Thanks Simon, hopefully Andrew Van Slaars will give you the accepted answer.
spoon16
Also, changed my post to community wiki in case others want to update the "Accepted Answer"
spoon16
thanks. i'm sure my answer will be outdated someday too :) i hadn't even HEARD of ASP.NET MVC when you wrote your answer :)
Simon_Weaver