Using JavaScript Along with ASP.NET 2.0

 

By Bill Evjen
Lipper/Reuters

April 2006

Applies to:
   ASP.NET 2.0
   Visual Web Developer 2005 Express Edition

Summary: Learn how to use JavaScript along with your ASP.NET 2.0 applications. (18 printed pages)

Contents

Introduction
Adding JavaScript to a Server Control
Performing a Simple Button-rollover
Setting Control Focus
Using Larger JavaScript Functions
Page.ClientScript.RegisterStartupScript() Method
Page.ClientScript.RegisterClientScriptBlock() Method
Keeping JavaScript in a Separate File (.js)
Conclusion

Introduction

Web developers have been working around the limitations of the browser for a long time by using a combination of server-side processing and client-side processing. Working logic and application processes on the client-side allows browser based applications to seem more responsive and to have more "snappiness" to them. For client-side development in the past, most developers turned to JavaScript and intermingled this programming language into their classic Microsoft Active Server Pages along with their server-side Microsoft Visual Basic Scripting Edition or Microsoft JScript code. Now, with Microsoft ASP.NET and the new models that it provides, Web developers often wonder how to properly work with their JavaScript functions in their ASP.NET pages.

In a previous MSDN article, I presented how to effectively utilize JavaScript within your ASP.NET 1.x applications. With the introduction of ASP.NET 2.0, however, you'll find that the way this is accomplished has changed. For this reason, it is important to revisit how you might best go about building ASP.NET applications that make use of JavaScript. This article will take a look at some of the ways your past JavaScript functions can now be used. There is more than one way to accomplish this task and this article will take a look at many different possibilities. This article will also take a look at some of the more common uses of JavaScript in ASP.NET pages with some short examples.

Adding JavaScript to a Server Control

It is quite easy to add JavaScript to a specific server control that resides on an ASP.NET page. Let's take a look at the button server control as an example. If you drag and drop a Button HTML server control (HtmlInputButton Class) onto a page using either Microsoft Visual Studio 2005 and run it as a server control, it should have the following construction:

<input id="Button1" type="button" value="button" runat="server" />

This is a normal button that can be programmatically manipulated in the code-behind or server-side script of an ASP.NET page. For example, to assign the button text when the page is generated, simply use the value property of the button after this element is turned into an HTML server control (right-click on the control and select Run As Server Control).

Visual Basic

Protected Sub Page_Load(ByVal sender As Object, _
   ByVal e As System.EventArgs)

     Button1.Value = DateTime.Now.ToString()
End Sub

C#

protected void Page_Load(object sender, EventArgs e)
{
   Button1.Value = DateTime.Now.ToString();
}

This simply provides a button on the page that shows a date and time as the text of the button.

Aa479390.javawasp201(en-us,MSDN.10).gif

Figure 1. Showing the date and time on a button

It is important to note that the ASP.NET page here gets the time from the server that generated the page. So if the Web server sits somewhere in the Central Time Zone of the United States (CST -6 GMT), then everyone who requests this page will get the same time no matter where they reside in the world.

What if you wanted the button to show the time of the person viewing the page? The easiest way of accomplishing this task would be to use JavaScript on the client-side.

For an example of this, we will place the end user's (the viewer of the web page) computer time on a button Web server control. The following code shows how to accomplish this task:

Visual Basic

<%@ Page Language="VB" %>

<script runat="server">
    Protected Sub Button1_Click(ByVal sender As Object, _
      ByVal e As System.EventArgs)
        Response.Write("Postback!")
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Using JavaScript</title>
</head>
<body onload="javascript:document.forms[0]['Button1'].value=Date();">
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Button" 
         OnClick="Button1_Click" Font-Bold="True" Font-Names="Verdana" 
         Font-Size="Larger" />
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Write("Postback!");
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Using JavaScript</title>
</head>
<body onload="javascript:document.forms[0]['Button1'].value=Date();">
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Button" 
         OnClick="Button1_Click" Font-Bold="True" Font-Names="Verdana" 
         Font-Size="Larger" />
    </div>
    </form>
</body>
</html>

In this bit of code, notice how some of the button's attributes are assigned server side before being sent down to the client's browser. In this case, the font of the text on the button is changed to Verdana as well as to a bold font-type of a specific size. Once the button's HTML code is received on the client, the client-side JavaScript changes the text of the button to the current time on the end user's computer. The HTML code generated for the entire page will then appear like this:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
   Using JavaScript
</title></head>
<body onload="javascript:document.forms[0]['Button1'].value=Date();">
    <form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
 value="/wEPDwUKMTY3NzE5MjIyMGRkVUxVdzEWBhD7U89t7JKIkQc6Cko=" />
