Tuesday, May 06, 2008

Optimization Tips: Using RadAjaxManagerProxy Controls

In this installment of my ongoing series covering RadControls for ASP.NET AJAX optimization tips, I am going to take a short break from talking about how to optimize your page performance and instead cover a tip that will help you optimize your code. Specifically, we're going to take a look at the RadAjaxManager and the RadAjaxManagerProxy controls to see how they enable you to very easily ajaxify all parts of your application.

The ASP.NET AJAX Era
Long before ASP.NET AJAX was a gleam in Microsoft's eye, Telerik was providing robust Ajax tools to its customers. Telerik developed a full Ajax framework that made it very easy to implement Ajax in ASP.NET applications, the cornerstone of which was the RadAjaxManager control. When we began making the transition to ASP.NET AJAX, though, we decided to completely leverage Microsoft's framework in our RadAjax product. We wanted to deliver all of the time-saving benefits of the RadAjaxManager at design-time while relying on ASP.NET AJAX at run-time.

Needless to say, the RadAjax product that exists now does exactly that. It is built completely on ASP.NET AJAX and delivers all of the power of the Microsoft framework through Telerik's award winning tools. But the new RadAjax does more than change the underlying technology handling the Ajax "magic"; it also makes your Ajax configuration easier than ever.

The Old Days
Before RadAjax for ASP.NET AJAX, the task of defining Ajax settings in site's that utilized MasterPages and UserControls (read: almost all sites) was...a bit of a challenge. If you wanted the benefits of the AjaxManager's visual configuration tool (or even in-page IntelliSense mark-up), you had to place a RadAjaxManager on every ContentPage. This worked to a point, but if you wanted to also ajaxify controls on MasterPages, you were stuck with two RadAjaxManagers that wanted to control the same rendered page. To solve the problem, you could put a RadAjaxManager on your MasterPage, but then all settings in your ContentPages and UserControls had to be made programmatically- a laborious and code-cluttering requirement.

Enter the Proxies
With the advent of ASP.NET AJAX, Microsoft introduced the ScriptManager control. This control must be present on any page that uses ASP.NET AJAX and- like the RadAjaxManager- can only be on the page once. To work around the problem of ContentPages and UserControls, the ScriptManager introduced a companion control called the ScriptManagerProxy. This control enables developers to define settings for the primary ScriptManager that are rolled-up in to the primary manager at runtime.

RadAjax for ASP.NET AJAX mimics that architecture. You can now easily define a single RadAjaxManager in your application's MasterPage and then add RadAjaxManagerProxy controls to all ContentPages and UserControls. At runtime all settings in the proxies are rolled-up to the primary RadAjaxManager, but at design-time you get all of the benefits of Source View IntelliSense and the RadAjaxManager visual configurator. See Slide 1 of my embedded Google Presentation (below) to see this layout illustrated.



By utilizing the RadAjaxManager and RadAjaxProxy controls, you greatly simplify your ASP.NET AJAX ajaxification process. First, you don't have to clutter your markup with the UpdatePanels normally required by ASP.NET AJAX, making your code easier to maintain and read. Next, you don't have to manually think through how Triggers should be defined on your UpdatePanels. The RadAjaxManager automatically figures that out based on your simple definition the controls that should be updated after specific control events fire. And finally, RadAjaxManager provides a complete client-side API that makes it easy to perform advanced ASP.NET AJAX operations without having to write a lot JavaScript manually.
Client-side Support
Among the client-side support that the RadAjaxManager offers is the definition of two JavaScript events you can subscribe to: OnRequestStart and OnResponseEnd. You can see the code required to wire-up these client-side events on Slide 2 of my embedded presentation deck (see above). The events are very handy if you want to do anything on the client (such as validation) before an Ajax event fires. You can even cancel an Ajax request before it fires.

This is an extremely easy way to take more control over your application's Ajax, but what if you want to customize the JavaScript events that handle Ajax settings in your Proxy controls? Since the Proxy controls are not actual instance of RadAjaxManager, they do not expose ClientSettings directly. Instead, you need to work a little JavaScript magic to provide custom client-side event handlers for your primary RadAjaxManager that only handle controls ajaxified by your proxy.

Handling Client Events in UserControls
You recall that all ajax settings in the Proxy controls are rolled-up to the primary RadAjaxManager at runtime. That means there is only one point to define the JavaScript events that fire on Ajax requests: the primary RadAjaxManager. You cannot define JavaScript events for each Proxy control. You can, however, change the JavaScript events defined on the primary Manager in the PageLoad of any ContentPage or UserControl.

