Mix08 Session Overview: Building Great AJAX Applications from Scratch Using ASP.NET 3.5 and Visual Studio 2008

I am really looking forward to my Mix08 session this year... It is going to be fun to building an Ajax application from scratch on stage with VS2008 and ASP.NET 3.5.  


Update (3/15): I made a few tweaks based on comments to this post.  thanks!

Update (3/07):  The session video is now posted.  There is even a place to discuss the session.

Here is a play-by-play if you want to follow along and help keep me in line...  This Mix08 folks should have the video up tomorrow... I will link to it when it is up.

Everything I will show can be done with the free-and-always free Visual Web Developer Express edition of VS... Go grab it and play along! 

Download the completed sample or just the starter files to play along at home.  

Part I:  CSS and HTML Designer

I started a brand new project and selected .NET Framework 2.0 as the target runtime.  This allows me use VS2008, but target servers that have not been upgraded to .NET Framework 3.5 yet. 


I then showed off the new Split view that is an excellent way to find out what markup goes with what UI element.  Notice as I highlight the text in the markup, it is tracked and highlighted in the designer.  I can also do two-way editing in the designer or the code source view. 


Next, I used VS 2008's great new CSS support.  I used the Manage Styles panel to create a new CSS Selector...  Notice I use ".photolist li" this rule will apply to any li inside an element with the class photolist. 

Also, notice we can select where to define the css rules in.  I have selected in a new style sheet. VS will create the new style sheet and (optionally) reference it from the current page. 


Next, I go into the markup and set the class for the ul to photolist.  Notice the great automatic completion VS gives me.


Now, i can open up the CSS file and see how clean it is?  Also, notice I can do code-focused editing of the CSS rather than use the designers.  Again, I get great help from VS.


Next, in design view, I click on an image... notice the breadcrumb at the bottom of VS shows you where you are in the visual tree.  Hit escape to navigate up the tree until the list item (li) is selected. 


We want this to layout like a grid, so in the CSS Properties window, under Position, set Display to "inline" and float to "left"


Next we use the grab-handles in the designer to give us a little more spacing... Again, notice how all these edits are cleanly going into the attached CSS style sheet rather than gunking up our code.

Finally, let's make this look really nice by throwing it a MasterPage will will give a common look and feel across our site.

And we are starting go have something that looks sort of nice!


To close this part of the demo off, let's go ahead and upgrade the site to use .NET Framework 3.5...
Before we do that, notice under Add References... there are a bunch of references grayed out.  This is to keep developers from accidentally using some new stuff that is only in .NET Framework 3.5. 


Under Project, Properties, Build Options you can change the target framework to be .NET Framework 3.5


Now, you will notice that all the references are available... 


Part II:  Data access with Linq

OK, that was great, but in a real world site you don't deal with static images... you need to pull data out of a database.   So let's change the site around a bit to pull data from a database.

First, i will drag in photos.mdb into App_Data, this is a SqlServer database that I created for this demo... I will use the free Sql Express to allow me to use it at development time.

As you can see it is a simple database.


Now, as a .NET developer, I'd really like to operate against this database as a set of .NET types rather than having to remember and debug some T-Sql code in my .NET code.  Luckily Linq solves this for me!

To add a Linq data model for this database... Add New Item, then select the Linq To Sql classes (note: Entity Framework works in an identical way)


Then drag the Photos and Tags table over the new design surface.


This is the view of your .NET types that represent your database.  Notice VS picked up on the relationships between the tables and even gave pretty names to the .NET classes (Photo rather than Photos for example).   You can of course edit these names in this designer view as well. 

Notice, while this will do direct CRUD operations against the database, it is very possible to encapsulate all access through stored procs if need be. 

Now, let's go back to the UI and give us some place to put this data.  I will show off the new ListView control in ASP.NET. 

The way ListView works, is that you give it a layout template that defines exactly how you work the markup to look.  In our case, we will just cut and pate that ul into the layout template and define a place holder of the li's

    <asp:ListView runat="server" ID="photoList" ItemPlaceholderID="ph">
            <ul class="photolist">
                <asp:PlaceHolder runat="server" ID="ph"></asp:PlaceHolder>

