Adding Paging to the Simple Photo Gallery

Turn the pageOver my last handful of posts, Building a Simple Photo Gallery in ASP.NET MVC Framework, Returning Thumbnails With the MVC Framework and Adding Lighbox.js to the Simple Photo Gallery I’ve built a simple photo gallery on the ASP.NET MVC framework.

In this post, we’re going to continue that project by adding paging rather than showing all of the pictures on the one page.

Adding Paging to the Model with LINQ

Since we are simply using an XML file for the storage, we need to do the paging manually against our set of objects that we have in memory. This method works well any time you have client side caching as well.

public class ImageModel : List<Image>
{
    public ImageModel() : this(1, 10)
    {
    }

    private List<Image> GetAllImages()
    {
        string imagesDir = HttpContext.Current.Server.MapPath("~/images/");
        XDocument imageMetaData = XDocument.Load(imagesDir + @"/ImageMetaData.xml");
        var images = from image in imageMetaData.Descendants("image")
                     select new Image(image.Element("filename").Value,
                     image.Element("description").Value);
        
        TotalCount = images.Count<Image>();

        return images.ToList<Image>();
    }

    public int TotalCount { get; set; }
    public int CurrentPage { get; set; }
    public int PageSize { get; set; }
    public ImageModel(int pageNum, int pageSize)
    {
        CurrentPage = pageNum;
        PageSize = pageSize;

        var images = GetAllImages();

        this.AddRange(images.Skip((pageNum - 1) * 
            pageSize).Take(pageSize).ToList());
    }
}

Notice that I added a new constructor that takes as parameters page number and page size. This will allow us, from the controller, to control the action happening here. The next thing to notice is that the default constructor is now calling the new constructor passing in default parameters of 1 and 10. Notice that we’re starting with 1 instead of 0. This will make a ton more sense to the user and makes mapping the pages a lot simpler. Lastly, notice that we’re setting some parameters (TotalCount, CurrentPage and PageSize). We’ll use these in the view in a little bit.

If we run right now, we’ll only get the first 10 pictures. If you happen to be following along and coding this with me, go ahead and try it.

Adding the Custom Route

Next, we need to add a route to handle the page mechanism.

In the global.asax.cs file, in the method called RegisterRoutes add the following route.

routes.MapRoute(
    "ImagePaging",                                              // Route name
    "{controller}/Page{pagenumber}",                           // URL with parameters
    new { controller = "Home", action = "Page", pagenumber = "1" }  // Parameter defaults
);

Notice how the routes are built. It’s a series of url parts and named parameters. For example, the Page2 is going to pass in 2 as the selected pagenumber. We actually could have hard coded the whole path except for the page number.

Adding the Paging Action to the Controller

Now that we’ve got data routing to the an Action, we need to make sure that we’re handling it.

Turns out, this was the easiest piece of all.

public ActionResult Page(string pagenumber)
{
    ImageModel model = new ImageModel(int.Parse(pagenumber), 10);
    return View("index", model);
}

Notice that we are just creating the ImageModel leveraging our new constructor and passing it into a view. The view that we’re using is still the index view, which is the default. We don’t have to go build a new view for the paging, we just need to alter the data that we’re passing into our current view.

If you want, you can go test by browsing to /image/page2 and see what it shows.

Adding the Navigation Links

The last thing to do is to add the navigation links to the view. If you use the <% %> tags in any ASPX it runs on the server side. What this is actually doing is that the ASPX page is parsed and generated into code and compiled into a .NET assembly on the server side and the code inside the <% %> just gets copied into that generated code before it’s compiled. This means that the code that’s inside your brackets must match the language that you set at the top of the page.

<%if (ViewData.Model.TotalCount > ViewData.Model.PageSize){ %>
<div class="paging">
    <%if (ViewData.Model.CurrentPage > 1) { %>
        <%= Html.ActionLink("Back", 
"Page" +
(ViewData.Model.CurrentPage - 1).ToString(), "Image")%>&nbsp; <% }%> <%decimal numberOfPages =
decimal.Divide(ViewData.Model.TotalCount, ViewData.Model.PageSize); int lastPageNumber = (int)decimal.Ceiling(numberOfPages); for (int i = 1; i <= lastPageNumber; i++) { if (i != ViewData.Model.CurrentPage) { %> <%= Html.ActionLink(i.ToString(), "Page" + i.ToString(), "Image")%>&nbsp; <% } }%> <%if (ViewData.Model.CurrentPage < lastPageNumber) { %> <%= Html.ActionLink("Next",
"Page" + (ViewData.Model.CurrentPage + 1).ToString(), "Image")%> <% }%> <%=lastPageNumber%> </div> <% }%>

Notice that we’re using the properties set by back in the model here. There’s three different sections here. The first checks to see if we need a back button. The second loops over the pages and creates step links. And the third checks to see if we need a next button.

The navigation links in the view turned out to be the most complicated part of adding paging to the photo gallery.

Stay tuned to future posts for styling with CSS, adding a Silverlight front end and more.

Adding Lighbox.js to the Simple Photo Gallery

image In my previous two posts, Building a Simple Photo Gallery in ASP.NET MVC Framework and Returning Thumbnails With the MVC Framework, I built a simple photo gallery on the ASP.NET MVC framework. In this post we are going to start making this a little prettier. To start with, we are going to leverage an JavaScript project called Lightbox.js that’s released under the Creative Commons Attribution 2.5 License.

One cool part about it is that you can get a tremendous amount of functionality with little to no JavaScript coding on your own. It leverages a couple of different JavaScript libraries including Prototype and Scriptaculous. These do a lot of generic HTML Dom manipulation and visualization.

The result of leveraging Lightbox.js is that when you click on one of the thumbnails that we started showing in Returning Thumbnails With the MVC Framework the full sized picture will show in a really nice lightbox style effect.

First, you need to download the Lightbox.js project. It comes in a zip file that comes with a sample application. Unzip the contents into the appropriate folders. This means that the .js files go in your /scripts directors and the images and the css in the /content folder.

The cool part is that since you have the source to it all, rock on and modify it to your heart’s content. And we’re going to do a light modification right off the bat. We could have put the images from the Lightbox.js project in the /images folder but we’re already using that for something else so we put them in the /content folder. That means that you need to open up lightbox.js and change the directory of the loading and close images to point to the correct directory.

