Wednesday, October 24, 2007

An Introduction to PageMethods

PageMethods offer a simple way to asynchronously communicate with a server using Microsoft's ASP.Net AJAX technologies.  Unlike Update Panels which utilize the full page life cycle to synchronously update a section of the page based on the panel's triggers, PageMethods handles the transmissions manually through JavaScript.  Since everything is manual, PageMethods take a small amount of additional time to develop; however, provides an additional level of efficiency that cannot be found in UpdatePanels.

In order to begin utilizing PageMethods in your ASP.Net AJAX enabled webpage, you need to do 3 things:
  • Set the ScriptManager's "EnablePageMethods" property to "true".
  • Write Public Static WebMethods in the Code Behind file of the web page that will return the information required.
  • Write JavaScript that calls the PageMethods and reacts to the return results (information or errors).
Setting up the Script Manager
Setting up the ScriptManager to handle PageMethods is fairly straightforward; however, there's one thing that you'll need to be aware of. The "EnablePageMethods" property is only found on the ScriptManager control and not the ScriptManagerProxy control. This means that if you have a Master Page with a ScriptManager control in it used by the Content Page that will contain the PageMethods, you must set the Master Page's ScriptManger control to include the property. Doing such enables all pages that use that master page to be able to use PageMethods. I haven't investigated to see the impact this has on pages that do not utilize PageMethods.

With that out of the way, in order to enable page methods on a page, simply go to your ScriptManager control that's associated with the page and set the "EnablePageMethods" property to "True". This is "False" by default, but once you set it to "True" you're all set.
Writing the Server Code
Now that we can write PageMethods, we need to flip to our code behind files (or our <script runat=server> sections) to begin. Below are the steps that I traditionally follow when creating PageMethods:
  1. Create a new method/function that returns String or value type (Integers, Doubles, Dates, etc.).
  2. Mark the new method as Public Static (or Shared for the VB coders out there)
  3. Import the System.Web.Services namespace
  4. Add the [WebMethod()] (or <WebMethod()>) Attribute to the Function
In a nutshell, I write the method first. This allows me to get the logic in place just in case I need to modify the implementation when I'm in the middle of writing this code. Next, I ensure the proper scope and modifiers are setup on the method, and finally, mark the method as a WebMethod like I would with a web service.

[WebMethod()]
public static string MyPageMethod(string someParam)
{
return "Hello, PageMethods!";
}

When the page loads, the ScriptManager will examine the page's definition for any public static webmethods. It will then generate JavaScript code that is used to call these methods and append it into the ASP.Net AJAX's PageMethods object. This interaction allows our new method to be called from JavaScript by referencing in JavaScript the method of the same name of the PageMethods object ( PageMethods.MyPageMethod(...) in this case - more on this below).

Making the calls with JavaScript

So far we have enabled PageMethods in our ScriptManager and have made some static web methods in our code that the ScriptManager will create JavaScript from. Now, we need to write our own JavaScript code to call these PageMethods so that we can retrieve the information they provide.

In order to create the JavaScript code to call the PageMethods, you simply have to make have 3 things:

  1. The script that calls the PageMethod itself
  2. A function to call on each successful PageMethod call
  3. A function to call when ever there was an error in the PageMethod call.

The code to call the PageMethod is very simple.

function callerMethod() {
PageMethods.MyPageMethod(PARAM1,
PARAM2,
PARAMn,
callerMethod_Success,
callerMethod_Failure);
}

Let's pick this apart now. What we have above is a simple JavaScript function called "callerMethod". Inside of this function, we do a simple call to our method's JavaScript counterpart that got attached to the PageMethods JavaScript object that's included by the ScriptManager. Next, we pass any parameters required (signified by the "PARAM1", "PARAM2", and "PARAMn" in this case) followed by a pointer/name of the method to call on a successful transmission and the same for the failed transmission.

One optional parameter that I've purposefully excluded can appear at the very end is designated for the current UserContext. In a later posting, I will provide more information revolving around this parameter and how to use it to provide more powerful communication models in the code. For right now, we will exclude the parameter because we can.

Now that we've created the call, we need to create the functions that'll be called when the transmission succeeds or fails.

function callMethod_Success(results, userContext, methodName) {
alert(results);
}

function callMethod_Failure(errors, userContext, methodName) {
alert(errors.get_Message());
}