Then, we can set the ItemTemplate to be one of the LIs... later we will need to come back and databind these values rather than using a hard coded example.

    <asp:ListView runat="server" ID="photoList" ItemPlaceholderID="ph">
            <ul class="photolist">
                <asp:PlaceHolder runat="server" ID="ph"></asp:PlaceHolder>
                <img src="Images/1.jpg" />
                <br />
                Eat more Cake 

Flip to design view, it looks pretty nice!  Now we just need some real data.


To get the real data, let's go back to that Linq data model we created and write some code against it. 

   1:          int i = 4;
   2:          PhotosDataContext db = new PhotosDataContext();
   3:          var q = from photo in db.Photos
   4:                  where photo.Rating == i
   5:                  orderby photo.Tags.First().TagName ascending
   6:                  select photo;
   7:          photoList.DataSource = q;
   8:          photoList.DataBind();

In line 2, we create the data context... this is the logic connection string for our Linq data model.

In line 3, we are using C#'s new var keyword which allows us to fudge on the type of the express...the compiler will figure it out...

In line 4, we are doing a where clause, notice that I am capturing a local variable in that, clearly this example is trivial, but it is a powerful feature.

in line 5 notice i am ordering by the first tag name, notice how nice this reads?  It would be much harder to do this  in TSQL!

in line 7 and 8 and I doing the normal databinding.

Now we need to go into the UI and set it up to pull values from this data source.

                <img src="Images/<%#Eval("ImagePath") %> />
                <br />
                <%#Eval("Title") %>

  The results!


Now, that is nice, but there are a ton of results here..  we really need a nice way to page through them.   

I use the new DataPager control in ASP.NET 3.5..  Notice it can have filed that are simple Next\Prev or numeric or you can even build your own!


Here is the complete code:

    <asp:DataPager runat="server" ID="dp"
            <asp:NumericPagerField />

Now, we need to ensure that the ListView will show the correct items when the data pager changes.  We do this by adding a PreRender() method to the page.  A simplified view of the page lifecycle is Page_Load(), then the control events are raised, then Page_PreRender() is called.   In our case the events from the pager need to be raised to change the page before we bind the list.

protected void Page_PreRender()

And notice it works great!


Part III:  Server Side Ajax

Now it is time to add a little ajax fun to the site.   Notice as I page through the items I am getting a little blink?  That is because the page is doing a full post-back to the server when only the images are changing.  It would be great if I could update only the part of the page that is changing! 

And you can with UpdatePanel. Simply wrap the UpdatePanel's content template around the area of the page that you want to update separately.  the runtime will turn any postbacks into XmlHttp calls, back the the server, get the right HTML and then bring in back and update only the part of the DOM effected.   Simple. Powerful. 


Oh, and don't forget to add ScriptManager to the top of the page.  This "turns on" the ajax functionality in ASP.NET...

<asp:ScriptManager runat=server id=sm></asp:ScriptManager>

Now the page refreshes much more smoothly. 

For the demo, we are running against localhost, but in the real world there is network load, congestion on the Internet, etc that may effect your page's responsiveness.   But you want to give user's an immediate response to their actions... to let them know that something is happening.   

You can use a Thread.Sleep (2000) in your page's load method to simulate this sort of load.. 

Enter UpdateProgress...   This little control listens for calls over XmlHttp and shows a progress template as they go out and takes it down when they come back in...  That plus a little animate gif gives users a great sense of "something happening". 

    <asp:UpdateProgress ID="UpdateProgress2" runat="server">
            <div id="UpdateProgressBox">
                <img id="Img2" runat="server" alt="Loading" src="~/Images/ajax-loader.gif" />

  And now the site looks good!


Part IV:  Client Side Ajax

Next we want to allow users to edit those titles, but in a smooth way that doesn't require form postback to the server.  

We start by changing the rendering of the title to an input control 