LightboxOptions = Object.extend({
    fileLoadingImage:        'content/loading.gif',
    fileBottomNavCloseImage: 'content/closelabel.gif',

That’s the only mod that we *need* to make at the moment. If you feel like it, you can fix the image paths in lighthouse.css as well.

#prevLink:hover, #prevLink:visited:hover { background: 
url(Content/prevlabel.gif) left 15% no-repeat; } #nextLink:hover, #nextLink:visited:hover { background:
url(Content/nextlabel.gif) right 15% no-repeat; }

The only thing left to do is update the Images/index view to take advantage of our new capabilities. There are two mods to make. First, we need to include links to the lightbox.css and the required 3 JavaScript files (prototype.js, scriptaculous.js and lighbox.js). Second, we need to add a rel=”lightbox” to the anchor tag around our picture.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
AutoEventWireup="true" CodeBehind="Index.aspx.cs"
Inherits="PhotoGalleryMVC.Views.Image.Index" %> <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"> <link rel="stylesheet" href="content/lightbox.css" type="text/css" media="screen" /> <script src="scripts/prototype.js" type="text/javascript"></script> <script src="scripts/scriptaculous.js?load=effects,builder" type="text/javascript"></script> <script src="scripts/lightbox.js" type="text/javascript"></script> <p><%= Html.ActionLink("Add your own image", "Upload", "Image")%></p> <% foreach (var image in ViewData.Model) { %> <span class="image"> <a href="/images/<%= image.Path %>" rel="lightbox">
<
img src="/image/thumbnail/<%= image.Path %>" />
</
a> <span class="description"><%= image.Description %></span> </span> <% }%> </asp:Content>

It’s that simple. This will render a really nice little lightbox effect on our images.

Stay tuned for future posts about styling the CSS, paging the pictures and a whole lot more.

Returning Thumbnails With the MVC Framework

In my last post, we put together a quick and simple photo gallery. This post will be building on that.

Depending on the size of your photo, however, it didn’t have the worlds greatest user experience. I’ll be playing with the CSS, JavaScript and a ton more over time. Today, however, I’m going to be just returning a thumbnail rather than the full picture to show in the view.

I don’t want to have to physically create each of the thumbnails so we’ll generate those dynamically on the fly.

Creating a Custom ActionResult

To return a given type of result, you have to return an ActionResult of that type. The types that are currently built in are View, Redirect, RedirectToAction, RedirectToRoute, Content, or Json. We need to create a specific action type that we’ll call the ThumbnailResult. It will be created with a virtual path to the picture that we need to show. When it’s executed, it will generate and return the thumbnail.

public class ThumbnailResult : ActionResult
{
    public ThumbnailResult(string virtualPath)
    {
        this.VirtualPath = virtualPath;
    }

    public string VirtualPath {get;set;}

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.ContentType = "image/bmp";

        string fullFileName =
            context.HttpContext.Server.MapPath("~/images/" + VirtualPath);
        using (System.Drawing.Image photoImg =
            System.Drawing.Image.FromFile(fullFileName))
        {
            using (System.Drawing.Image thumbPhoto =
                photoImg.GetThumbnailImage(100, 100, null, new System.IntPtr()))
            {
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                {
                    thumbPhoto.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                    context.HttpContext.Response.BinaryWrite(ms.ToArray());
                    context.HttpContext.Response.End();
                }
            }
        }
    }
}

Notice that we’ve set the HttpContext.Response.ContentType to “image/bmp”. This is critical for the browser to understand the data that it recieves.

Leveraging the Custom ActionResult

The next step is to add a method to the controller that will return the ThumbnailResult.

public ActionResult Thumbnail(string id)
{
    return new ThumbnailResult(id);
}

And lastly we need to update the view to leverage this new thumbnail action.

<a href=”/images/<%= image.Path %>“><img src=”/image/thumbnail/<%= image.Path %>” /></a>

When you run now, you should get the thumbnails instead of the full sized picture. However, you should still be able to click through to the actual picture. In an upcoming blogpost, we’ll change this to use lightbox.js.

Building a Simple Photo Gallery in ASP.NET MVC Framework

image I decided to create a simple photo gallery in the ASP.NET MVC framework. The fun part is that this level of application is really the new “Hello World”. It takes less time to build than the “Hello World” did back in the day.

In this post, I’ll walk you through the process of creating this simple photo gallery with the MVC framework.

First, let’s talk a little about what the ASP.NET MVC framework is. It’s a web framework built on .NET with the principles of the MVC architecture behind it.

The MVC Architecture

MVC architecture divides the responsibilities of an application into three main components – models, views, and controllers.

image“Models” are responsible for the the data access. The data is often times in a database but it doesn’t have to be. The model could be over an XML file or whatever other data store that you happen to use. By default the ASP.NET MVC framework uses the Entity Framework. However, it can work with any data access type that returns a set of objects that the view can access. Most of the time, this will be an ORM such as the Entity Framework, NHibernate or SubSonic. In our demo below we’re actually going to just be reading in an XML file from the disk.

“Views” are responsible for the actual user interface. Typically this is HTML but it could be XML, JSON or any other number types of display/service response. Most of the time, these displays/responses are built based on model data.

“Controllers” are responsible for the actual logic. It handles the end user interaction, manipulates the data in the model and decides which view to return to the user. Simple enough? 

Creating the ASP.NET MVC Framework Project

image I started out creating an ASP.NET MVC Web Application called PhotoGalleryMVC. There are a couple of very important things to notice in an ASP.NET MVC framework project.

First, look at the Global.asax and it’s code behind. It’s got a really important method called RegisterRoutes where you define your routes.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", 
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = "" }
    );

}

These routes define what happens when your application receives a request. The controller is a class and the action is a method on that class. The parts after that are parameters to the method. We’ll see more with this in a few moments.

The next thing is to notice the controllers. The default method that you get in the helper class is as follows:

public ActionResult Index()
{
    ViewData["Title"] = "Home Page";
    ViewData["Message"] = "Welcome to ASP.NET MVC!";

    return View();
}

