AJAX Panels with ASP.NET MVC
(
Jul 22 2008 - 08:10:10 AM by
Timothy Khouri) - [
print article]
ASP.NET MVC Preview 4 brought a bit of AJAX support, which is a natural fit for the MVC design pattern. This article will show how incredibly easy it is to create "lazy loading AJAX panels" with ASP.NET MVC.
First, Issues with "ASP.NET AJAX"
Because "Web Forms" (traditional ASP.NET) is based around each 'Page' containing both the presentation layer and the code behind, ASP.NET AJAX wasn't able to shine as it should have. Most ASP.NET developers who branched out into AJAX were just randomly placing "UpdatePanels" in their pages to make the page 'look' like it has AJAX support. Really, this is only preventing the page from 'flickering', but the page is still doing a full post-back; and it's still going through the entire page life cycle.
This is not to say that the problem lies with ASP.NET AJAX, but rather the issue comes from the different mentality that is needed to use AJAX to the full. To be fair, there are much better options with ASP.NET AJAX than using the UpdatePanel control. This includes:
- Page Methods - Directly calling methods that live in the code-behind of the page (on the server).
- Web Services - Calling methods that live in web services in your application.
These two options are "better" than using the UpdatePanel in that they don't require you to re-load the entire page just to render some HTML back to the client. But they are "worse" in that you now have to implement all of your presentation logic in JavaScript (which is horrible, don't let anyone tell you otherwise).
MVC AJAX Saves the Day
Wouldn't it be amazing if you could get all of the rendering power of ASP.NET as if you were using an UpdatePanel *AND* all of the clean code separation and performance as if you were consuming web services? Well, thanks to the nature of the MVC design pattern - and thanks to ASP.NET MVC - you can!
Let's take a look at a real-world problem of creating 'lazy loading' AJAX panels. We'll assume that we have a web application that delivers some heavy reports back to the client. If we didn't use AJAX, then each report would add to the overall load time of the page. Instead, we're going to request each report asynchronously (using AJAX), so that the page itself will load instantly, and each report will be displayed as soon as it's finished running.
Basically we're going to create a page that has 4 'reports' on it. Each report will take between 3 to 5 seconds to run. So if we were using traditional Web Forms, this page would take about 12 to 20 seconds to load. But because of MVC, we'll cut that time down to about 5 seconds, and still get a beautiful looking page.
There is one important note here. The above performance gains will be limited by a few factors. You still have to take into account the fact that the server will need to process all of these requests, which could slightly slow down the end result. Also, most browsers only allow 2 simultaneous downloads at a time, so you're savings would only amount to about 50% in this instance above.
Using the Ajax.Form Method
MVC Preview 4 added a few methods inside of the "this.Ajax" field for all MVC Pages and MVC User Controls. The "Ajax.Form" method is just like the "Html.Form" method, but it adds a little JavaScript help to ensure that the request is sent asyncronously. Also, there is the ability to define an HTML element that the results of the post should come back to.
For instance, if you wanted to post to some sort of 'send email' action, and have the server put the text "Your email has been sent" inside of a <div> with the ID of "resultDiv", then you would do this:
<div id="resultDiv"></div>
<% using (Ajax.Form("SendMail", new AjaxOptions { UpdateTargetId = "resultDiv" })) { %>
<% } %>
That code above will build the following <form> tag:
<form action="/Home/SendMail" onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, { insertionMode: 0, updateTargetId: 'resultDiv' }); return false;">
</form>
As was mentioned above, this is very similar to the form that would be built by the "Html.Form" method, but as you can clearly see there is an 'onsubmit' method that will instead send the request using AJAX. Also, you can see that our 'resultDiv' parameter is being passed to the server.
Keep in mind that the server will receive the request just like normal, and it will send the requested data back just like normal. The magic that happens is inside of ASP.NET MVC. The response that comes back from the server will be put inside of our <div> and the rest of the page will remain untouched.
This is true, simple AJAX at its best. However, an issue that you may have already figured out is that the form will only contact the server when the user specifically 'submits' the form with a submit button (<input type="submit">). So to solve that, we are going to add a line of JavaScript right after our form that will automatically submit the form and begin the asynchronous request for our reports. I'll also need to change the "Form" method a little to add an HTML ID so that I can access it in JavaScript.
Here's what our new code will look like:
<div id="resultDiv"></div>
<% using (Ajax.Form("ReportOne", null,
new AjaxOptions { UpdateTargetId = "resultOne" },
new { id="reportFormOne" })) { } %>
<script type="text/javascript">
$get("reportFormOne").onsubmit();
</script>
This above code could be a little simpler if I just directly called the 'Sys.Mvc.AsyncForm.handleSubmit' method. But I chose to allow MVC to build my form for me and then to access it via JavaScript so that if JavaScript method changes in the future, I'm still covered.
Show Me The Results!
Using the methods above, and adding a simple "loading gif" that I got from the internet, we now have a page that dynamically (and asynchronously) loads my reports and displays them back to the user as soon as possible. Here are a few screen shots of the end result:
Here is the source code for the above project. Remember, this was written and compiled against ASP.NET MVC Preview 4, and may no longer be completely relevant by the time you're downloading this: SingingEels_MVC_Asyncronous_AJAX_Panels.zip