<input id="titleTextBox"
       onchange="onTitleChange(this.value, <%#Eval("ID") %>);"
       value="<%#Eval("Title") %>" />

Now we need to go define the onTitleChange client side javascript method. 

We do this in the header content area our MasterPage has left us.  

    <script type="text/javascript">
        function onTitleChange (title, id) {

Notice that VS 2008 has some great intellisense for JavaScript.   We are actually running a JavaScript interpreter in the background, so we always know what type the objects are. 

For example, here VS knows n is a Dom element. 


But we can easily change the type to a string...  and VS keeps up!


We know debugging in JavaScript can be hard... I know I have used alert() based debugging too many times!  Well, VS2008 is here to help with full debugging support for client side javascript. 


Lots of cool stuff to show you here.  Notice at the top right, full debugging controls, run, break, step over, step into, etc.
At the mid-left, notice the icon's for break point, and current executing line.
At the mid-right, notice the debugging views I get that show me exactly what the current value of all the locals and parameters are.
At the bottom right, notice my the results of my call to Sys.Debug.Trace() are beging displayed in the output window. 
And finally at the bottom right, notice I have full control to use the immediate window to evaluate results in the current context. 

Ok, cool, but now we want to actually go change the datamodel on the server... How do I do that? 

Well, first define a WCF-Ajax service.  This well expose JSON calls that is very ajax friendly.   Add, New Item, Ajax-enabled WCF service.


Now, we need to implement a web services that will update our data model. 

   1:      public string SetPhotoTitle(string title, int id)
   2:      {
   3:          PhotosDataContext db = new PhotosDataContext();
   4:          var q = (from photo in db.Photos
   5:                  where photo.ID == id
   6:                  select photo).First();
   7:          q.Title = title;
   8:          db.SubmitChanges();
   9:          return q.Title;
  10:      }

Then we just need to call it from client side javascript.  To do that, we need to add a reference in ScriptManager. 

    <asp:ScriptManager runat="server" ID="sm">
            <asp:ServiceReference Path="~/PhotoService.svc" />

Then, we can directly access the SetPhotoTitle method from JavaScript.  Notice we even get auto-completion.


Because the is Ajax, we need to be asynchronous... which means we need to define a callback method to get the results. 

        function onTitleChange (title, id) {
          Sys.Debug.trace("Title: " + title);
          PhotoService.SetPhotoTitle(title, id, onComplete);
        function onComplete (results) {
           Sys.Debug.trace (results);

OK... let's run this in FireFox and use FireBug to check out the network traffic. 

First thing to notice is that the Sys.Debug.Trace() calls are making their way to firefox's console window.  Very helpful in debugging. 


Next, we will expand that node and notice the request is in JSON format


As is the response..


Part V:  Ajax Control Toolkit Fun!

Now we need some way to add new items to our database.  Let's add a new page for this purpose. 

Right click on the master and select add content page.  Rename it to "AddPhoto.aspx"


Now, I will use a FormView in Insert mode to give us some pre-backed UI to start with. 

    <asp:FormView runat="server" 

Then, to show databinding in the designer, let's flip to design view and edit databinding.


We will use the new LinqDataSource control


Notice it already knows about the PhotosDataContext we created earlier


We have really customization support


The results look good...


The LinqDataSource that was created is far from a black box, you can not only re-run the wizard, but you can edit this in markup as well.

    <asp:LinqDataSource ID="LinqDataSource1" runat="server" 
        Select="new (Title, Description, Rating, Tags)" TableName="Photos">

Now, let's go in and Ajax enable this form a little more!

First, for the tags, we want to provide a suggest type of feature to give people a hint as to what tags are. This is easy with the Ajax Control Toolkit's AutoCompleteExtender. 

Select Edit Templates, then InsertItem, then Add Extender.


Select the AutoCompleteExtender


Now, select Add AutoCompletePageMethod


And here is the implantation... again, some fun Linq code.

   1:      [System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
   2:      public static string[] GetCompletionList(string prefixText, int count, string contextKey)
   3:      {
   4:          PhotosDataContext db = new PhotosDataContext();
   5:          var q = from t in db.Tags
   6:                  where t.TagName.StartsWith(prefixText) 
   7:                  select t.TagName; 
   9:          return q.Take(count).ToArray();
  11:      }

Let's check out the markup and see what is generated.   We will also set the MinimumPrefixLength to 1 to make the demo smoother.

            <asp:TextBox ID="TagsTextBox" runat="server" Text='<%# Bind("Tags") %>' />
            <cc1:AutoCompleteExtender ID="TagsTextBox_AutoCompleteExtender" runat="server" 

When we run it.. it looks great... 


Now, let's add a couple of other toolkit controls..

Replace the rating textbox with a much cooler netflix style ratings control, put a watermark on the description textbox and confirm before submitting. 

            <cc1:Rating ID="Rating1" runat="server" BehaviorID="AutoCompleteEx" CurrentRating='<%# Bind("Rating") %>'
                EmptyStarCssClass="emptyRatingStar" FilledStarCssClass="filledRatingStar" MaxRating="5"
                StarCssClass="ratingStar" WaitingStarCssClass="savedRatingStar">
            <asp:TextBox ID="DescriptionTextBox" runat="server" 
                Text='<%# Bind("Description") %>' />
            <cc1:TextBoxWatermarkExtender ID="DescriptionTextBox_TextBoxWatermarkExtender" runat="server"
                Enabled="True" TargetControlID="DescriptionTextBox" WatermarkCssClass="watermarked"
                WatermarkText="&lt;type description>">
            <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" 
                CommandName="Insert" Text="Insert" />
            <cc1:ConfirmButtonExtender ID="InsertButton_ConfirmButtonExtender" runat="server"
                ConfirmText="Are you sure you want to add this item?" Enabled="True" TargetControlID="InsertButton">


Ok, that is some really cool functionality, but what about page load time?  Let's go back to FireBug and take a look at the scripts that we are loading.

I am seeing 13 different requests, 122KB and 10.35s... wow that seems like a lot. 


We can use the new ScriptCombining feature to combing the scripts into a single request that saves the round trip time and compresses better.


Notice this part of the demo will only work once we ship out the update to ASP.NET we are working on right now... So for now, it is just for your reference.  

But first we need to know exactly what scripts are being loaded.  To see this let's look at the ScriptReference debugging tool.

Just drop it on your page

    <cc2:ScriptReferenceProfiler ID="ScriptReferenceProfiler1" runat="server" /> 

and you see exactly what is loaded.


We also, have both the debug and retail scripts ready to download in case we want to share this across several pages.

Then cut and past that into ScriptManager.

    <asp:ScriptManager runat="server" ID="sm">
                <asp:ScriptReference Name="MicrosoftAjax.js" />
                <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" />
                <asp:ScriptReference Name="AjaxControlToolkit.Common.Common.js" Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.ExtenderBase.BaseScripts.js" Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.TextboxWatermark.TextboxWatermark.js"
                    Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.Rating.RatingBehavior.js" Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.Compat.Timer.Timer.js" Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.Animation.Animations.js" Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.Animation.AnimationBehavior.js" Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.PopupExtender.PopupBehavior.js" Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.AutoComplete.AutoCompleteBehavior.js"
                    Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
                <asp:ScriptReference Name="AjaxControlToolkit.ConfirmButton.confirmButtonBehavior.js"
                    Assembly="AjaxControlToolkit, Version=3.0.11119.25533, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />

Now, let's go back to firebug...


This time, we have two request 118KB and 4.39s... Much better!


Comments (32)
  1. Joe Levi says:

    Live blogging the presentation from the 3rd row back at: http://tinyurl.com/2p7cx9


  2. Bruno Moniz says:

    Excelent 🙂

    Looking forward to the video of the session.

  3. jp says:

    I can’t find the  <CompositeScript> under the scriptmanager.  I am targeting .net 3.5.  Is this an add on?

  4. dan says:

    I’m with jp–there are build errors…

  5. bleroy says:

    @jp: compositescript is in 3.5 SP1.

  6. Noam says:

    Aren’t the new features like compositeScript still internal?  when will they be released?

  7. Ian says:

    Great tutorial – I also can’t wait until the video is made available.

  8. Doga Oztuzun says:

    ScriptCombining Feature

  9. Doga Oztuzun says:

    ScriptCombining Feature

  10. Steve says:

    Getting this error:

    Error 19 Type ‘System.Web.UI.ScriptManager’ does not have a public property named ‘CompositeScript’.

  11. Darrell says:

    This is cute, but the real issue for me is lazy loading and slicing and dicing data on the client.  There doesn’t seem to be an lot of emphasis on client side list data processing by Microsoft insiders.  If we are going to make round trips to the server just to get a string we may as well get dev express or teleric and and call it a day.  

    I’m waiting for a smooth way to stay on the client as long as is feasible and build a reusable client library from it.  Is this a place we can get to with this version of the framework without some major hacking?  

  12. The great folks here running Mix have done a excellent job getting the videos for the Mix session up

  13. The great folks here running Mix have done a excellent job getting the videos for the Mix session up

  14. Darrell says:

    I’m sorry Brad, was this a response to the question I posed?  I am new to the blog so pardon if I am missing some of the etiquette.

  15. David Hayden says:

    Just wanted to say that I watched your presentation via video and I thought it was an excellent overview of practical AJAX, LINQ To SQL, and new features in Visual Studio 2008 and the .NET 3.5 Framework presented in a very compact and easy-to-digest format. Great job!

  16. Programming says:

    The great folks here running Mix have done a excellent job getting the videos for the Mix session up

  17. I guess MIX-08 was a pretty cool event Unfortunately all I can do was guess because I wasn&#39;t there

  18. BradA says:

    >> Getting this error:


    >>Error 19 Type ‘System.Web.UI.ScriptManager’ >>does not have a public property >>named ‘CompositeScript’.

    Sorry about that, I should have mentioned that CompositeScripts will not be on line until a servicing release later this year..  Stay tuned!

  19. TerryLee says:


  20. jlxuqiang says:

    Excelent 🙂

    but  i can’t get "completed sample" from you posted Url

  21. JohnL says:

    In order to go to next page I have to click Datapager

    2 times?

  22. BradA says:

    >> In order to go to next page I have to click Datapager

    >>2 times?

    Good call John!  I made a slight bug.  I was missing the Page_PreRender() method to rebind the listview after the pager control had raised the event to change the page.    So we were always a page off 😉

    I updated the text of this post and fixed the sample and snippets file.  Please let me know if that fixes the issue you are seeing.


  23. Jacky_Xu says:


  24. Josh Lewis says:

    I have downloaded your completed sample and was attempting to use the AddNewPhoto page but without changing anything I get the error.

    LinqDataSource ‘LinqDataSource1’ does not support the Insert operation unless EnableInsert is true.

    So I added the EnableInsert="true" to the statement and I get a new error.

    LinqDataSource ‘LinqDataSource1’ does not support the Select property when the Delete, Insert or Update operations are enabled.

    What am I missing here? Also would it be possible to add to the add photo page a way to actually upload a new photo?

  25. topzengyi says:




  26. Tanvir says:

    I have just finished watching your MIX 08 presentation video. It is a great video. I have tried to download the completed project source code, but failed to do so. Could you please update the download link of the completed project zip? Thanks

  27. BradA says:

    Tanvir — sorry about that, my ISP is having an issue… they hope to have it back up monday.

  28. VS2008 and .NET Framework 3.5 offer a ton of customer value from Linq to Ajax and much more.&#160; The

  29. We recently finished the post product work required to get enhanced videos posted.&#160; The videos not

  30. Programming says:

    We recently finished the post product work required to get enhanced videos posted.&#160; The videos not

  31. For my Mix Essentials talk in South Africa I updated my Mix08 talk Building Great AJAX Applications from

  32. The AJAXWorld Conference and Expo got underway in San Jose today, under the broad theme of "Rich Web

Comments are closed.

Skip to main content