This is the default action for the controller. It’s simply setting some properties on the View and then returning it. Notice that we’re not instantiating a copy of the view and setting properties directly on it. Instead, we’re staying with the very loosely coupled method of using a ViewDataDictionary called ViewData. This is a dictionary of items that both the view and the controller have access to.

Creating the ImageModel

The first thing I want to create is a way to get the images in the first place. Rather than creating a database, we’re going to simply use an XML file as our storage for our information about our images.

Create a folder called Images under the root of the project. This will be where we put the images.

As a file ImagesMetaData.xml in the images directory following the format below. Feel free to substitute your own data in for the data I have below…

<?xml version="1.0" encoding="utf-8" ?>
<images>
  <image>
    <filename>IMG_3717.JPG</filename>
    <description>Paul playing Guitar Hero.</description>
  </image>
  <image>
    <filename>IMG_3720.JPG</filename>
    <description>Phizzpop Signin.</description>
  </image>
</images>

Add a class called Image under the model folder. For now this will be really simple.

namespace PhotoGalleryMVC.Models
{
    public class Image
    {
        public Image(string path, string description)
        {
            Path = path;
            Description = description;
        }
        public string Path { get; set; }
        public string Description { get; set; }
    }
}

All this class provides for now is a holder for the image path and description. We’ll do more with this class in the future.

The next thing that we need to do is create a way to get those images from the disk. This will be in a class called ImageModel. To make this really simple, we will inherit from a generic list of Image. This gives us a lot of functionality already. What we need to add is a constructor that will retrieve the images from the disk.

namespace PhotoGalleryMVC.Models
{
    public class ImageModel : List<Image>
    {
        public ImageModel()
        {
            string imagesDir = HttpContext.Current.Server.MapPath("~/images/");
            XDocument imageMetaData = XDocument.Load(imagesDir + @"/ImageMetaData.xml");
            var images = from image in imageMetaData.Descendants("image")
                         select new Image(image.Element("filename").Value,
                         image.Element("description").Value);
            this.AddRange(images.ToList<Image>());
        }
    }
}

All this model is doing is reading in the XML file and creating a list of images based on that metadata.

Creating the Controller

The next step is to create the controller. Again, for the moment, this will be extremely simple. We’ll do more with it in the future.

namespace PhotoGalleryMVC.Controllers
{
    public class ImageController : Controller
   
{
        public ActionResult Index()
        {
            return View(new ImageModel());
        }
    }
}

Notice that this is slightly different than the default controller as it’s passing in the ImageModel. We’ll have to create the View to accept it here in just a moment.

Creating the View

Now we need to add a folder to the hold our images view in the Views folder. Now to create the view in the Images view folder, right-click on the folder and select Add View. Name the view Index.

Now that we have our view, modify it’s declaration to accept the ImageModel class.

namespace PhotoGalleryMVC.Views.Image
{
    public partial class Index : ViewPage<ImageModel>
    {
    }
}

What this does is set up our view based on a generic ViewPage with ImageModel as it’s base.

And lastly we need to add the HTMLish stuff to do the actual display.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
AutoEventWireup="true" CodeBehind="Index.aspx.cs"
Inherits="PhotoGalleryMVC.Views.Image.Index" %> <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"> <% foreach (var image in ViewData.Model) { %> <span class="image"> <a href="images/<%= image.Path %>"><img src="images/<%= image.Path %>" /></a> <span class="description"><%= image.Description %></span> </span> <% }%> </asp:Content>

If you’ve ever done ASP Classic or PHP, this HTMLish stuff shouldn’t look too odd. If you strip out the HTML code, you’ve got a normal foreach loop written in C#. The bad news about this approach is that there’s a lot less controls, such as the datagrid and such, available to you. The good news is that you’ve got absolute control over the HTML that is produced.

You should notice, however, that we’re able to leverage master pages as we do in ASP.NET 2. This is great because it allows us to define our look and feel in a master page. There’s a great amount of flexibility and power in that.

Last step is that we need to add a tab on the main navigation to get to the images page. We do that in the /views/shared/site.master

<ul id="menu">
    <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
    <li><%= Html.ActionLink("Images", "Index", "Image")%></li>
    <li><%= Html.ActionLink("About Us", "About", "Home")%></li>
</ul>

Even though we’ve got few controls at out disposal, there are some interesting helpers such as this Html.ActionLink. This returns a link that points to the appropriate controller and action without us having to divine what that link should be based on the current routes. 

At this point, the application runs and shows really big pictures (assuming that you’ve put a few in the images folder in the first place).

Adding a New Picture

Now that we’ve got a few manually placed a few of the pictures in the folders and gotten them to display on the view, we need a way for the user to add their own pictures to the site. We’re going to do this one in reverse order where we create the view and work backwards from there.

Step one is that we need a new view and a way to get to it from the images page. We can accomplish that with a simple Html.ActionLink in the Image Index view.

    <p><%= Html.ActionLink("Add your own image", "Upload", "Image")%></p>

Now we need to create the view for the New action. Simply right click on the View folder and select Add|View. Name this view “Upload”.

In the view, we need to create a form that will do the post.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
AutoEventWireup="true" CodeBehind="Upload.aspx.cs"
Inherits="PhotoGalleryMVC.Views.Image.Upload" %>

<asp:ContentID=”Content1″ContentPlaceHolderID=”MainContent”runat=”server”>
<
form method=”post” action=”<%=Url.Action(“save”) %>enctype=”multipart/form-data”>
    <
input type=”file” name=”file” />
    <input type=”submit” value=”submit” /> <br />
    <input type=”text” name=”description” />
</form>
</
asp:Content>

It’s not the world’s prettiest form but it’s functional. Notice the action on the form tag. It’s using another helper called Url.Action. This maps to the same controller but a different action.

Now we need to add the upload and save action to the controller. The Upload action is very simple. It simply returns the Upload view. The Save is a little more complicated as it has to do the actual logic of getting the files and descriptions and putting those on the model.

namespace PhotoGalleryMVC.Controllers
{
    public class ImageController : Controller
    {
        public ActionResult Index()
        {
            return View(new ImageModel());
        }

        public ActionResult Upload()
        {
            return View();
        }