</div>

    <div>
        <input type="submit" name="Button1" value="" id="Button1" 
         style="font-family:Verdana;font-size:Larger;font-weight:bold;" />
    </div>
    
<div>

   <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
    value="/wEWAgK394SHCAKM54rGBtsX8d2S8MO7sf02DOAiquFyBkeY" />
</div></form>
</body>
</html>

Clicking on the button will still give you a postback (observed through the Response.Write command) and a new time on the button control as the page is re-rendered. The result is shown in Figure 2.

Aa479390.javawasp202(en-us,MSDN.10).gif

Figure 2. Clicking on the date button

In this case, we placed some JavaScript directly in the <body> element of the page using the onload attribute. For the value of the onload attribute, we specifically pointed to the HTML element with the name Button1 that is in the first <form> section (as it is possible to have multiple forms in HTML).

This was an easy way to add some JavaScript to work with an ASP.NET Web server control, though, we could have just as easily added a JavaScript command to the button itself, as shown in the following partial code example:

Visual Basic

<%@ Page Language="VB" %>

<script runat="server">
    Protected Sub Page_Load(ByVal sender As Object, _
      ByVal e As System.EventArgs)
        Button1.Attributes.Add("onclick", _
           "javascript:alert('ALERT ALERT!!!')")
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Using JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button id="Button1" runat="server" Font-Bold="True" 
         Font-Names="Verdana" Font-Size="Larger" 
         Text="Click Me!"></asp:Button>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>

