Dienstag, Mai 30, 2006

Visual Studio .NET add-in updated

One of my older projects where updated today.

I missed some commands so I started developing a collection of useful tools that help developing and controlling my work and files. The result was an add-in for Visual Studio that adds commands for comparing files and folders, an explore command, and some useful reports for web projects.

Give it a try at: http://www.codeproject.com/csharp/WebReports8.asp

Sonntag, Mai 28, 2006

Update to the back-button and history implementation

The last past was about implementing a back-button and local history support to the AJAX Engine.

I've added 2 attributes to the PropHistory web control that can be declared to avoid some scripting on the page:

<ajax:PropHistory runat="server" stateList="version,book,chapter" propList="vers" />

stateList specifies the page properties that together form the current state of the page. A change to the value of any of these properties will cause a new entry in the history of the browser.

propList specifies the page properties that are persisted in the hash part of the url so that hyperlinks will work.

The implementation takes care of the fact that all properties in the statList must also be part of the url but you don't have to specify them again in the propList attribute.

The download files where updated today too.

Ajax.zip contains the ASP.NET 2.0 web project that builds the side. The complete AJAX Engine and all samples are included. Use this project when you want to start building your AJAX web application.

AJAXEngine.zip This Zip-File contains the core files of the AJAX engine and the AJAX controls. You can use this if you want to update your project with the updated core files.

Freitag, Mai 12, 2006

Another view to the Back Button Problem of AJAX applications

A lot of people already wrote about this topic. Search "AJAX BACK BUTTON PROBLEM" on a search portal and you can find a lot of stuff about it!

But there are still aspects that haven't been talked about.

Let me explain that the problem is old, well known, not an AJAX specific problem and after all: technically solved.

What the back button does - and why not

Still some people think that the web is a mass of pages pointing to each other using hyperlinks. While navigating along these hyperlinks every visited page is recorded into a local list often called "history". The original idea was to support this list of pages with some functionality.

When framesets came into the browser model this simple idea got the first scratch because when you use hyperlinks that change only the content of a frame the url doesn't change. The url that you can see in the address is not the only information you need to restore a browser situation.

Up to here the back button still works in the browsers, because they also record this extra information together with the url - at least when working with the browser history functionality.

Then there are web servers that found a (not so) wonderful trick to use forms for navigating from one page to another and things get complicated. Hyperlinks can be used to submit the content of a form (including the current browser state) back to the server which then returns the next or the modified page. A problem on this approach is that the same url (main.do, main.aspx, main.jspx, main.php, ...) can be reused for the whole application.

Here the back button also has to record all the data that was posted to the server so it can be re-posted when the user wants to go one or more pages back.

This kind of request cannot in generally be distinguished by the server from clicking the same button of a form twice and often there are filters available on the server to redirect these requests to another page.

And this is why navigating back using the back button of the browser often doesn't work.

And this is why many applications start a new window at the beginning without displaying the navigation bar that includes the back button.

And this is why many users like the back button on the mouse or keyboard (ALT-LEFT).

And this is why the web doesn't work like this (too often).

The favorite problem

As with the history list a very similar problem exists with the favorites and with web urls stored in files. When you save a current page to your favorites list you might think that this helps you coming back to this page but if the server needs post information or the page is built using frames you might become disappointed because this kind of information is not stored in hyperlinks.

The IE implements a special *.url file type that is created when using the IE built in "Add to favorites..." command that contains extra information about the current urls of the frames and maybe more.

But the *.lnk file type that is created when dragging an URL from the IE address bar to the desktop as well as the url file that is created by Mozilla/Firefox doesn't hold this information.

What's the problem?

The problem with the back button existed long before AJAX applications became widely known. The core of the problem is about building a web application that works by using meaningful urls whether using frames or not and enabling the usage of the history and favorites feature of the existing browsers.

AJAX applications do have the same problem like those applications doing everything through a single url: it's meaningless and you cannot rely on any posted information because it just doesn't exist.

So what we all have to do is giving our applications meaningful urls.

Meaningful urls

Not every click should change the url and in many applications there is no clear "back" situation. If you browse your mail inbox for example a click to open a message may be a clear "navigate to" situation. When you delete the message by using a click on a button the main UI might navigate for you to the next message in the list. But where is the "back" position now - on the deleted mail?

You can also argue that moving on to the next mail is neither forward nor back but something like up and down and back will always bring you back to the list view you started.

So what I want to say is that the (forward and) back direction is often very application or problem specific. With AJAX you have the chance to model these situations the way you like and the way that is the best for your application and you are not bound to the GET and POST requests done by hyperlinks and forms.

I use the url as a textual key to the global addressable state of an Ajax application. By moving some information into the url and reading this information out of the url when a page loads or the urls changes, there is a clear interface between the Ajax page and the external world that can be used for storing browser history, favorites and links.

The back problem is technically solved

If you look for a good article on how to implement a technical solution to the problem have a look at the article "AJAX: How to Handle Bookmarks and Back Buttons" by Brad Neuberg at http://www.onjava.com/lpt/a/6293.

... by tricking IE

The Mozilla/Firefox solves this problem really straight forward and it works as expected.

When using the method window.location.replace(newHash) only the current URL is changed.

By assigning a new value to the window.location.hash property a new entry in the history list is created.

The IE is very confused about URL-hash values hat do not really point to existing anchors and does not record any history and needs a invisible iframe with a page coming from the same server. It's a little bit tricky to get all situations working and you can see the current implementation by looking into the JavaScript implementation of the PropHistory Behaviour (view source).

Implementation

The AJAXEngine already has a client side state mechanism (Page Properties or DataConnections) I introduced in September 2005 that stores key-value pairs. Instead of building a new API and leave it to the AJAX application to call a method to change the URL you only have to declare what page properties should be used in the URL. When a Page Property's value changes the URL is updated automatically and when the URL changes all connected controls will get informed about it.

When one of the properties, that define a state that should be persisted to the history changes, a new history entry is recorded.

All you need to do to make it work is to include the PropHistory control:

<ajax:PropHistory runat="server" />

and to declare what properties should be used to form the url (propList) and what subset of these properties should define the state (stateList):

<script defer="defer" type="text/javascript">
  // set default values for the Page Properties, if the value is not in the URL:
  jcl.DataConnections.Load("version", "luther1912");
  jcl.DataConnections.Load("book", "1");
  jcl.DataConnections.Load("chapter", "1");
  jcl.DataConnections.Load("vers", "1");
 
  // declare the properties that should be written to the URL:
  PropHistory.propList = {"version":"","book":"","chapter":"","vers":""};
 
  // declare the properties that are meaningful for history recording:
  PropHistory.stateList = {"version":"","book":"","chapter":""};
</script>

The sample comes from the updated Bible reader application. When you navigate through the verses of a chapter, only the URL gets changed. The navigation to a new book, version or chapter a new entry in the history stack is created.

You now also can use URLs to jump directly to some important content. Donald E. Knuth likes reading any book chapter 3 verse 16 and specially BiblePage.aspx#version=sf_kjv_strongs_rev1b&book=43&chapter=3&vers=16 and an important verse of the upcoming da vinci code movie by Dan Brown is BiblePage.aspx#version=en_gb_KJV2000_1&book=18&chapter=38&vers=11