To change the events defined in the RadAjaxManager, the code shown on Slide 3 of my presentation should be added to the PageLoad event. Notice that the RadAjaxManager class exposes a very handy "GetCurrent" method that makes it very easy to get a reference to our primary RadAjaxManager from any position in our application (on a ContentPage, UserControl, etc.). With a reference to our primary Manager, we can quickly set the OnRequestStart and OnResponseEnd event names (just simple strings).

But wait! Now what happens when an ajax event defined in our MasterPage fires? It travels through our new JavaScript event handlers in our UserControl. That's no good. We only want controls ajaxified by our Proxy to get handled by our new JavaScript event handlers. Is there any way to "route" ajax events triggered in our UserControl to one set of JavaScript event handlers and ignore other ajax events? Yes, sorta.

Route the Events
Since there can only be one active set of JavaScript functions that handle RadAjaxManager client-side events, we have to manually provide support for "routing" events to the proper JavaScript functions. We can do this by inspecting the EventTarget property of the eventArgs passed to the OnRequestStart JavaScript function. That property will contain the full ClientID of the control that initiated the Ajax event. For example, if our button is located in UserControl "ProxyUserControl" on page "Default" in a MasterPage, we might see an ID like:

ctl00$ContentPlaceHolder1$ProxyUserControl1$btnUpdateTime

Ah hah! We have a way to tell where the Ajax event came from. By using some JavaScript to see if our UserControl name exists in this EventTarget string we can correctly route the RadAjaxManager client events. See Slide 4 in the embedded presentation for a complete look at the JavaScript code that handles this routing.

Gotchas
While this is a great solution for enabling custom handling of the OnRequestStart and OnResponseEnd events in UserControls, it does require a couple of assumptions that make our code a little brittle. First, you must know the names of the OnRequestStart and OnResponseEnd JavaScript functions in your MasterPage and you must assume those functions are present. Second, you must know the name of your UserControl so that you can correctly detect if the current Ajax event was fired from within the UserControl. Other than that, you're good to go.

Optimization Tip Summary
So what have you learned today? A few key points:

  • RadAjax for ASP.NET AJAX implements ASP.NET AJAX (not proprietary Ajax). Spread the word.
  • You can (and should) use RadAjaxManagerProxy controls to define Ajax settings in ContentPages and UserControls
  • You can use JavaScript to "route" OnRequestStart and OnReponseEnd events to different client-side functions by interrogating the EventTarget property of the eventArgs
Hope this helps you develop ASP.NET AJAX-enable applications faster than ever and gives you the tools you need to take exacting control over your Ajax behavior. In the next installment in this series, we'll resume with our look at techniques that improve your page load performance when using the RadControls for ASP.NET AJAX.

10 comments:

Asit said...

Is it advisable to have just one script manager (MS or Telerik) or both? Will they clash?

Todd Anglin said...

Asit-

As far as the ScriptManager is concerned, you can only have a Telerik RadScriptManager or a standard ASP.NET AJAX ScriptManager. You cannot use both at the same time.

The RadScriptManager is essentially a wrapped version of the standard ScriptManager with special code for combining the RadControl script resource links.

-Todd

Asit said...

So it's better to use RadScriptManager instead of ScriptManager to get more functionality. And more importantly, without losing any functionality. That's good to know. I have ScriptManager in my Master Page. Maybe I should replace it with RadScriptManager.

Todd Anglin said...

Definitely! Check out my previous post on this exact topic to see the gains you get for making the switch:

The Rad Managers

-Todd

Asit said...

What happens when MS releases a new version of AjaxManager? Now I have a situation where RadAjaxManager is out of sync with AjaxManager.

Todd Anglin said...

Asit-

I think you may be confused. This post is covering the RadAjaxManager, a control that Microsoft does not offer.

The other post I referenced covers the RadScriptManager, a control that replaces the standard ScriptManager control.

That said, you don't have to worry about these getting out of sync. MS doesn't release new versions of controls/frameworks very often at all, and when they do, Telerik is well prepared ahead of time with any necessary changes to our version of the control so you can transition seamlessly.

-Todd

Asit said...

:)

You are absolutely right. The alphabet soup got me.

Joshua Starr said...

Great article! The optimization benefits are hard to ignore, thanks for the overview.

The Telerik Robot is pretty leet, you should make a schwag plushy of it for conferences.

Anonymous said...

So, if I put RadScriptManager insteadof ScriptManager in my master page, what do I use t add scripts to my inherited pages? That is, now I'm using ScriptManagerProxy which is MS. Is there a RadScriptManagerProxy?

Todd Anglin said...

@Peter- You can use the normal ScriptManagerProxy with a RadScriptManager as the parent. Please see this forum thread for similar info: http://www.telerik.com/community/forums/thread/b311D-behhgg.aspx

Hope that helps!