Again, these are very simple methods that do nothing other than alerting the user of the resulting value on success or the error messsage on failure. The names of the methods are completely up to you naturally; however, whatever you name the methods, each require 3 parameters.

The first parameter of is for the returned value or error that the call to the PageMethod created. On success, you can immediately begin using the results as if they were a normal value passed into any regular function (since it's either a String or Number JavaScript type). On failure, the PageMethod and ScriptManage return an object with information about the error. The get_Message() method of the error object will return the error message that was thrown during the transmission. Once you have the resulting value (success or failure), you can then write JavaScript logic to do whatever you want with it.

The second parameter is the userContext. Like previously stated, this will be covered in a future posting. For now, just remember that you can send the userContext to the PageMethod and read the resulting context on the returning trip.

The last parameter of the success and failure methods is the methodName. This parameter provides a simple string that represents the PageMethod name that was called and caused the success or failure function to be triggered. This is a great addition to the returning functions since it allows you to reuse success and/or failure functions across different PageMethods and produce custom logic based on which PageMethod was called. While I can see some merit in having a single success and a single failure (or even 1 function that does both), I wouldnt' want to maintain the if statements that would spawn from such logic.

Summary

While the example code here isn't too useful (like most Hello, World projects), it hopefully will get you started on using PageMethods. In future postings, I'll provide some addition information and techniques that you can use in order to utilize PageMethods by using the UserContext object, identifying more in depth the data types that can and cannot be passed, and also object serialization through JSON. In addition to these items, I'll also be keeping an eye out on any items that may be not quite so obvious when you're work with PageMethods. Down the road a bit, I'll do a very similar post to this about using local WebServices instead of PageMethods and why.

Tuesday, October 23, 2007

The Beauties of PageMethods & WebServices

It's funny. My first experiences with AJAX was back with the old XMLHTTP Post days going to a Java Servlet. I liked the results but hated the implementation. Thankfully the rest of the development community and vendors couldn't either, and now, today, you can't go anywhere without hearing AJAX it seems.

I didn't care too much for Microsoft's ASP.Net 2.0 AJAX implementation. I toyed around with it and like the simplicity of Update Panels; however, I hated the overhead and the synchronous interaction they provided. I was looking for an easy toolkit that I can use w/o having to write a lot of custom JavaScript or focus on writing my own JavaScript toolbox like I felt like I had to with AJAXPro. Luckily, I stumbled upon different features of ASP.Net AJAX; PageMethods and Web Services.

Most blogs about ASP.Net 2.0 AJAX will focus on the uses of Update Panels or controls from the toolkit. However, there's a couple that talk about the ability to do truly Asynchronous calls using PageMethods or WebServices. Under the hood, these appear to be pretty much the same: we public-scoped, static/shared method that can be called using JavaScript once it's class has been registered with the ScriptManager (or ScriptManagerProxy in the case of Master Pages).

With the similarities, there are some differences:

  • Page Methods are Public, Static methods located in the page's class file or in it's <Script Runat=Server> tag.

  • PageMethods are scoped to just the local page. You cannot call a page method of a different page than what you are currently on. (I'm needing to test this further.)

  • Web Services methods allow for a better separation of presentation and control than what a normal code behind structure can provide.

  • You cannot reference a WebService method that is in a different domain than the page. (Cross Domain Scripting has security issues that many modern browsers just shut down now).



With two different technologies, which is the better one to use inside of your application?

For the PageMethods model:


  • Best for smaller projects

  • If time is critical, Page Methods are faster to develop then the WebService Model



For the WebService model:


  • When the same code is needed in multiple locations.

  • Separation of the control logic is desired

  • Projects are larger and tends to find multiple developers working amongst each other's code



In the next post, I'll provide some code snippets on how to get started on each of these technologies.

Monday, October 22, 2007

Beginning of a Different Focus

For the majority of the year, I have been researching and helping my coworkers learn a variety of technologies. This has lead to a lot of opportunities as well as forced me to really take the time and focus on a number of technologies. I've been somewhat bouncing all over the board of technologies on my researching; Regex, CSS, LINQ, AJAX, etc. Going forward, I'm going to be focusing on writing shorter, more focused blog entries in order to provide some value over the random ramblings that I've posted thus far.

Stay tuned.