        public ActionResult Save()
        {
            foreach (string name in Request.Files)
            {
                var file = Request.Files[name];

                string fileName = System.IO.Path.GetFileName(file.FileName);
                Image image = new Image(fileName, Request["description"]);

                ImageModel model = new ImageModel();
                model.Add(image, file);
            }
            return RedirectToAction("index");
        }
    }
}

The important part here is that this controller is not actually doing the logic of saving out to the disk. This is important because it gives us the flexibility to alter the model switch from file based storage to a database and so on. This separation is key to the success of the architecture.

Last thing to do is alter the model to actually save out to the disk.

public void Add(Image image, HttpPostedFileBase file)
{
    string imagesDir = HttpContext.Current.Server.MapPath("~/images/");
    file.SaveAs(imagesDir + image.Path);

    this.Add(image);
    XElement xml = new XElement("images",
            from i in this
            orderby image.Path
            select new XElement("image",
                      new XElement("filename", i.Path),
                      new XElement("description", i.Description))
            );

    XDocument doc = new XDocument(xml);

    doc.Save(imagesDir + "/ImageMetaData.xml");
}

The LINQ makes creating the XML document really simple.

There are a lot of optimizations that could be done here such as storing off the model in memory and the like so that we’re not constantly reading/writing to the disk and the like. That’s not the point of this exercise. The point here is to work with the MVC framework.

At this point we’ve got a functioning image gallery with uploads and a view.

In my next post, I’ll alter this to serve up thumbnails and give a nicer user experience.

Ann Arbor Day of .Net

Wow I’ve been swamped. There’s so much to blog about in the past couple of weeks so I’m just going to catch some of the highlights.

Ann Arbor Day of .NET was on 5/5/2007. It was fantastic! It sold out at 250 people and of that there were 210 people show up. That’s actually really good as most free events have a 40% droppoff and they had less than 20% droppoff. The only downside on the day was that with less than a 20% droppoff – pizza was a little short at lunch.

They are actually thinking about going to every 6 months instead of every 12 months. I think this would be fantastic!

I kicked off the day with a session on User Experience technologies at Microsoft. I borrowed from some of the materials that we are putting together for the upcoming ArcReady (Check the site for dates and times across the entire central region – Detroit on 5/25 in two weeks for all those that attended Day of .Net). We dipped into WPF, AJAX and Silverlight. My favorite demo is the Silverlight Airlines Demo. It shows a truly out of the box user experience that’s not all glitz and glammor but a truly solid UI for a true business application. Many of the demos, while showing off the platform really well, are marketing apps that show lots of 3D and animation. My customers often look at the glitzy demos and say that they are not doing 3D so they don’t look at the technologies. What they are missing is that there are real benifits here with enabling truly rich interfaces that go well beyond text and pictures.

I had two more 30 minute sessions. In both of those sessions the overwhelming requests were to have more Silverlight content. I had nothing prepared for these sessions but they went really well. In the first session, I pulled Don Burnett, who started Michigan Interactive Designers, out of the crowd and asked him to do a tour around Expression Blend and Silverlight. He got up, completely unscripted, and did a fantastic job! I will definitely be bringing him in to do more demos and presentations – especially when we have a designer based crowd. It turns out that he used to work with Bill Wagner (my former business partner when I was at SRT Solutions) on the Lion King Animated Storybook.

In the second session, I was on my own but I showed Top Banana, the DLRConsole (python and javascript version – IronRuby will be released as a CTP from CodePlex later this year) and talked about the .NET support in Silverlight 1.1 Alpha. Yes – I actually wrote some Python and did a simple overview for people at the conference. It was a fun day!

Here are some of the resources that we talked about during the three talks:

•Windows Forms @ .NET FX Developer Center
http://windowsclient.net

•WPF @ MSDN Developer Center
http://msdn.microsoft.com/winfx/reference/presentation/default.aspx

•.NET 3.0 (WPF, WCF, WF) Community Site
http://windowsclient.net/

•Silverlight
http://www.silverlight.net

•ASP.NET AJAX @ ASP.NET Developer Center
http://msdn.microsoft.com/winfx/reference/presentation/default.aspx

•ASP.NET AJAX Community Site
http://ajax.asp.net/

•DirectX @ DirectX Development Center
http://msdn.microsoft.com/directx/

•Microsoft Visual Studio @ Visual Studio Developer Center
http://msdn.microsoft.com/vstudio/

•Microsoft Expression
www.microsoft.com/expression

 

Day of .NET site

Link to Day of .Net in Ann Arbor 2007 – Home

Don Burnett’s write-up of the event.

Link to Don.NET’s WPF Designers Blog: Eastern Michigan Day of Dot Net

 

Playing with JSON

Silverlight Plasma ReactorI was asked on Friday by a friend how one can consume JSON in Silverlight. At the time, I just said start with the System.Json namespace and I’ll get you a sample later. Well, here’s a sample and a peek into my head because I couldn’t just stop with creating the sample that he needed.

Download Solution – PlayingWithJSON.zip

*Update – gotta do a quick shoutout to Leon Gersing for his passionate defense of JavaScript and JSON. It’s part of what inspired me to spend as much time on this as I did.

Really short JSON overview

JSON, for those of you who don’t know, is a really simple data format heavily used with JavaScript. It’s a lot smaller and lighter than XML.

This is the JSON that I’m using in this example. As you can see, it’s just name/value pairs with a little bit of extra formatting. Curly Braces separate objects in a list. Commas separate values. Colons separate the names from the values. 

[
{“FirstName”:”Etta”,”LastName”:”James”,”Url”:”http:\/\/www.etta-james.com\/”},{“FirstName”:”Billie”,”LastName”:”Holiday”,”Url”:”http:\/\/www.billie-holiday.net\/”},{“FirstName”:”Ella”,”LastName”:”Fitzgerald”,”Url”:”http:\/\/en.wikipedia.org\/wiki\/Ella_Fitzgerald”}]
}

Creating the JSON service with ASP.NET MVC Framework

The first thing that I did was slap together an ASP.NET MVC Framework application to produce the JSON and host the Silverlight application. This was remarkably easy. I decided against going through the effort of creating a database because that’s not really the point of the exercise.

I created a simple class that to fill out and serialize and then returned it from a controller.

public class Artist
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Url { get; set; }
}

