Building the User Interface for an ASP.NET AJAX Client-Centric Wiki Application

In the last article, we began to put together a client-centric wiki application based on MS AJAX and ASP.NET. In this article, the second of four parts, we will take a look at the user interface, especially for logging in and registration, and at managing article categories.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 7
October 10, 2007
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

A downloadable .rar file is available for this article.

Asynchronously Logging into the System and User Management

Let's now take a first look at how the login functionality is accomplished.

User Interface

Ideally, we'd better arrange the login support as a part of the homepage and achieve the login operation asynchronously, which makes sense because users are able to log in from anywhere. Although I've put the login part in an individual page, you can very easily move it into the homepage.

Now, after starting up the application and clicking the Login button at the upper left corner of the homepage (default.aspx), a traditional login page will appear before us. The following Figure 7 gives one of the related runtime snapshots.

Figure 7-one of the runtime snapshots of the login page.

Note here, to test the logout functionality, we deliberately have not navigated the valid user to the homepage but left him/her at the "login.aspx" page so as to let him/her select to log out of the system or enter the homepage.

Another point that should be noticed is that in this sample any user opening the homepage has the ability to view the articles and all their related posted comments. However, only the validly logged in users (automatically assigned the role of "contributor" by the system) can write new articles and post comments to the present articles.

Client-side Programming

When you look into the code for this page, you'll find the markup associated with our Login and Logout button, which looks like this:

<a href="<%= ResolveUrl("~/Register.aspx") %
>">Register</a>&nbsp;&nbsp;

<button id="ButtonLogin" onclick="OnClickLogin();"
class="mybutton" >Log in</button>&nbsp;

  <button id="ButtonLogout" class="mybutton"

   onclick="OnClickLogout();" style="visibility: hidden;">

    Log out</button>

<a id="backhome" href="<%=ResolveUrl("~/Default.aspx") %>"
style="visibility: hidden;">Back to Home Page</a>

.....(omitted)

 

You can see that when you click the Login button, it calls the "OnClickLogin();" script. Below is the related code snippet:

  function SetDefaultLoginCompletedCallBack(){.....(omitted)}

  function SetDefaultLogoutCompletedCallBack(){.....(omitted)}

  function SetDefaultFailedCallBack(){.....(omitted)}

  function OnClickLogin() {

   SetDefaultLoginCompletedCallBack();

   SetDefaultLogoutCompletedCallBack();

   SetDefaultFailedCallBack();

Sys.Services.AuthenticationService.login($get('username').value,

$get('password').value, false,null,null,null,null,"User
Context");

}

  function OnClickLogout(){

//clear the authentication related cookie and log off

Sys.Services.AuthenticationService.logout(null, null, null,
null);

}

..... (Omitted)

  function OnFailed(error, userContext, methodName)

{..... (Omitted)}

  function OnLogoutCompleted(result){ .....(Omitted)}

As advised in the official materials, we've first specified three default callback functions for the subsequent authentication service. Next, we call Sys.Services.AuthenticationService.login to try to log into the system using the passed parameters. The following shows the detailed signature for the  Sys.Services.AuthenticationService.login method.

Sys.Services.AuthenticationService.login(userName, password,

  isPersistent, customInfo, redirectUrl,

   loginCompletedCallback, failedCallback, userContext);

Since the parameters are self-explanatory and the online materials have provided detailed information, we will not spend any more time on this. From the above code listing, however, you can easily singled out the most interesting and important parameter-loginCompletedCallback, which is a pointer attached to the callback function that is invoked when the login completes. Here is its related code:

function OnLoginCompleted(validCredentials,userContext,
methodName)

{

  if (validCredentials == true)

{

  $get('loggingInMsg').style.visibility = "visible";

  $get('loginFailureMsg').style.visibility = "hidden";

  $get('buttonLogin').style.visibility = "hidden";

  $get('buttonLogout').style.visibility = "visible";

  $get("backhome").style.visibility = "visible";

  $get("logoutOK").style.visibility = "hidden";

//window.setTimeout("window.location.href('default.aspx')",
2000);

}

  else{

   $get('loggingInMsg').style.visibility = "hidden";

   $get('loginFailureMsg').style.visibility = "visible";

   $get('buttonLogin').style.visibility = "visible";

   $get('buttonLogout').style.visibility = "hidden";

   $get("backhome").style.visibility = "visible";

   $get("logoutOK").style.visibility = "hidden";

 }

}

Apparently, when the calling succeeds we give the user two choices: going back to the homepage, or logging out of the system by clicking the Logout button. Of course, you can uncomment the above line "window.setTimeout..." to navigate the valid user to the homepage. You see, all of the underground work has been hidden by the developers by leveraging merely one static class: Sys.Services.AuthenticationService. However, from the client-side JavaScript, with this class we can easily achieve the aim of authentication using the standard ASP.NET 2.0 membership application service.

