In this article, however, I want to address another ASP.NET MVC approach to AJAX based on helper components. This approach doesn’t have an official name. In many ways, it's similar to classic ASP.NET partial rendering, but done better. To make a distinction, I’ll call it selective update. In the rest of the article, I’ll discuss the subtleties of using selective update extensively.
The Mechanics of Selective Update
Selective update refers to an application’s ability to refresh only a fragment of the current view in response to some user actions. User actions are essentially of two types: clicking on hyperlinks (known as action links in ASP.NET MVC jargon) and submitting the content of a form.
With action links, a user triggers an asynchronous action on some HTTP endpoint, receives any markup being returned, and uses that to refresh a specific section of the existing view. You can configure the AJAX request to be GET or POST; the composition of the URL determines which parameters are passed to the target.
With AJAX forms, you simply post the content of the HTML form to which the clicked submit button belongs. You can configure the HTTP verb to be GET or POST and include additional parameters (beyond the content of the input fields) at will.
As mentioned, selective update results in an asynchronous request that is controlled via some script code injected by the framework. The script code lives in the MicrosoftMvcAjax.js file that is automatically included in any new ASP.NET MVC project you create in Visual Studio. The following code shows the script tags you need to incorporate in any page that uses selective update. This code snippet downloads the scripts from the Microsoft CDN, but you're free to modify the URL to suit any of your more specific needs.
An AJAX form in ASP.NET MVC looks like the code Figure 1 shows. The form markup is generated using the Ajax.BeginForm helper method and posts the content of the form to the Update method of the current controller. (The helper offers an additional overload for you to also specify the name of the target controller.)
The form submission request executes according to the specified options. In particular, based on the code Figure 1 shows, a user will see an update progress screen during the operation and a particular segment of the user interface will be replaced at the end. Figure 2 shows the markup generated by the code in Figure 1.
The OnComplete function is invoked before the outcome of the operation is determined; the function fires regardless of whether the next call will be for OnSuccess or OnFailure. You can programmatically stop the AJAX request in either of two ways. If you assign a value to the Confirm property of the AjaxOptions class, ASP.NET MVC will display a confirmation message box. By clicking Cancel, the user stops the operation. In addition, by writing a handler for OnBegin that returns false you tell the framework not to proceed with the operation.
Transforming an ASP.NET MVC application into an AJAX application is not a hard task; it can be summarized in two steps. First, you turn all HTML forms into AJAX forms using the AJAX BeginForm helper and its options. Second, if the default behavior you get out of it is not exactly what you want, use client-side events to alter it as you wish.
However, in doing so, sooner or later you'll run into some snags. The following code illustrates the standard structure of a controller method when you employ AJAX calls:
public ActionResult Insert(InsertInputModel inputModel)
var model = GetInsertViewModel(inputModel);
The AjaxOnly attribute (shown below) is a custom one you can use to ensure that the given method is only invoked via AJAX. The PartialView method loads a user control and builds a view object that contains a chunk of HTML instead of an entire page. This is an easy way to handle AJAX calls especially when you have master pages around.
public class AjaxOnlyAttribute: ActionMethodSelectorAttribute
public override Boolean IsValidForRequest(
ControllerContext controllerContext, MethodInfo methodInfo)
Now let’s review some of the challenges you might run into when using AJAX with ASP.NET MVC.
Handling Failures Effectively
The AJAX infrastructure you find in ASP.NET MVC offers two distinct callbacks to handle success and failure of a request. These callbacks might seem sufficient, but let's say you have a view that contains a classic HTML form and a submit button. All you want to do is post any content asynchronously and refresh a particular DIV in the page with any response. What should you do in case of a server error?
The difficulty occurs if you need to apply a different behavior on the client for success and failure. In an AJAX scenario, a successful operation likely requires that you display a temporary message to notify success and then route the user to the next screen. In case of failure, you want to display the message and stay on the current page.
To solve the issue, I created a new action result class (Figure 5) that operates like a standard view result—except that it allows you to set the HTTP status. Figure 6 shows how you use this action result class. The action result object will take the specified view, populate it with the response object (it's a custom class that typically contains a Boolean flag and error information), and return the final markup.
Detecting Cookie Expiration
In classic ASP.NET, you're allowed to have protected pages that only authorized users can access. In ASP.NET MVC, the same underlying mechanism is exposed through the Authorize attribute. The feature works well, except when you have a lot of AJAX requests in the application and the authentication cookie expires.
If you place a non-AJAX request, and the authentication cookie has expired (i.e., the timeout is set to just a few minutes and the user leaves his desk), you run into some problems. On the next request, the mechanism detects the cookie is invalid and correctly redirects you to the specified login page. Unfortunately, the login markup is sent in the context of an AJAX call so it likely will end up being inserted in any DOM location where the original response was expected. The solution consists of adding code to the method that will display the login view. The sample method below produces a view with a login box:
public ActionResult Index(String returnUrl)
return RedirectToAction("Relogin", "Account");
If the login URL is invoked with the return URL parameter set, and the application is only doing its work with AJAX, then you can conclude that you need to return just the login box instead of the classic login page. You redirect to an AJAX login page that outputs markup like that shown below:
You need to reconnect
<a href="/home/index"> Click here to log in again </a>
This message will appear no matter what the user does after the authentication cookie expires. To log back in, a user simply follows the link. If you’re using both AJAX and HTML requests, things are trickier and you have to track in some way whether or not the original request is AJAX. Checking the Request object from a method like Index won’t work because that request has been originated as HTTP 302 and doesn’t natively contain any specific AJAX header.
Another common issue you might encounter when using AJAX in ASP.NET MVC is updating multiple segments of the view after an async request. To address this issue, though, some modifications are required to the AJAX programming interface of the entire MVC framework. You can find your way to that by serving your own copy of the MicrosoftMvcAjax.js file, or you can wait for MVC3, where this feature is expected to be addressed.