The next step was to create a simple controller that would return my list as JSON. As you can see, there’s a JsonResult that you can return right from a controller method.

public class ArtistsController : Controller
{
    public JsonResult GetAll()
    {
        List<Artist> artists = new List<Artist>();

        artists.Add(new Artist("Etta", "James", "http://www.etta-james.com/"));
        artists.Add(new Artist("Billie", "Holiday", "http://www.billie-holiday.net/"));
        artists.Add(new Artist("Ella", "Fitzgerald", "http://en.wikipedia.org/wiki/Ella_Fitzgerald"));

        return Json(artists);
    }
}

To test it, I just browsed to http://localhost:mylocalport/artists/getall. That returned the JSON file. As the browser doesn’t display JSON auto-magically, it prompted me to download a file and save it off.

Now, take notice of the URL. The ASP.NET MVC Framework is producing what’s called a RESTful Service. The parameters and all are simply in the URL. In the URL, “artists” takes us to a particular Controller called the ArtistsController and the “getall” calls the “GetAll()” method on that controller. We can further specify parameters and the like in the URL. Scott Guthrie has a great article that explains the URL routing and all at http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx.

Now that we are producing JSON from a services, we are ready to create a client.

Getting the JSON from the RESTful service.

The first client that I tried was the straight up System.Json namespace client. Since we are using a RESTful service, we can’t generate the proxy object in the same way that we’re used to with SOAP. Instead, we need to leverage the WebClient object.  This is done as follows:

void mainButton_Click(object sender, RoutedEventArgs e)
{
    Uri serviceUri = new Uri("/Artists/GetAll", UriKind.Relative);
    WebClient downloader = new WebClient();
    downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
    downloader.OpenReadAsync(serviceUri);
}

Notice that the URL that I’m using is relative. You can specify the full URL if the service is not on your own server. These calls, as all calls in Silverlight, are async. Therefore I wire up the downloader_OpenReadCompleted event and call OpenReadAsync. Simple enough?

Leveraging System.Json

Once the downloader returns, I can get the result off of the event arguments. Load is a static method on the JsonArray that will automatically parse out the results from the stream object. Then, I can just loop over the objects in the array and use them to fill out my own type that I’m ready to databind to.

void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    JsonArray jsonArray = (JsonArray)JsonArray.Load(e.Result);

    List<Artist> artists = new List<Artist>();

    foreach (JsonObject jsonArtist in jsonArray)
    {
        Artist artist = new Artist();
        artist.FirstName = jsonArtist["FirstName"];
        artist.LastName = jsonArtist["LastName"];
        artist.Url = jsonArtist["Url"];

        artists.Add(artist);
    }

    dataGrid1.ItemsSource = artists;
}

This was fairly straight forward and simple, but I wasn’t ready to be done yet.

Leveraging LINQ

The next thing is to try LINQ against this JsonArray and see what happens.

void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    JsonArray jsonArray = (JsonArray)JsonArray.Load(e.Result);

    var query = from artist in jsonArray
                select new Artist
                {
                    FirstName = (string)artist["FirstName"],
                    LastName = (string)artist["LastName"],
                    Url = (string)artist["Url"],
                };

    List<Artist> artists = query.ToList() as List<Artist>;
    dataGrid1.ItemsSource = artists;
}

Personally, I think that the LINQ version is a lot more powerful. It’s not immediately obvious in this simple example but there’s a ton that I could do with the LINQ query from filling out sub-types to filtering and so on.

JSON in JavaScript

JavaScript ReferenceBut then I started thinking about all of the different ways that one can get and parse out JSON directly in JavaScript (I mean it does have JavaScript right in the name).

First, I did it the old school way that I used to do back when I was doing a ton of JavaScript development.

Quick note here – before you start copying this code – this is NOT the way to do this in the modern era. I did it to prove a point. You really need to be leveraging one of the many great JavaScript frameworks that are out there in order to accomplish your JavaScript today. I’ll get to those in a minute.

Short version, you’re going to be doing an XMLHttpRequest directly. When that returns you’ll get an “onreadystatechange” event which you can respond to. If it’s actually ready, then you can call a JavaScript function called eval that will return and array of objects parsed out from the string that you pass in.

<script language="javascript" type="text/javascript">
    function GetJson(url) {
        // Create xmlhttprequest object
        var xmlhttp = null;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
            //make sure that Browser supports overrideMimeType
            if (typeof xmlhttp.overrideMimeType != 'undefined') {
                xmlhttp.overrideMimeType('text/xml');
            }
        }
        else if (window.ActiveXObject) {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        else {
            alert('Perhaps your browser does not support xmlhttprequests?');
        }

        // Create an HTTP GET request
        xmlhttp.open('GET', url, true);

        // Set the callback function
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                var json = xmlhttp.responseText;

                var artists = eval(json);

                var newArtistList;
                newArtistList = "<ul>";

                for (var i in artists) {
                    var artist = artists[i];
                    newArtistList += "<li>"
                    + artist.FirstName + " "
                    + artist.LastName
                    + "</li>"
                }

                newArtistList += "<ul>";

                outputControl = document.getElementById("divOutput");
                outputControl.innerHTML = newArtistList;
            } else {
                // waiting for the call to complete
            }
        };

        // Make the actual request
        xmlhttp.send(null);
    }
</script>

Alright, that’s a lot of JavaScript to get through and understand. There are multiple possible problems here. First, that’s just a ton of code. Second, the same eval function that you are calling here is the same eval function used to dynamically execute a piece of JavaScript in a string. This means that you’re open to all kinds of possible attacks. Finally, there are a ton of frameworks that have come up in the past handful of years.

So, let’s go look at some of those frameworks.

Leveraging MS AJAX

The AJAX framework that I’ve been trying to learn lately is the MS AJAX one. It’s got a lot of power. First, notice that the WebRequest actually looks a lot like what I did in C#. Next, notice the JavaScriptSerializer object. This gives me some nice and easy serialization to and from JSON. The reason to use this is that it’s a much safer mechanism than eval. Lastly, notice the $get at the end. This is a nice and easy selector that does all of the heavy lifting of finding the object in the DOM and the like.