There is also one point here worth noticing. Unlike the early Atlas July Preview in which there was another method - validateUser provided by Sys.Services.AuthenticationService -- for the developers themselves to validate the user (establishing their identity and permissions), in the present ASP.NET AJAX 1.0 method, validateUser is removed, letting the system or elsewhere perform these tasks. This is comprehensible because safety is always the most important task in real applications.

As with the traditional ASP.NET 2.0, to enable the login functionality and forms authentication there is a lot of other work to do, such as enabling the Authentication Service via web.config, making sure the browser has cookies enabled, configuring access to the Membership database via machine.config file, and creating roles, their related users and specifying their accessing rules via the ASP.NET Web Site Administration tool. However, to make a long story short, we omit all of these things but recommend you research carefully into the web.config file accompanying the source code, as well as refer to the online tutorial titled "Using Forms Authentication with ASP.NET AJAX."

Registration

Registration should always be the first step to using a web system before logging into it. Ironically, however, there does not currently exist ready registration support in the MS AJAX framework. Therefore, we have to resort to the traditional and rather elegant ASP.NET 2.0 server control CreateUserWizard to accomplish this task. The following Figure 8 shows the related runtime snapshot for the registration.

Figure 8-the runtime snapshot for the registration.

There is nothing special to be emphasized here since all the related things derive from the common ASP.NET 2.0 supports.

Author's Note: in this example, by using the ASP.NET Web Site Administration tool we have created two types of roles, Admin and Contributor, and three users: "Mike" with both roles and "a" and "b," both with only a Contributor role, whose password are all pass@word. Only a member with the Admin role has the ability to edit article categories as well as author articles. A member with the Contributor role can only write new articles and post comments to the articles on the website. Passing travelers can only view the article categories and the article details in which they are interested. In addition, any newly-registered user, by default, is assigned a Contributor role.

Next, let's research the really interesting things.

Managing the Article Categories

This part belongs to the background management. Therefore, we put all the related pages under an individual folder, named Manager. Because this part is programmed using the typical MS AJAX client-centric solution we will elaborate on it.

The UI and Client-side Coding

The following Figure 9 shows the client UI for the article category editing.

Figure 9-a typical UI design for the article category editing.

The topmost part of the page includes the MS AJAX server control ScriptManager which is a must have for any MS AJAX-based page. The long and narrow rectangle below this is the MS AJAX client-side advanced control named ListView, which is leveraged to exhibit all the article category records, which can nearly accomplish the functionality of the famous GridView server control supported by ASP.NET 2.0.

The large rectangle area at the lower part corresponds to the MS AJAX client-side advanced control named ItemView, which shows the detailed information of each article category record. You can also compare it with the DetailsView control supplied by ASP.NET 2.0. The six buttons below the ItemView control are responsible for handling the above two views.

Now let's look more closely into how the MS AJAX client-side control named ListView is bound to the client-side DataSource control, which is in turn bound to the server-side Web Service via the MS AJAX Web Service Bridge.

Let's start by looking at the crucial HTML code associated with the ListView control.

<div id="topListView">

</div>

 <div style="visibility: hidden; display: none">

 <div id="masterTemplate">

  <table border="1" cellpadding="3">

   <thead>

 <tr>

  <td><a href="#" id="sortId">CategoryID</a></td>

  <td ><a href="#" id="sortName">CategoryName</a></td>

  <td><a href="#" id="sortDescription">CategoryDes</a></td>

 </tr>

</thead>

 <tbody id="masterItemTemplateParent">

  <tr id="masterItemTemplate">

   <td><span id="txtCategoryId"></span></td>

<td style="width: 275px"><span id="txtCategoryName"> </span></td>

<td style="width: 462px"><span id="txtCategoryDes"> </span></td>

 </tr>

</tbody>

</table>

</div>

  <div id="NoDataTemplate"></div>

</div>

Here we define two important <div> elements. The first <div> element is topListView, which will be used to contain the rendered results. The second is masterTemplate, which defines the template for how the data will appear. In addition, the inner part <table> element is used to hold the concrete records. Both of these <div> elements will have MS AJAX client controls mapped to them.

Let's continue to look at the MS AJAX script code that maps to these elements and binds to the data source.

<script type="text/xml-script">

<page xmlns:script="http://schemas.microsoft.com/xml-
script/2005">

  <components>

<dataSource id="CateDataSource"
serviceURL="../MyDataService.asmx" />

 <dataView id="view">

 <bindings>

  <binding dataContext="CateDataSource" dataPath="data"
property="data"/>

 </bindings>

</dataView>

<listView id="topListView"
itemTemplateParentElementId="masterItemTemplateParent" >

 <bindings>

  <binding dataContext="view" dataPath="filteredData"
property="data"/>

</bindings>

 <layoutTemplate>

  <template layoutElement="masterTemplate"/>

 </layoutTemplate>

 <itemTemplate>

  <template layoutElement="masterItemTemplate">

  <label id="txtCategoryID">

   <bindings>

    <binding dataPath="CategoryID" property="text"/>

   </bindings>

  </label>