<script runat="server"> 
    protected void Page_Load(object sender, EventArgs e)
    {
        Button1.Attributes.Add("onclick", 
           "javascript:alert('ALERT ALERT!!!')");
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Using JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button id="Button1" runat="server" Font-Bold="True" 
         Font-Names="Verdana" Font-Size="Larger" 
         Text="Click Me!"></asp:Button>
    </div>
    </form>
</body>
</html>

Using a server control's attribute property is a great way to add additional JavaScript to a control that is control specific. In this case, the JavaScript was added using the Attribute.Add property along with the key of the script, as well as the script itself (both represented as string values).

Performing a Simple Button-Rollover

When it comes to buttons on a Web page, one of the more common functionalities that Web developers want to give their buttons is a rollover effect. The rollover effect experience is when end users hover their mouse over a button on a Web page (without clicking the button) and the button itself changes color or shape. This can be especially useful for Web pages that have multiple buttons, and it would be beneficial from a usability standpoint to notify end users of the button they would be clicking prior to clicking it.

This was fairly easy to do before server controls came along, and it isn't that difficult now with server controls. The code for performing such an operation is as follows:

Visual Basic

<%@ Page Language="VB" %>

<script runat="server">
    Protected Sub ImageButton1_Click(ByVal sender As Object, _
      ByVal e As System.Web.UI.ImageClickEventArgs)
        Label1.Text = "Postback!"
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Using JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <p>
       <asp:ImageButton id="ImageButton1" 
        onmouseover="this.src='button2.gif'" 
        onclick="ImageButton1_Click" 
        onmouseout="this.src='button1.gif'" runat="server" 
        ImageUrl="button1.gif"></asp:ImageButton>
    </p>
    <p>
       <asp:Label id="Label1" runat="server" />
    </p>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>

<script runat="server"> 
  protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
  {
      Label1.Text = "Postback!";
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Using JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <p>
       <asp:ImageButton id="ImageButton1" 
        onmouseover="this.src='button2.gif'" 
        onclick="ImageButton1_Click" 
        onmouseout="this.src='button1.gif'" runat="server" 
        ImageUrl="button1.gif"></asp:ImageButton>
    </p>
    <p>
       <asp:Label id="Label1" runat="server" />
    </p>
    </div>
    </form>
</body>
</html>

Instead of assigning the JavaScript to a server control through the <body> element, this time we used the onmouseover and onmouseout events of the control. For each of these events, we assigned a JavaScript value. The onmouseover event is when end users hover their mouse over the control, and the onmouseout is for actions when end users remove their mouse from hovering over the control. In our case, we want to show one image while the mouse hovers over the button and then show the original image, from when the page was loaded, when the mouse moves away from the button.

If you are working directly in the control such as this, instead of specifying the control in the form as we did when working with JavaScript in the <body> element, you can use the this keyword followed by the property you are trying to change.

Setting Control Focus

ASP.NET 2.0 now includes the ability to set the focus (of the cursor) to one of your HTML form elements. Before ASP.NET 2.0, you had to employ JavaScript yourself to accomplish the same task. For example, if your ASP.NET 1.x page has multiple text boxes on it, focus could have been set to the first TextBox control when the page was loaded by employing the following code in the <body> tag of the page.

<body onload="document.forms[0]['TextBox1'].focus();">

Using this construct, when the page was loaded, the element that contains the ID TextBox1 would employ the focus, and this would then enable the end user to start entering text directly without the need to use the mouse to position the focus.

ASP.NET 2.0 makes this task much easier with the addition of the Focus() method. Now you can accomplish a focus to a TextBox control as shown here:

Visual Basic

Protected Sub Page_Load(ByVal sender As Object, _
 ByVal e As System.EventArgs)   
   TextBox1.Focus()
End Sub

C#

protected void Page_Load(object sender, EventArgs e)
{
   TextBox1.Focus();  
}

When the page using this method is loaded in the browser, the cursor is already placed inside of the text box, ready for you to start typing. There's no need to move your mouse to get the cursor in place so you can start entering information in the form. The Focus() method enables you to dynamically place the end user's cursor in an appointed form element (not just the TextBox control, but in any of the server controls derived from the WebControl class).

Using Larger JavaScript Functions

Now that we can place pieces of JavaScript within HTML elements and even work with JavaScript and Web server controls in a dynamic fashion, how do you go about putting entire JavaScript functions in your code?

There are a couple of ways to accomplish this task and we will take a look at some of the more common methods that you can employ in your ASP.NET code. For this article, we will look at using the new Page.ClientScript property. Before ASP.NET 2.0, you would have needed to employ the RegisterStartupScript and the RegisterClientScriptBlock methods. These methods are now considered obsolete. Both of these possibilities for registering scripts in ASP.NET 1.x required a key/script set of parameters. Because two separate methods were involved, there was an extreme possibility that some key name collisions would occur. The Page.ClientScript property is meant to bring all the script registrations under one umbrella, making your code less error prone.

Page.ClientScript.RegisterStartupScript() Method

One of the first options available is to register script blocks using one of the .NET classes for this purpose. The first is the RegisterStartupScript method. This class would be best used when you have a JavaScript function that you want to initiate when the page is loaded. For an example of this, create an ASP.NET page in Visual Studio 2005 that contains two buttons. Button1 and Button2 should be the IDs of the two buttons. Then place the following code within the Page_Load event.

Visual Basic

Page.ClientScript.RegisterStartupScript(Me.GetType(), "MyScript", _
   "function AlertHello() { alert('Hello ASP.NET'); }", True)

Button1.Attributes("onclick") = "AlertHello()"
Button2.Attributes("onclick") = "AlertHello()"

C#

Page.ClientScript.RegisterStartupScript(this.GetType(), "MyScript",
   "function AlertHello() { alert('Hello ASP.NET'); }", true);

Button1.Attributes["onclick"] = "AlertHello()";
Button2.Attributes["onclick"] = "AlertHello()";

The two possible constructions of the RegisterStartupScript method are the following:

  • RegisterStartupScript (type, key, script)
  • RegisterStartupScript (type, key, script, script tag specification)

From the previous example, you are specifying the type as Me.GetType(), the key, the script to include, and then a Boolean value setting of True so that .NET places the script on the ASP.NET page with <script> tags automatically.

Using this code in the Page_Load event will produce the following HTML code in the browser (some HTML code has been removed for clarity):

<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
   Using JavaScript
</title></head>
<body>
    <form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
 value="/wEPDwUJMTM4ODA1MjE5D2QWAgIED2QWBAIBDw9kFgIeB29uY2xpY2s
 FDEFsZXJ0SGVsbG8oKWQCAw8PZBYCHwAFDEFsZXJ0SGVsbG8oKWRk+DQIaJpw5
 A7pyhzP8dxf/JGUSbA=" />
</div>

    <div>
        <input type="submit" name="Button1" value="Button" 
         onclick="AlertHello();" id="Button1" />
        <input type="submit" name="Button2" value="Button" 
         onclick="AlertHello();" id="Button2" />
    </div>
    
<div>

   <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
    value="/wEWAwK4yNWFBwKM54rGBgK7q7GGCHwBEr6DyGutQ/egvNrB3OYhCwM4" />
</div>

<script type="text/javascript">
<!--
function AlertHello() { alert('Hello ASP.NET'); }// -->
</script>
</form>
</body>
</html>

Working with this ASP.NET page, notice that there is one JavaScript function that was placed at the bottom of the page before the close of the form (</form>).

It is important that all the JavaScripts on the page have unique keys given to them (this is provided through the key parameter requirement in the method). If there is more than one JavaScript with the same key name, only the first one will be placed on the page.

Page.ClientScript.RegisterClientScriptBlock() Method

Now let's create a better version of the button rollover example by using the Page.ClientScript.RegisterClientScriptBlock method. The problem with the rollover button example from earlier is that when the end user's mouse hovered over the button image, the rollover image had to be retrieved from the server in a separate request. A better rollover button situation would be one in which the rollover image of the button is already downloaded and stored in the browser's cache, so that when the end user hovers over the button, it is instantaneously displayed. To accomplish this we must build a JavaScript function. The following example shows the JavaScript function, as well as the use of the RegisterClientScriptBlock method to get the function onto the page. For this example, the code-behind only needs a Page_Load event and a button-click event for an ImageButton server control.

Visual Basic

Protected Sub Page_Load(ByVal sender As Object, _
 ByVal e As System.EventArgs)   
   Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), _
      "MyScript", _
      "if (document.images) {" & _
      "MyButton = new Image;" & _
      "MyButtonShaded = new Image;" & _
      "MyButton.src = 'button1.gif;" & _
      "MyButtonShaded.src = 'button2.gif;" & _
      "}" & _
      "else {" & _
      "MyButton = '';" & _
      "MyButtonShaded = '';" & _
      "}", True)

   ImageButton1.Attributes.Add("onmouseover", _
      "this.src = MyButtonShaded.src;" & _
      "window.status='Oh Yes! Click here!';")
   ImageButton1.Attributes.Add("onmouseout", _
      "this.src = MyButton.src;" & _
      "window.status='';")
End Sub

Protected Sub ImageButton1_Click(ByVal sender As Object, _
  ByVal e As System.Web.UI.ImageClickEventArgs
    Label1.Text = "Postback!"
End Sub

C#

<%@ Page Language="C#" %>
<script runat="server">   
protected void Page_Load(object sender, EventArgs e)
{
       Page.RegisterClientScriptBlock("MyScript", _
           "if (document.images) {" +
           "MyButton = new Image;" +
           "MyButtonShaded = new Image;" +
           "MyButton.src = 'button1.gif;" +
           "MyButtonShaded.src = 'button2.gif;" +
           "}" +
           "else {" +
           "MyButton = '';" +
           "MyButtonShaded = '';" +
           "}", true);

       ImageButton1.Attributes.Add("onmouseover",
          "this.src = MyButtonShaded.src;" +
          "window.status='Oh Yes! Click here!';");
       ImageButton1.Attributes.Add("onmouseout",
          "this.src = MyButton.src;" +
          "window.status='';");
    }
 
  protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
  {
     Label1.Text = "Postback!";
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Using JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <p>
       <asp:ImageButton id="ImageButton1" 
        onmouseover="this.src='button2.gif'" 
        onclick="ImageButton1_Click" 
        onmouseout="this.src='button1.gif'" runat="server" 
        ImageUrl="button1.gif"></asp:ImageButton>
    </p>
    <p>
       <asp:Label id="Label1" runat="server" />
    </p>
    </div>
    </form>
</body>
</html>

Using this code, the HTML output to the browser will appear as follows:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1"><title>
   Using JavaScript
</title></head>
<body>
    <form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"  
 value="/wEPDwUKMTcyMTcwOTQ2NA9kFgICBA9kFgICAQ8PZBYEHgtvbm1
 vdXNlb3ZlcgVCdGhpcy5zcmMgPSBNeUJ1dHRvblNoYWRlZC5zcmM7d2luZ
 G93LnN0YXR1cz0nT2ggWWVzISBDbGljayBoZXJlISc7Hgpvbm1vdXNlb3V
 0BSl0aGlzLnNyYyA9IE15QnV0dG9uLnNyYzt3aW5kb3cuc3RhdHVzPScnO
 2QYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgEFDEltYWd
 lQnV0dG9uMXDJ4zl4FNylcdE+kep0e5wzi14T" />
</div>

<script type="text/javascript">
<!--
if  (document.images) 

{MyButton = new Image;MyButtonShaded = new Image;
MyButton.src = 'button1.gif';MyButtonShaded.src = 'button2.gif';}

else 

{MyButton= '';MyButtonShaded = '';}// -->
</script>

    <div>
        <p>
            <input type="image" name="ImageButton1" id="ImageButton1" 
             onmouseover="this.src = MyButtonShaded.src;window.status=
               'Oh Yes! Click here!';" 
             onmouseout="this.src = MyButton.src;window.status='';" 
             src="button1.gif" style="border-width:0px;" />
        </p>
        <p>
            <span id="Label1"></span>
        </p>

    </div>
    
<div>

   <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
    value="/wEWAgLhoLy4DwLSwpnTCEKaKJJN3KmLU7TP4vwT5VSKMT+M" />
</div></form>
</body>
</html>

With this output, notice that by using the RegisterClientScriptBlock the JavaScript function appeared directly after the opening <form> element in the HTML code. In addition to adding a JavaScript function using the RegisterClientScriptBlock method, we also added some additional JavaScript (just for fun) so that text will appear in the browser's status bar when the end user hovers over the mouse. This is shown in Figure 3.

Aa479390.javawasp203(en-us,MSDN.10).gif

Figure 3. Rollover button in action

The nice thing with all this JavaScript is that the normal postback to server-side events works just fine. Clicking on the ImageButton in this example causes a postback in which the Label server control's text property is changed.

The Difference Between Page.ClientScript.RegisterStartupScript and Page.ClientScript.RegisterClientScriptBlock

We have shown two different methods for placing JavaScript functions on an ASP.NET page—so what is the difference? The main difference is that the RegisterStartupScript method places the JavaScript at the bottom of the ASP.NET page right before the closing </form> element. The RegisterClientScriptBlock method places the JavaScript directly after the opening <form> element in the page. So what difference does this make? It can make quite a bit of difference, as we will see.

For an example of this, here is a way to put focus on a text box on a page when the page is loaded into the browser—with Visual Basic using the RegisterStartupScript method:

Page.ClientScript.RegisterStartupScript(Me.GetType(), "Testing", _ 
  "document.forms[0]['TextBox1'].focus();", True)

This works well because the textbox on the page is generated and placed on the page by the time the browser gets down to the bottom of the page and gets to this little bit of JavaScript. But, if instead it was written like this (using the RegisterClientScriptBlock method):

Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "Testing", _
  "document.forms[0]['TextBox1'].focus();", True)

Focus will not get to the textbox control and a JavaScript error will be generated on the page (shown in Figure 4).

Aa479390.javawasp204(en-us,MSDN.10).gif

Figure 4. Error executing JavaScript

The reason for this is that the browser will encounter the JavaScript before the text box is on the page. Therefore, the JavaScript will not be able to find a TextBox1.

Keeping JavaScript in a Separate File (.js)

Keeping JavaScript functions in a separate file (a .js file) is highly recommended. Once they are in a separate file and part of a project, the file can be imported into a page using some of the methods already described.

For instance, a .js file can be included in an ASP.NET page using the following code:

Visual Basic

Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "MyScript", _
   "MyJavaScriptFile.js")

C#

Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "MyScript", 
   "MyJavaScriptFile.js");

Once the .js file is imported into the ASP.NET page, any of the JavaScript functions can be called as before. This is a great way to manage JavaScript functions and keep them separate from the other logic of ASP.NET pages. It is also an easy way to use the same JavaScript functions on multiple ASP.NET pages.

Conclusion

This paper took a quick look at some common ways of working with JavaScript in ASP.NET pages and some of the more common uses of JavaScript. Some of the more important tips to take away are to keep JavaScript in a separate .js file and to make use of the RegisterStartupScript and RegisterClientScriptBlock methods to get the JavaScript into pages. It is also quite easy to use the capabilities of the HtmlGenericControl to deploy control-specific JavaScript to ASP.NET pages.

 

About the author

Bill Evjen is an active proponent of .NET technologies and community-based learning initiatives for .NET. He has been actively involved with .NET since the first bits were released in 2000. In the same year, Bill founded the St. Louis .NET User Group (http://www.stlnet.org), one of the world's first .NET user groups. Bill is also the founder of the International .NET Association (http://www.ineta.org), which represents more than 400,000 members worldwide.

Based in St. Louis, Missouri, USA, Bill is an acclaimed author and speaker on ASP.NET and XML Web services. He has written or coauthored more than 10 books including Professional ASP.NET 2.0, Professional C# 2005, and Professional VB 2005, XML Web Services for ASP.NET, Web Services Enhancements: Understanding the WSE for Enterprise Applications, Visual Basic .NET Bible, and ASP.NET Professional Secrets (all published by Wiley). In addition to writing, Bill is a speaker at numerous conferences including DevConnections, VSLive, and TechEd.

Bill is a Technical Architect for Lipper (a Reuters owned company). He graduated from Western Washington University in Bellingham, Washington, with a Russian language degree. When he isn't tinkering on the computer, he can usually be found at his summer house in Toivakka, Finland. You can reach Bill at evjen@yahoo.com. He presently keeps his weblog at http://www.geekswithblogs.net/evjen.

© Microsoft Corporation. All rights reserved.