<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
    function GetJson() {
        var request = new Sys.Net.WebRequest();
        request.get_headers()['Content-Type'] = 'application/json; charset=utf-8';
        request.set_url('/Artists/GetAll');

        request.add_completed(Function.createDelegate(null, DisplayArtists));
        request.invoke();
    }

    function DisplayArtists(executor) {
        if (executor.get_responseAvailable()) {
            var json = executor.get_responseData();
            var artists = Sys.Serialization.JavaScriptSerializer.deserialize(json);

            var newArtistList;
            newArtistList = "<ul>";

            for (var i in artists) {
                var artist = artists[i];
                newArtistList += "<li>"
                + artist.FirstName + " "
                + artist.LastName
                + "</li>"
            }

            newArtistList += "<ul>";

            $get("divOutput").innerHTML = newArtistList;
        }
    }
</script>

This is a lot less code and a lot safer than what I was doing in raw JavaScript. However, I thought I should try this with a few more frameworks.

Leveraging Prototype

image A framework that I’ve used for a while and really like is Prototype.

This is a whole lot less code. Notice the “Ajax.Request”. That packages up all of the work of doing the network call behind one simple to use function. And on the response is a nice and easy method called evalJSON that will parse out the JSON string to an array of objects that you can loop over. Finally, notice the $() selector.

<script src="../../Scripts/prototype-1.6.0.2.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
    function GetJson() {
        new Ajax.Request('/Artists/GetAll', {
            method: 'get',
            onSuccess: DisplayArtists
        })
      }

      function DisplayArtists(transport) {
        var json = transport.responseText.evalJSON();
        var newArtistList;
        newArtistList = "<ul>";

        json.each(function(artist) {
            newArtistList += "<li>"
                    + artist.FirstName + " "
                    + artist.LastName
                    + "</li>"
        });

        newArtistList += "<ul>";

        $("divOutput").insert(newArtistList);
    }
</script>

I liked this a lot. A feature that I didn’t take advantage of is that Scriptaculous, which is a fantastic set of JavaScript libraries for visualization, weaves in with Prototype really easily.

Leveraging jQuery

image The last JavaScript framework that I tried was jQuery. One extra cool part about this one for me is that I get intellisense right in Visual Studio. Check out Scott Guthrie’s post on jQuery Intellisense in VS2008 to see how to enable it.

Notice that it’s got the same type of easy to use function that packages up the call to get the JSON. Since it knows that it’s JSON, the variable returned to the callback is already parsed out into a usable object. And lastly, notice the $() selector again. There is a subtle difference between this one and the Prototype selector in that the jQuery one uses a # to signify that it’s looking for an ID, . to signify objects with a given class and so on.

<script language="javascript" type="text/javascript">
    function GetJson() {
        $.getJSON("/Artists/GetAll",
          {},
          DisplayArtists);
      }

      function DisplayArtists(data) {
          var newArtistList;
        newArtistList = "<ul>";

        for(var i = 0; i < data.length;i++)
        {
            var artist = data[i];
            newArtistList += "<li>"
                + artist.FirstName + " "
                + artist.LastName
                + "</li>"
        }

        newArtistList += "<ul>";

        $("#divOutput").html(newArtistList);
    }
</script>

Now that I was done playing with different JavaScript libraries, I thought I’d see if I could piece it all back together.

Leveraging jQuery and Silverlight

I decided to try jQuery and Silverlight together, leveraging jQuery to get and parse the JSON and Silverlight to do the display. This turned out to be remarkably simple.

First, in order for Silverlight to call into the JavaScript, you just have to call HtmlPage.Window.Invoke. That dynamically looks up and executes the method named in the first parameter.

void mainButton_Click(object sender, RoutedEventArgs e)
{
    HtmlPage.Window.Invoke("GetJson", "/Artists/GetAll");
}

Now, I could have wired up the JavaScript to listen for the button click event directly but that’s a lot more code than what I’ve got here.

Next I had to enable the Silverlight objects for callbacks. Step 1 is to Register the class with the browser’s scripting engine.

public LeveragingJQuery()
{
    InitializeComponent();
    HtmlPage.RegisterScriptableObject("LeveragingJQuery", this);
...
}

Step 2 is to declare one of the methods as a ScriptableMember. This gives the scripting engine access to the method in question. There’s also ScriptableType for creating serializable objects but that’s not what we need here. Notice, however, that the object type passed in is a ScriptObject. The slick part about this object is that it’s got a “ConvertTo” method that will take the weakly typed objects that it contains and serialize them to the type of object that you specify. This made the C# code here REALLY simple.

[ScriptableMember]
public void CallBackFromJavaScript(ScriptObject artists)
{
    List<Artist> listofartists = artists.ConvertTo<List<Artist>>();
    dataGrid1.ItemsSource = listofartists;
}

What’s left is the JQuery in the browser that we’re talking to. Notice that the first part is exactly the same. The second part, however, is a little different. First, we have to get a reference to the Silverlight plugin itself. Since I’m in a form object, ASP.NET mangles the name a little bit but it wasn’t too hard to figure out the new name. Next, I have to get the object that I had registered with the RegisterScriptableObject method. Then, all that’s left is calling the method to pass in my array of Artists.

<script src="/Scripts/jquery-1.2.6.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
    function GetJson(url) {
        $.getJSON(url,
          {},
          DisplayArtists);
    }

    function DisplayArtists(artists) {
        var control = document.getElementById("ctl00_MainContent_SilverlightPlugin");
        var leveragingJSPage = control.Content.LeveragingJQuery;
        leveragingJSPage.CallBackFromJavaScript(artists);
    }
</script>

Conclusion

This is how I learn about new things. I’m not satisfied with just getting the job done in one and only one way. I want to try out 3, 4, 5 different ways to accomplish a given task. That way I know what the right way to do something is in a given context. For example, I don’t know that I’ll ever need to mingle jQuery and Silverlight. But, I know how it’s done now and know that it’s a lot simpler than I originally thought it would be.

JSON is a simple but powerful format. There are a ton of simple services, from flickr to twitter to many of your production applications that could be producing JSON. It saves bandwidth compared to XML and is a just as simple to use.

Too much to see at the MDC Detroit

I’m not normally overly excited about the large Microsoft events, however, I’m really looking forward to the MDC Detroit next week.

The idea behind the show is that it’s taking the most critical sessions from PDC and repackaging them in a one day format.