<label id="txtCategoryName">

  <bindings>

  <binding dataPath="CategoryName" property="text"/>

</bindings>

</label>

<label id="txtCategoryDes">

 <bindings>

 <binding dataPath="CategoryDes" property="text"/>

</bindings>

</label>

</template>

</itemTemplate>

  <emptyTemplate>

   <template layoutElement="NoDataTemplate" />

</emptyTemplate>

</listView>

<control id="sortId">

  <behaviors>

   <sortBehavior dataView="view" sortColumn="CategoryID"/>

  </behaviors>

</control>

  <control id="sortName">

   <behaviors>

    <sortBehavior dataView="view" sortColumn="CategoryName"/>

   </behaviors>

  </control>

   <control id="sortDescription">

    <behaviors>

     <sortBehavior dataView="view" sortColumn="CategoryDes"/>

    </behaviors>

  </control>

....................................... (Omitted)

<application>

  <load>

<invokeMethodAction target="CateDataSource" method="load" />

  </load>

</application>

</components>

</page>

</script>

You can see at the bottom of the script that the action to invoke upon the application loading is the load method of the DataSource control CateDataSource. This will bind the data source to the above data service and call the load method, which returns all the available records.

Why do we define a DataView control here? To solve this riddle, please look at the following first:

<dataView id="view">

  <bindings>

   <binding dataContext="CateDataSource" dataPath="data"
property="data"/>

  </bindings>

</dataView>

<listView id="topListView"
itemTemplateParentElementId="masterItemTemplateParent" >

  <bindings>

   <binding dataContext="view" dataPath="filteredData"
property="data"/>

  </bindings>

......... (Omitted)

<control id="sortId">

  <behaviors>

   <sortBehavior dataView="view" sortColumn="CategoryID"/>

  </behaviors>

</control>

  <control id="sortName">

......... (Omitted)

The answer now becomes clear. Here we use the client-side DataView control together with the built-in behavior named SortBehavior to sort the content in the ListView control. After everything is Okay, click any column header, as you work with a common Windows desktop ListView control, and you will see the contents in the ListView control are sorted in ascending or descending order.

Next, if you remember the above HTML, there was this peculiar-looking tag:

<div id="topListView">

</div>

It seems pretty odd that there would be a <div> element on a page that contains nothing. Don't worry; all is explained when you look at the ListView control as defined in the script which wraps this underlying <div> element, as you can see here:

<listView id="topListView"
itemTemplateParentElementId="masterItemTemplateParent" >

The target element for the ListView control is specified as topListView, which means the underlying <div> element, which appears empty, will be treated by MS AJAX as a ListView control. This list will use an item template to define its contents. The item template is called masterItemTemplateParent. Additionally, the bindings for the ListView control are set up, and in this case, please note, the control is being bound to the DataView control rather than the DataSource control.

<bindings>

<binding dataContext="view" dataPath="filteredData"
property="data"/>

</bindings>

By setting the dataPath to filteredData, we are binding to the filteredData property that is being exposed by the DataView control. Note this property can return the dataset that has been filtered by DataView. It binds it to the data property of the ListView control.

When the data property is set on a control, as is the case with the ListView control here, template properties can then be bound to the local data property, and the columns on that property can be specified using the dataPath property. So the following item on the template will create a <label> element that is bound to the CategoryName column on the data property of the parent control, which in this case is bound to the CategoryName column on DataView:

<label id="txtCategoryName">

  <bindings>

   <binding dataPath="CategoryName" property="text"/>

  </bindings>

</label>

As for the next ItemView control, I would not like dwell on much because the inner workings with it are nearly the same as those of the ListView control. Also, here, we don't waste space on the six buttons. You can study the source code, and if there is any question please contact me by making a comment on the article. 

In the next article, we will say a few words about the background Web Service and database. Please check back next week for the third part of this four-part tutorial.

blog comments powered by Disqus
ASP.NET ARTICLES

- Implementing ASP.NET 4.0 Page.MetaDescriptio...
- ASP.Net Development Tips
- Intro to Sessions in ASP.Net
- Google Maps API Introduction in ASP.NET usin...
- Creating an ASP.NET 3.5 Gridview Image Galle...
- Encrypt QueryString in ASP.NET 3.5 using VB....
- ASP.NET 3.5 Drop Down List Controls
- Connect to Access Database with ASP.Net
- Secure Audio Streaming with ASP.Net and Flash
- Dynamic Sitemap and Navigation in ASP.Net
- Implement Gzip and Deflate Compression in AS...
- Run ASP.Net in Ubuntu with Apache
- ASP.Net Mono Website Contact Forms
- ASP.Net URL Rewriting Methods
- Murach`s ASP.NET 4 Web Programming with C# 2...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 2 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials