Atlas Keynote Walkthrough

I mentioned a little earlier that I’d post the Atlas sample code and overall talk flow from the keynote demo I was part of earlier today at the PDC.  Here it is below:

 

Step 1: The Web Service We Use

 

In the talk Anders used the new LINQ features in C# 3.0 to query for process information, then join it in memory with data from a database, and then transform it into XML.  Don then showed exposing it via Indigo as first a SOAP end-point, then an RSS end-point, and then finally as a JSON end-point that I could consume.

 

Unfortunately I don’t have a snap-shot of the above code still with me (it is on another machine right now), so can’t show what we really used during the keynote.  Here is a simplified .asmx version, though, that shows what the signature of the service looks like The sample below is calling System.Diagnostics directly instead of using the cool new LINQ features, but hopefully provides a little insight into the service signature.  Note that there is no Atlas specific decoration or meta-data that needs to be applied to the web-service – it is just a standard .asmx file (Atlas then installs an HttpModule that can handle transforming the input/output of the service to a JSON wire protocol as appropriate): 

 

LapService.asmx

 

<%@ WebService Language="C#" Class="LapService" %>

 

using System;

using System.Collections;

using System.Collections.Generic;

using System.ComponentModel;

using System.IO;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

 

public class LapService : System.Web.Services.WebService

{

    [WebMethod]

    public ProcessData[] GetProcesses() {

        return this.GetAllProcesses().ToArray();

    }

 

    [WebMethod]

    public ProcessData[] MatchProcesses(string expression)

    {

        List<ProcessData> data = this.GetAllProcesses();

        if (String.IsNullOrEmpty(expression))

        {

            return data.ToArray();

        }

 

        string[] words = expression.Split(' ');

        return data.FindAll(new Predicate<ProcessData>(delegate(ProcessData process)

        {

            return System.Text.RegularExpressions.Regex.IsMatch(process.Name, expression);

        })).ToArray();

    }

 

    private List<ProcessData> GetAllProcesses()

    {

        List<ProcessData> data = new List<ProcessData>();

 

        System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();

        foreach (System.Diagnostics.Process process in processes)

        {

            data.Add(new ProcessData(process.ProcessName, process.WorkingSet64, process.Threads.Count));

        }

 

        return data;

    }

}

 

ProcessData.cs

 

using System;

using System.ComponentModel;

 

public class ProcessData

{

    private string _name;

    private long _workingSet;

    private int _threadCount;

 

    public string Name {

        get { return _name; }

        set { _name = value; }

    }

 

    public long WorkingSet {

        get { return _workingSet; }

        set { _workingSet = value; }

    }

 

    public long WorkingSetInMB {

        get { return _workingSet / (1024 * 1000); }

        private set { }

    }

 

    public int ThreadCount {

        get { return _threadCount; }

        set { _threadCount = value; }

    }

 

    public ProcessData() { }

 

    public ProcessData(string name, long workingSet, int threadCount) {

        _name = name;

        _workingSet = workingSet;

        _threadCount = threadCount;

    }

}

 

Step2 : Simple Invocation of the Web Service

 

The first step with Atlas we did on stage was to take a simple html page with no server-side code and show binding to the remote LapService end-point with it.  The final code for this segment looked like the page below. 

 

Note how it is easy to add a JSON proxy to the page – just add two script references to the page (one that points to the AtlasCore.js library and one that points to the .asmx with the /js flag specified).  You can then just call methods on the remote service – and setup a call-back event handler that will be invoked when the response is returned.  You can then work with the data using the same object model (except in Jscript) that was used on the server.  All code in the below sample runs on the client. 

 

Default.aspx:

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

 

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

  <title>Process Viewer</title>

  <link type="text/css" rel="stylesheet" href="simple.css" />

 

  <script src="ScriptLibrary/AtlasCore.js" type="text/javascript"></script>

  <script src="LapService.asmx/js" type="text/javascript"></script>

 

  <script language="javascript" type="text/javascript">

 

        function Button1_onclick() {

            var text1 = document.getElementById("Text1");

            LapService.MatchProcesses(text1.value, onSearchComplete);

        }

       

        function onSearchComplete(results) {

            var searchResults = document.getElementById("searchResults");

           

            for (var i=0; i<results.get_length(); i++) {

              searchResults.innerHTML += results[i].Name + "<br>";

            }

        }

  </script>

 

</head>

<body>

  <form id="form1" runat="server">

 

    <div id="logo">

      Process Explorer

    </div>

   

    <div id="header">

      Search:

      <input id="Text1" type="text" />

      <input id="Button1" type="button" value="Search" onclick="Button1_onclick();" />

    </div>

   

    <div id="content">

   

      <div class="left">

        <span id="searchResults"></span>

      </div>

     

    </div>

  </form>

</body>

</html>

 

 

Step 3: Using an Atlas ListView Control

 

[In the keynote demo we actually merged this step and the next one together – but for this post I’ll actually show what we originally planned (before we ran into a time crunch and had to compress them together).]

 

In this step we’ll take our simple invocation further and use one of the new Atlas controls called ListView to customize the presentation of the data further (and avoid having to hard-code it into javascript like the sample above). 

 

Atlas provides a Javascript client library that provides a Listview control that I can declare and use with javascript on the client.  Alternatively, I can use the ASP.NET server control model to nicely encapsulate this and handle automatically sending out the appropriate client markup (which is what I’ll do below).

 

Note that all Atlas-enabled ASP.NET Server Controls support both a client-side and server-side object model – so I can write code against them both from client Javascript and my server code-behind file.  In the below example I’m taking the same Results data that we retrieved above and instead of doing a for-loop over it I’m binding it on the client to the ListView (by calling searchResults.control.set_data(results).  Note also that all style design is done using standard CSS.

 

Default.aspx:

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

 

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

  <title>Process Viewer</title>

  <link type="text/css" rel="stylesheet" href="simple.css" />

 

  <atlas:ScriptManager runat="server" />

  <script src="LapService.asmx/js" type="text/javascript"></script>

 

  <script language="javascript" type="text/javascript">

 

        function Button1_onclick() {

            var text1 = document.getElementById("Text1");

            LapService.MatchProcesses(text1.value, onSearchComplete);

        }

       

        function onSearchComplete(results) {

            var searchResults = document.getElementById("searchResults");

            searchResults.control.set_data(results);

        }

  </script>

 

</head>

<body>

  <form id="form1" runat="server">

 

    <div id="logo">

      Process Explorer

    </div>

   

    <div id="header">

      Search:

      <input id="Text1" type="text" />

      <input id="Button1" type="button" value="Search" onclick="Button1_onclick();" />

    </div>

   

    <div id="content">

      <div class="left">

     

        <atlas:ListView id="searchResults" runat="server" ItemTemplateControlID="row" CssClass="listView"

          ItemCssClass="item" AlternatingItemCssClass="alternatingItem">

          <LayoutTemplate>

            <ul runat="server">

              <li id="row" runat="server">

                <atlas:Label id="name" runat="server">

                  <Bindings>

                    <atlas:Binding DataPath="Name" Property="text" />

                  </Bindings>

                </atlas:Label>

                <atlas:Label runat="server" CssClass="bar">

                  <Bindings>

                    <atlas:Binding DataPath="WorkingSetInMB" Property="style" PropertyKey="width" />

                  </Bindings>

                </atlas:Label>

                <atlas:Label runat="server">

                  <Bindings>

                    <atlas:Binding DataPath="WorkingSetInMB" Property="text" />

                  </Bindings>

                </atlas:Label>MB

              </li>

            </ul>

          </LayoutTemplate>

        </atlas:ListView>

       

      </div>

       

    </div>

  </form>

</body>

</html>

 

 

Step 4: Implementing Drag/Drop

 

The next step is to implement a master/detail drill-down view, where we let visitors to the site drag/drop processes from our Listview into an ItemView control to drill into its details (entirely on the client without requiring any post-backs or page refreshes).  Doing this is pretty easy with Atlas – drag/drop sourcing and targeting can be done declaratively or programmatically (note the <behaviors> tag to see how this is done below).  Note that I also switching the CSS stylesheet to "color.css" (from simple.css") just to make it look a little better.

 

Default.aspx:

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

 

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

  <title>Process Viewer</title>

  <link type="text/css" rel="stylesheet" href="color.css" />

 

  <atlas:ScriptManager runat="server" />

  <script src="LapService.asmx/js" type="text/javascript"></script>

 

  <script language="javascript" type="text/javascript">

 

        function Button1_onclick() {

            var text1 = document.getElementById("Text1");

            LapService.MatchProcesses(text1.value, onSearchComplete);

        }

       

        function onSearchComplete(results) {

            var searchResults = document.getElementById("searchResults");

            searchResults.control.set_data(results);

        }

  </script>

 

</head>

<body>

  <form id="form1" runat="server">

 

    <div id="logo">

      Process Explorer

    </div>

   

    <div id="header">

      Search:

      <input id="Text1" type="text" />

      <input id="Button1" type="button" value="Search" onclick="Button1_onclick();" />

    </div>

   

    <div id="content">

         

      <!-- Listview -->

      <div class="left">

 

        <atlas:ListView id="searchResults" runat="server" ItemTemplateControlID="row" CssClass="listView"

          ItemCssClass="item" AlternatingItemCssClass="alternatingItem">

          <Behaviors>

            <atlas:DragDropList runat="server" DataType="Process" />

          </Behaviors>

          <LayoutTemplate>

            <ul id="ul1" runat="server">

              <li id="row" runat="server">

                <atlas:Label id="name" runat="server">

                  <Behaviors>

                    <atlas:DraggableListItem runat="server" Handle="name">

                      <Bindings>

                        <atlas:Binding Property="data" />

                      </Bindings>

                    </atlas:DraggableListItem>

                  </Behaviors>

                  <Bindings>

                    <atlas:Binding DataPath="Name" Property="text" />

                  </Bindings>

                </atlas:Label>

                <atlas:Label id="Label1" runat="server" CssClass="bar">

                  <Bindings>

                    <atlas:Binding DataPath="WorkingSetInMB" Property="style" PropertyKey="width" />

                  </Bindings>

                </atlas:Label>

                <atlas:Label id="Label2" runat="server">

                  <Bindings>

                    <atlas:Binding DataPath="WorkingSetInMB" Property="text" />

                  </Bindings>

                </atlas:Label>MB

              </li>

            </ul>

          </LayoutTemplate>

        </atlas:ListView>

      </div>

             

      <!-- Item Details -->

      <div class="right">

     

        <atlas:ItemView id="details" runat="server">

          <Behaviors>

            <atlas:DataSourceDropTarget runat="server" Append="false" AcceptedDataTypes="Process" />

          </Behaviors>

          <ItemTemplate>

            <atlas:Label runat="server" CssClass="name">

              <Bindings>

                <atlas:Binding DataPath="Name" Property="text" />

              </Bindings>

            </atlas:Label>

            <span class="detailRow">

              Working set:

              <atlas:Label runat="server">

                <Bindings>

                  <atlas:Binding DataPath="WorkingSetInMB" Property="text" />

                </Bindings>

              </atlas:Label>

            </span>

            <span class="detailRow">

              Thread count:

              <atlas:Label runat="server">

                <Bindings>

                  <atlas:Binding DataPath="ThreadCount" Property="text" />

                </Bindings>

              </atlas:Label>

            </span>

          </ItemTemplate>

        </atlas:ItemView>

       

      </div>

    </div>

       

  </form>

</body>

</html>

 

 

Step 5: Implementing VirtualEarth

 

This step was completely gratuitous but fun.  Since any “real” Ajax app has some-type of map integration <g>, we decided to add support for mapping the location of our server processes on a map.

 

Since there is no way to get real longitude or latitude information from a running process, we just hard-coded in the coordinates.  But the name of the process was data-bound and live (and if we did have longitude and latitude information we could obviously have data-bound that too).

 

Here is what the code looked like with the virtual earth inside the bottom of the ItemView (note that no other code changes were required).  I’m using an older push-pin image so the background image is not transparent (it was for the demo) – but it should give you an idea of what it looked like:

 

Default.aspx:

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

 

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

  <title>Process Viewer</title>

  <link type="text/css" rel="stylesheet" href="color.css" />

 

  <atlas:ScriptManager runat="server" />

  <script src="LapService.asmx/js" type="text/javascript"></script>

 

  <script language="javascript" type="text/javascript">

 

        function Button1_onclick() {

            var text1 = document.getElementById("Text1");

            LapService.MatchProcesses(text1.value, onSearchComplete);

        }

       

        function onSearchComplete(results) {

            var searchResults = document.getElementById("searchResults");

            searchResults.control.set_data(results);

        }

  </script>

 

</head>

<body>

  <form id="form1" runat="server">

 

    <div id="logo">

      Process Explorer

    </div>

   

    <div id="header">

      Search:

      <input id="Text1" type="text" />

      <input id="Button1" type="button" value="Search" onclick="Button1_onclick();" />

    </div>

   

    <div id="content">

         

      <!-- Listview -->

      <div class="left">

 

        <atlas:ListView id="searchResults" runat="server" ItemTemplateControlID="row" CssClass="listView"

          ItemCssClass="item" AlternatingItemCssClass="alternatingItem">

          <Behaviors>

            <atlas:DragDropList runat="server" DataType="Process" />

          </Behaviors>

          <LayoutTemplate>

            <ul id="ul1" runat="server">

              <li id="row" runat="server">

                <atlas:Label id="name" runat="server">

                  <Behaviors>

                    <atlas:DraggableListItem runat="server" Handle="name">

                      <Bindings>

                        <atlas:Binding Property="data" />

                      </Bindings>

                    </atlas:DraggableListItem>

                  </Behaviors>

                  <Bindings>

                    <atlas:Binding DataPath="Name" Property="text" />

                  </Bindings>

                </atlas:Label>

                <atlas:Label id="Label1" runat="server" CssClass="bar">

                  <Bindings>

                    <atlas:Binding DataPath="WorkingSetInMB" Property="style" PropertyKey="width" />

                  </Bindings>

                </atlas:Label>

                <atlas:Label id="Label2" runat="server">

                  <Bindings>

                    <atlas:Binding DataPath="WorkingSetInMB" Property="text" />

                  </Bindings>

                </atlas:Label>MB

              </li>

            </ul>

          </LayoutTemplate>

        </atlas:ListView>

      </div>

       

      </div>

     

      <!-- Item Details -->

      <div class="right">

     

        <atlas:ItemView id="details" runat="server">

          <Behaviors>

            <atlas:DataSourceDropTarget runat="server" Append="false" AcceptedDataTypes="Process" />

          </Behaviors>

          <ItemTemplate>

            <atlas:Label runat="server" CssClass="name">

              <Bindings>

                <atlas:Binding DataPath="Name" Property="text" />

              </Bindings>

            </atlas:Label>

            <span class="detailRow">

              Working set:

              <atlas:Label runat="server">

                <Bindings>

                  <atlas:Binding DataPath="WorkingSetInMB" Property="text" />

                </Bindings>

              </atlas:Label>

            </span>

            <span class="detailRow">

              Thread count:

              <atlas:Label runat="server">

                <Bindings>

                  <atlas:Binding DataPath="ThreadCount" Property="text" />

                </Bindings>

              </atlas:Label>

            </span>

           

            <!-- Virtual Earth Control -->

            <atlas:VirtualEarthMap id="map" runat="server" ZoomLevel="17" Latitude="34.042653"

              Longitude="-118.269779" PushpinImageUrl="~/TravelImages/pushpin.gif"

              PushpinCssClass="pushpin" PushpinImageWidth="12" PushpinImageHeight="20" PushpinActivation="Click"

              PopupPositioningMode="TopLeft" MapStyle="Hybrid">

              <PopupTemplate>

                <atlas:Label runat="server">

                  <Bindings>

                    <atlas:Binding DataContext="details" DataPath="dataContext.Name" Property="text" />

                  </Bindings>

                </atlas:Label>

              </PopupTemplate>

              <Pushpins>

                <atlas:Pushpin Value="pp" Latitude="34.042653" Longitude="-118.269779" />

              </Pushpins>

            </atlas:VirtualEarthMap>

          </ItemTemplate>

        </atlas:ItemView>

       

      </div>

    </div>

       

  </form>

</body>

</html>

 

 

Step 6: Showing it on a Mac

 

The final step we showed was switching to a Mac running Safari and hitting the same page above using it.  Safari browsers get the exact same user experience with full Ajax support.

 

Hopefully this provides a rough sense of what the demo was like.

 

- Scott

17 Comments

  • Wooooow awesome



    Will there be any Atlas demonstration on channel9 or anywhere else? I would love to watch a demo of this.



    When is Atlas beta coming out? next year or will it ship with VS.NET 2005 this november?



    Is MSN Virtual Earth using an early version of Atlas?



    Amazing work, keep it up

  • Scott,



    The Atlas stuff looks great, and so does the LINQ stuff. Although I'm confused on how DLinq relates or will relate to Object Spaces which is supposed to be part of WinFS. Any ideas?



    Anyhow. What are the release plans for these? Generally PDC is stuff that will come out in the future. But, you have said Atlas will release as a stand alone toolset that you can add into ASP.Net/.Net 2.0. Right?



    What about LINQ? It is being positioned as C# 3.0 / VB.Net 9.0? But, it is shipped as a preview add-in for VS 2005? So, are these next language versions tied to a new version of the CLR and Visual studio?



    Will there be a point where the revisions of Visual Stidio, Lanagage and CLR revs will not be tied together? Or will they always be so?



    I'm not looking for hard dates, just general road map stuff.



    Thanks,

    BOb

  • Is there somewhere with this example working, so I can show my friends and convince them we need to pursue this. (without downloading, installing, and creating this little app?).

  • Yes!!!



    Thks for Atlas!! i 'm test now!



    [],

  • The NEXT release?

    So, in 1,2 or so years time?!



    Is Atlas techincally beta until then?

    Is it a bad idea to use Atlas in commercial applications for now?



  • Hi Scott,



    plz add css and images



    tks,



    Ramon

  • Is there any API documentation available in which all the components that come with atlas are explained? I am very much interested in the grid type controls. Any exmaples?

  • Say, would you mind posting your stylesheets? That would make this code complete!



    Thanks!

  • Wow. The XML markup for bindings is ridiculously verbose. Do you really expect anybody to type that, or are you guys so lost in the world of WYSIWYG that you don't care?



    Seriously, many of us still like to write programs with a keyboard.



    Here's my suggestion. Translate this:



    &lt;atlas:Label runat=&quot;server&quot;&gt;

    &lt;Bindings&gt;

    &lt;atlas:Binding DataPath=&quot;WorkingSetInMB&quot; Property=&quot;text&quot;/&gt;

    &lt;/Bindings&gt;

    &lt;/atlas:Label&gt;



    ... into this:



    &lt;atlas:Label runat=&quot;server&gt;{{WorkingSetInMB}}&lt;/atlas:Label&gt;

  • Question: if I have a autocompletion textbox setup so that after the user selects their choice, you click the button and have it save that value..how do you access that textbox value?



    Is it not accessible via the TextBox.Text property?

  • Hi Steve,



    On the client i think you can just say &quot;mytextbox1.value&quot; to retrieve the value (the same object model as a standard html textbox).



    Hope this helps,



    Scott

  • I got a run-time error with LapService.asmx: Unable to generate a temporary class.



    To fix, simply remove the keyword &quot;private&quot; from the WorkingSetInMB property in the ProcessData.cs class.



    This probably works in the Whidbey build scottgu used on stage.



    -Scott Stanfield

  • Has Anyone succeded in getting this code running? I've been trying now for hours and VS05 doesn't seem to recognise the tags e.g. atlas:ItemView, I think it has something to do with not having the color.cs style sheet, is there anyway around this? Any help would be much appreciated

  • Hi Michael,

    Unfortunately the above code is using a very old build of Atlas (the September PDC), which is why the code-sample doesn't work anymore.

    Sorry!

    Scott

  • I am totally excited about the new altas features for .net. I downloaded both the Microsoft ASP.NET AJAX v1.0 Beta and the rosoft ASP.NET AJAX CTP Beta and nstalled them both. &nbsp;Then began watching the getting started video with Scott Guthrie. &nbsp;One thing that I notice is that I did not have the Microsoft.web.Atlas.dll in my bin folder I had the Microsoft.web.preview.dll. I did a reinstall and repair thinking I missed a step. &nbsp;Stil the same issue. &nbsp;So was unable to take advantage of the atlas tags.
    I am using the Visual Web Developer Express and was wondering if anyone else had simular issues and how they resolved it.

  • Hi Lauri,

    The recent ASP.NET AJAX Beta has a number of changes in syntax and APIs from this previous walkthrough and even the video on www.asp.net.

    We are working hard now on getting all of the videos and documentation updated though.

    Hope this helps,

    Scott

  • hi Scott,

    how i can get the Style Sheet directory you used in the video

    thansk

Comments have been disabled for this content.