I’ve had a chance to go through a lot of the content and see what all is going to be show. The cool part about it is that the vast majority of the talks are doing a demo. This is a big departure from a lot of the multi-city roadshows that Microsoft puts on and it’s a good thing. You’ll actually get to see code running. You’ll see applications being built. The other thing is that these demos are real world. It’s not hello world style demos. In my talk, I’m actually building a full line of business HR application that reads and writes from the database.

The talk that I’m doing is the Silverlight talk. Those of you who know me are not shocked by that. 🙂 The cool part is that there are two parts to the talk. First, I’m going to show what you can do with current and shipping technologies. Then I’m going to show you what’s coming next.

Web technologies not your bag, there’s still plenty to see. Specifically, there are three different tracks. I’m in the Client and Presentation track. I’m just happy that there’s a lunch between me and Billy Hollis. That’ll give the audience to forget how awesome he was before coming and hearing me.

AGENDA

Time Table Azure Services Platform for Cloud Computing Client and Presentation Tools, Languages and Framework
7:00-8:30 Registration and Breakfast
8:30-10:00 Ron JacobsThe day starts off with a keynote presented by Ron Jacobs. If you’ve not heard Ron speak before, you’re in for a treat. He’s a dynamic and engaging speaker on any topic.
10:00-10:15 Break
10:15-11:30 Brian PrinceA Lap Around Windows Azure and the Azure Services Platform
Brian Prince
Jeff Hunsaker
Jason Karns
ASP.NET and JQuery
Jeff Hunsaker
Jason Karns
Bill WagnerThe Future of Managed Languages: C# and Visual Basic
Bill Wagner
11:30-12:30 lunch
12:30-1:45 Jennifer MarsmanDeveloping and Deploying Your First Azure Service
Jennifer Marsman
Billy HollisDeveloping Data-Centric Applications Using the WPF DataGrid and Ribbon Controls
Billy Hollis
Delbert MurphyA Lap Around “Oslo”
Delbert Murphy
Darryl Hogan (note that Darryl didn’t send in a photo.)
1:45-2:00 Break
2:00-3:15 Jeff BlankenburgA Lap Around the Live Framework and Mesh Services
Jeff Blankenburg
Josh HolmesBuilding Business-Focused Applications Using Silverlight 2
Josh Holmes

Randy Pagels
Tony Jimenez
A Lap Around VSTS 2010
Randy Pagels
Tony Jimenez

3:15-3:30 Break
3:30-4:45 Chris WoodruffDeveloping Applications Using Microsoft SQL Data Services
Chris Woodruff

Carey Payette
Jeff McWherter
ASP.NET 4.0 Roadmap
Carey Payette / Jeff McWherter

Jay WrenAn Introduction to Microsoft F#
Jay Wren

Chuck Norris writes code under the name Josh Holmes

I love Chuck Norris jokes. One of my favorites is “Some people wear Superman pajamas. Superman wears Chuck Norris pajamas.” There are a ton of them out there. There are even entire web sites dedicated to Chuck Norris jokes such as http://www.thechucknorrisfacts.com/. Most of those jokes are hysterical though some are slightly less than politically correct.

So Bill Wagner accidentally started jokes about me. Bill was actually responding to me when I posted that it was -8 outside. The full context is that “-8 keeps out the riff raff” but as you can read below, it looks like he was saying that I’m the one that keeps out the riff raff.

Leon Gershing (aka fallenrogue) took that and ran with it ala Chuck Norris jokes. Since then a ton of people have started piling on. (btw – Leon actually named this post to)

Bill_color_small_normalbillwagner: @joshholmes Keeps out the riff raff.
1 day ago · Reply · View Tweet
Photo_22_normal fallenrogue: @billwagner I hear @joshholmes‘ tears cure cancer…. too bad he’s never cried.
1 day ago · Reply · View Tweet
Photo_22_normalfallenrogue: I also hear that @joshholmes has to register any code he writes as lethal weapons.
1 day ago · Reply · View Tweet
Picture_14_normalusher: Good laugh of the day – RT @fallenrogue: I also hear that @joshholmes has to register any code he writes as lethal weapons.
1 day ago · Reply · View Tweet

Photo_35_normaljoefiorini: @fallenrogue I’ve heard that @joshholmes‘ failing tests pass anyway because they are too scared to fail.
1 day ago · Reply · View Tweet
3187276048_580e77883b-1_normalcoreyhaines: @joefiorini I heard that @joshholmes‘ testing framework writes tests for @joshholmes
1 day ago · Reply · View Tweet
Photo_22_normalfallenrogue: @joefiorini @joshholmes can’t do TDD because it’s impossible to follow “Red > Green > Refactor” when his code only goes green.
1 day ago · Reply · View Tweet
Photo_35_normaljoefiorini: @fallenrogue exactly; @joshholmes doesn’t need TDD. His code works the first time.
1 day ago · Reply · View Tweet
3187276048_580e77883b-1_normalcoreyhaines: @joefiorini @fallenrogue @joshholmes code refactors itself
1 day ago · Reply · View Tweet
Mike1981_1__normalViNull: According to NSA regulations, only @joshholmes is allowed to carry @joshholmes code across state lines
1 day ago · Reply · View Tweet
Head_shot_v2_normal brianhprince: @ViNull and chuck norris of course
1 day ago · Reply · View Tweet
Mike1981_1__normal ViNull: @brianhprince I heard Chuck Norris tried to out code @joshholmes once and broke all his fingers
1 day ago · Reply · View Tweet
Photo_35_normaljoefiorini: Lesson learned: no amount of careful can replace testing.
about 13 hours ago · Reply · View Tweet
Photo_22_normalfallenrogue: @joefiorini except for @joshholmes who, btw, wrote a program that’s already counted to infinity… twice.
about 13 hours ago · Reply · View Tweet
Photo_35_normaljoefiorini: @fallenrogue of course that was after he wrote a program to find all possible Marseinne primes. @joshholmes
about 12 hours ago · Reply · View Tweet
Photo_22_normalfallenrogue: You know why you can’t mock HttpContext in .Net? because @joshholmes wrote it and @joshholmes WILL NOT BE MOCKED!!!!
about 12 hours ago · Reply · View Tweet
Chris_roland_normalChrisRoland: @joshholmes Snores in binary and that’s how the internet was born.
about 12 hours ago · Reply · View Tweet
Mike1981_1__normalViNull: I heard @joshholmes beard can optimize and compile 8088 assembly faster than Deep Thought
about 5 hours ago · Reply · View Tweet
 
And after Chris Woodruff got stuck in the median in a snow storm…
 
Head_shot_v2_normalbrianhprince: @cwoodruff being as tall as you are, I figured you just picked up your car ‘hulk style’ and put it back on the road
about 2 hours ago · Reply · View Tweet
Mikewood-headshot_normalmikewo: @brianhprince Come on now, it’s not like @cwoodruff is @joshholmes or Chuck Norris.
about 2 hours ago · Reply · View Tweet

 

Keep those jokes rolling… I might just print these off as my next resume. Or I might start handing out pajamas. 🙂

*Update – a lot more jokes added below – enjoy! *

Marty_normal MartyAdams: @joshholmes can squeeze orange juice from a banana
about 19 hours ago · Reply · View Tweet
Carey_normalcareypayette: A man once asked @joshholmes if his real name is “Jo”. @joshholmes did not respond, he simply stared at him until he exploded.
about 19 hours ago · Reply · View Tweet
Carey_normalcareypayette: @joshholmes threads don’t sleep … they wait!
about 19 hours ago · Reply< /a> · View Tweet
Marty_normalMartyAdams: @crazeegeekchick @careypayette go straight to the Mountain Dew. Enough caffeine to kill a horse! (but not @joshholmes)
about 19 hours ago · Reply · View Tweet
Pblogo_normalPainBank: ‘@joshholmes can code so well he can squeeze a Perl out a Python that looks like a Ruby, yet runs under .Net faster than C++’ C.Norris
about 19 hours ago · Reply · View Tweet
Marty_normalMartyAdams: thought of this this morning while driving in… @joshholmes doesn’t actually write code, he wills applications into existence.
about 4 hours ago · Reply · View Tweet
Mikewood-headshot_normalmikewo: @aaronlerch @joshholmes doesn’t write workarounds. Whatever he codes becomes the best practice.
about 3 hours ago · Reply · View Tweet

Jared Spool re-convinces me that UX Matters

Jared Spool

Jared Spool is one of my heroes. I go hear him speak every time that I get a chance to and have often retold a number of his stories with various clients. One of the first times that I heard him speak was at the Software Development Conference in 2000.

Jared is a usability expert. That does not mean graphic designer. That means that his expertise is understanding the user and building an experience that is relevant and meaningful in the user’s context.

So what is a “User’s Context”? It’s all of the things that make up your user and how they work. What’s their education level (high school, college, doctorate)? How loud is the work environment (are they on a call center floor? are they in an office by themselves?)? How many and how big are the individual tasks that the user has to perform (is it clicking one button or filling in a 1000 question survey)? Are they wearing gloves while working (such as a mechanic)? Are they familiar with the application (such as an internal application) or are they new to the application (such as a publicly facing web site)? What’s the average tenure of an employee? All of these things and more make up the context for the user and dramatically change the needs of the user for a given application.

He talks about the process that his firm goes through where they start with “Users in the Mist”, all props to Dian Fossey. This involves sometimes 2 or more weeks of just observing the users at work in their natural environment. This gives him a good understanding of the users and how they work so that the software that he’s helping create will slide right into the way that they need to work without them having to spend time fighting to the tools. Sometimes, the result is actually not more software. I know that’s shocking but it’s true. One of these stories ended up solving the worker’s issue with plywood and Christmas tree lights. That’s cool.

I have a tremendous amount of respect for those that have graphic artist abilities because I’ve got none. However, you should not confuse that with usability. This point is very clearly demonstrated in his latest article on his blog – UIEtips: The $300 Million Button » UIE Brain Sparks. In this article, he talks about a fairly straight forward ecommerce site that was loosing millions a year and they couldn’t figure out why. They brought in Jared’s team who after a few weeks of usability testing with real users changed the working on the button for a $300 million dollar jump in profits the following year. The button was pretty enough, functional enough and so on but the user’s didn’t understand the ramifications of clicking the button. That’s an issue that they found through extensive usability testing.

Before you spend a lot of time and money building a beautiful skin to your application, make sure that you understand your users and that you’ve built the application in such a way that it works for them rather than them working for the application.

Missed the PDC? Catch the content live at the MDC!

The Professional Developers Conference (PDC) is one of my favorite conferences.  But it is an investment, especially when you factor in the cost of airfare and a week in a downtown LA hotel, in addition to the cost of the conference.  In today’s unstable economy, some people missed out on a lot of cool technical content. 

clip_image00138

But, the MSDN Developer Conference (MDC) is bringing the PDC to you!  The MDC is a day-long conference with three parallel tracks, summarizing the essentials of the PDC, for only $99.  These events will be held in 11 major cities across the US.  Hear all of the exciting announcements around the Azure Services Platform, Windows 7, and Visual Studio 2010 – the session lineup is pretty compelling. 

Windows7_h_rgbAnd of course, there are great giveaways and swag!  The most exciting thing is that all attendees will receive a Windows 7 Beta DVD.  If the Windows 7 Beta is not available at the time of the event, the DVD will be shipped to you when it becomes available.

There are other worthwhile gatherings happening at the MDC:

Community Courtyard: Perhaps you’ve seen the PDC content already, but want a chance to discuss it?  Maybe you have questions or still just don’t get what the excitement around Azure is all about.  The Community Courtyard is an Open-Space-like environment, where attendees can propose topics to discuss and convene their own sessions!  Leaders in the development community as well as Microsoft employees will be hanging around to answer questions and participate in the conversations. 

WomenBuild: This interactive workshop is open to both men and women.  Participants utilize Lego bricks to explore different solutions to the same problem, and celebrate the true meaning of diversity. 

Register today

Date          City

1/13/2009 Chicago, IL

1/13/2009 Minneapolis, MN

1/16/2009 Washington, DC

1/20/2009 New York, NY

1/22/2009 Boston, MA

1/22/2009 Detroit, MI

1/26/2009 Dallas, TX

2/23/2009 San Francisco, CA