HighBall Part Duex (#01)

I'm working through this next part of my HighBall Project, which I'll be blogging regularly, using TDD and UI/X First Development.  In other words, to give some context, I'm building out a UI first, then I'll start from the back end and build together using primarily TDD style development.  I'll admit, I'm a bit unsure of how to go about building out the UI with a TDD style process.  But hopefully by the end of this little application building exercise I'll have it figured out.

My basic user stories so far is as follows.

  1. As a manager I want to create a schedule for a particular route.
  2. As a manager I want to delete an old schedule for a particular route.
  3. As a manager I want to view all of the schedules for all routes.
  4. As a manager I want to view the history of all past schedules for all routes.
  5. The driver needs to select a route and view the route schedule.

Basically we have the simple CRUD operations for a schedule tracking system.  I'll elaborate more as I work through this project.

For the first step I created the follow UI pieces in Silverlight & WPF, one for web and one for desktop.  Eventually I might even toss in the ASP.NET MVC for a non-Silverlight web version.  But for now the first step is to mock up the screens as the manager & drivers would view them.

Mocking Up the Screens

I created the create screen first to figure out how I would do this.  Keep in mind I'm going at this almost completely blind, as I'm not even sure what the actual architecture might be.  I'm merely giving both of these approaches a shot at the same time.  One last note, I'll be using TriMet, NJ Transit, and Sound Transit as my sources of example data, so if it seems familiar, it is.

The first view module that I built was the add route schedule screen.  Upon completion of the basic screen I was amazed at how similar the xaml was for the Silverlight and the WPF.  With this level of similarity I'm thinking there will be many more ways to refactor the xaml itself.  Maybe even create a xaml view generator?  At this point, the goal is to get the view modules created, so back to work.  Here is my first module below.  So far the WPF and Silverlight screen are exactly the same.

<UserControl x:Class="HighBall.Interface.Wpf.ScheduleAdd"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Foreground="White" Background="Black">
    <Grid x:Name="LayoutRoot" Background="Black">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
 
        <TextBlock Margin="5,5,5,5" x:Name="textRoutes">Routes:</TextBlock>
        <ListBox Margin="5,5,5,5" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <ListBoxItem x:Name="routeOne" Content="WES Commuter Rail"></ListBoxItem>
            <ListBoxItem x:Name="routeTwo" Content="9 Powell"></ListBoxItem>
            <ListBoxItem x:Name="routeThree" Content="72 Killingsworth/82nd Ave"></ListBoxItem>
            <ListBoxItem x:Name="routeFour" Content="590 Tacoma/Seattle"></ListBoxItem>
            <ListBoxItem x:Name="routeFive" Content="Sounder Commuter Rail"></ListBoxItem>
            <ListBoxItem x:Name="routeSix" Content="The Newark Light Rail Orange Line"></ListBoxItem>
            <ListBoxItem x:Name="routeSeven" Content="The Newark Light Rail Blue Line"></ListBoxItem>
            <ListBoxItem x:Name="routeEight" Content="The River Line"></ListBoxItem>
        </ListBox>
 
        <TextBlock x:Name="routeName" Margin="0,5,5,5" Grid.Column="1" Grid.Row="0"  >Add New Schedule</TextBlock>
 
        <StackPanel Grid.Column="1" Grid.Row="1" >
            <TextBlock x:Name="frequencyIdentifier" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1"  HorizontalAlignment="Left" VerticalAlignment="Top">Frequency Identifier</TextBlock>
            <TextBox x:Name="textFrequencyIdentifier"  Margin="0,5,5,0" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text=""></TextBox>
            <TextBlock x:Name="startLocation" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1"  HorizontalAlignment="Left" VerticalAlignment="Top">Start Location</TextBlock>
            <TextBox x:Name="textStartLocation"  Margin="0,5,5,0" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text=""></TextBox>
            <TextBlock x:Name="startTime" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1"  HorizontalAlignment="Left" VerticalAlignment="Top">Start Time</TextBlock>
            <TextBox x:Name="textStartTime"  Margin="0,5,5,0" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text=""></TextBox>
            <TextBlock x:Name="endLocation" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1"  HorizontalAlignment="Left" VerticalAlignment="Top">End Location</TextBlock>
            <TextBox x:Name="textEndLocation"  Margin="0,5,5,0" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text=""></TextBox>
            <TextBlock x:Name="endTime" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1"  HorizontalAlignment="Left" VerticalAlignment="Top">End Time</TextBlock>
            <TextBox  x:Name="textEndTime" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text=""></TextBox>
            <TextBlock x:Name="scheduleStarts" Margin="0,5,5,0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top">Schedule Starts</TextBlock>
            <TextBox  x:Name="textScheduleStarts" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text=""></TextBox>
            <TextBlock x:Name="scheduleEnds" Margin="0,5,5,0" Grid.Column="1"  HorizontalAlignment="Left" VerticalAlignment="Top">Schedule Ends</TextBlock>
            <TextBox  x:Name="textScheduleEnds" Margin="0,5,5,0" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text=""></TextBox>
            <Button x:Name="buttonAddNewSchedule" Margin="10,10" Grid.Column="1" Grid.Row="1" Height="Auto" Width="Auto" HorizontalAlignment="Right"  VerticalAlignment="Top" Content="Add Schedule"></Button>
        </StackPanel>
        
    </Grid>
</UserControl>

The next screen I built was the view all module.  Since I would most likely reuse this screen, or at least a large part of it, for the delete screen it would be best not to get the cart before the horse.

<UserControl x:Class="HighBall.Interface.Silverlight.ScheduleViewAll"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <ListBox x:Name="listSchedules">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="260" Text="{Binding Path=FrequencyIdenfitier}"/>
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="210" Text="{Binding Path=Route}"/>
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="100" Text="{Binding Path=StartLocation}"/>
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="100" Text="{Binding Path=EndLocation}"/>
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="140" Text="{Binding Path=ScheduleStarts}"/>
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="140" Text="{Binding Path=ScheduleEnds}"/>
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="80" Text="{Binding Path=StartTime}"/>
                        <TextBlock Width="Auto" Height="Auto" Padding="5" MinWidth="80" Text="{Binding Path=EndTime}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</UserControl>

To test out what it would look like I added the following class and code just for an example.

using System;
using System.Collections.Generic;
using System.Windows.Controls;
 
namespace HighBall.Interface.Silverlight
{
    public partial class ScheduleViewAll : UserControl
    {
        public ScheduleViewAll()
        {
            InitializeComponent();
 
            var schedules = LoadTestViewData();
            listSchedules.ItemsSource = schedules;
        }
 
        private static List<RouteSchedule> LoadTestViewData()
        {
            var schedules =
                new List<RouteSchedule>
                    {
                        new RouteSchedule
                            {
                                Route = "WES Commuter Rail",
                                EndLocation = "Beaverton",
                                EndTime = DateTime.Now.AddHours(-5),
                                FrequencyIdenfitier = Guid.NewGuid().ToString(),
                                ScheduleEnds = DateTime.Now.AddDays(185),
                                ScheduleStarts = DateTime.Now.AddDays(5),
                                StartLocation = "Wilsonville",
                                StartTime = DateTime.Now.AddHours(10)
                            },
                        new RouteSchedule
                            {
                                Route = "WES Commuter Rail",
                                EndLocation = "Wilsonville",
                                EndTime = DateTime.Now.AddHours(-5),
                                FrequencyIdenfitier = Guid.NewGuid().ToString(),
                                ScheduleEnds = DateTime.Now.AddDays(185),
                                ScheduleStarts = DateTime.Now.AddDays(5),
                                StartLocation = "Beaverton",
                                StartTime = DateTime.Now.AddHours(10)
                            },
                        new RouteSchedule
                            {
                                Route = "WES Commuter Rail",
                                EndLocation = "Beaverton",
                                EndTime = DateTime.Now.AddHours(-5.5),
                                FrequencyIdenfitier = Guid.NewGuid().ToString(),
                                ScheduleEnds = DateTime.Now.AddDays(185),
                                ScheduleStarts = DateTime.Now.AddDays(5),
                                StartLocation = "Wilsonville",
                                StartTime = DateTime.Now.AddHours(9.5)
                            },
                        new RouteSchedule
                            {
                                Route = "WES Commuter Rail",
                                EndLocation = "Wilsonville",
                                EndTime = DateTime.Now.AddHours(-5.5),
                                FrequencyIdenfitier = Guid.NewGuid().ToString(),
                                ScheduleEnds = DateTime.Now.AddDays(185),
                                ScheduleStarts = DateTime.Now.AddDays(5),
                                StartLocation = "Beaverton",
                                StartTime = DateTime.Now.AddHours(9.5)
                            },
                        new RouteSchedule
                            {
                                Route = "590 Tacoma/Seattle",
                                EndLocation = "Seattle",
                                EndTime = DateTime.Now.AddHours(-5),
                                FrequencyIdenfitier = Guid.NewGuid().ToString(),
                                ScheduleEnds = DateTime.Now.AddDays(185),
                                ScheduleStarts = DateTime.Now.AddDays(5),
                                StartLocation = "Tacoma",
                                StartTime = DateTime.Now.AddHours(10)
                            }
                    };
 
            return schedules;
        }
    }
 
    public class RouteSchedule
    {
        public string Route { get; set; }
        public string FrequencyIdenfitier { get; set; }
        public string StartLocation { get; set; }
        public string EndLocation { get; set; }
        public DateTime StartTime { get; set; }
        public DateTime EndTime { get; set; }
        public DateTime ScheduleStarts { get; set; }
        public DateTime ScheduleEnds { get; set; }
    }
}

While trying to get this to work in the Silverlight screen I ran into the dreaded "AG_E_INVALID_ARGUMENT" exception.  This is some type of xaml parsing issue, which I jumped right out to Google to try and figure out.  The link above eventually led me to this entry on the silverlight forums.  Even after digging through all of these ancient (in Silverlight terms) fixes, I still had the error.  At this point I threw up my hands and recreated the entire screen.  Once I did that, it worked.  However, the Silverlight xaml screen stopped color coding the xaml correctly and shaded out ALL of the ListBox.ItemTemplate xaml between the tags.  I don't know what is wrong with this but it is extremely annoying.

StringFormat is another thing that works in WPF but not in Silverlight.  I started to use them to format the date time bound fields.  Since there is this disparity, I just left that as is.  I'll eventually get back to cleaning up data a bit later.

At this point I needed to wire these together for the customer (which at this point is me, but I'm following Agile Practice).  I didn't want to get too many UI modules done and then realize I had to change significant parts.  In my next entry I'll cover working with the Composite Application Library (used to be the Composite Application Block, but that's evil) to get two builds, one for Silverlight and one for WPF.

Other bits of Information relating to user stories, UI/X, TDD, and other topics.

Of course, grab the code on Codeplex for HighBall.

kick it on DotNetKicks.com
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 3/30/2009 at 7:35 AM
Tags: , , , ,
Categories: How-To, Samples, and Such | Highball
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (2) | Post RSSRSS comment feed

Using HTTP Compression for Faster Downloads With .NET C#

IIS provides the following compression options:

  • Static files only.   
  • Dynamic application responses only.
  • Both static files and dynamic application responses.

It is important on dynamic responses that the resource is compressed on the fly every single time it is requested.  This can cause some heavy processor utilization.

To enable HTTP compression (IIS 6.0) follow these steps.  You must be an adminstrator to complete these steps, so use the runas or command prompt with

runas /user:Administrative_AccountName"mmc %systemroot%\system32\inetsrv\iis.msc" 

to gain access to IIS.

...as quoted steps from Microsoft TechNet for IIS 6.0 Compression Settings...

  1. To enable global HTTP compression by using IIS Manager
    In IIS Manager, double-click the local computer, right-click the Web Sites folder, and then click Properties.
  2. Click theService tab, and in the HTTP compression section, select the Compress application files check box to enable compression for dynamic files.
  3. Select the Compress static files check box to enable compression for static files.
  4. In the Temporary directory box, type the path to a local directory or click Browse to locate a directory. Once a static file is compressed, it is cached in this temporary directory until it expires, or the content changes. The directory must be on the local drive of an NTFS–formatted partition. The directory cannot be compressed or shared, and the access control lists (ACLs) for the directory must include Full Control access to the identity of the application pool or to the IIS_WPG group.
  5. Under Maximum temporary directory size, click a folder size option. If you specify a maximum size under Limited to (in megabytes) (the default setting is 95 MB), then when the limit is reached, IIS automatically cleans up the temporary directory by applying the "least recently used" rule.
  6. Click Apply, and then click OK.

To enable global HTTP compression by using Adsutil.vbs

  1. Open a command prompt.
  2. To enable dynamic compression, type the following at the command prompt and then press ENTER:
    cscript adsutil.vbs set w3svc/filters/compression/parameters/HcDoDynamicCompression true 
  3. To enable static compression, type the following at the command prompt and then press ENTER:
    cscript adsutil.vbs set w3svc/filters/compression/parameters/HcDoStaticCompression true 

To enable HTTP Compression for Individual Sites and Site Elements

  1. Disable global static compression by executing the following command at a command prompt:
    adsutil set w3svc/filters/compression/parameters/HcDoStaticCompression false 
  2. Enable static compression at this directory by executing the following command at a command prompt:
    adsutil set w3svc/1/root/Home/StyleSheets/DoStaticCompression true 

To disable static compression for only a single directory, first enable global static compression (if it is disabled) and then disable static compression at that directory. For example, to enable static compression for a directory at http://www.contoso.com/Home/StyleSheets, perform the following steps:

  1. Disable global static compression by executing the following command at a command prompt:
    adsutil set w3svc/filters/compression/parameters/HcDoStaticCompression true 
  2. Enable static compression at this directory by executing the following command at a command prompt:
    adsutil set w3svc/1/root/Home/StyleSheets/DoStaticCompression false

For IIS 7.0 information I found some on www.iis.net.  If you're looking to setup IIS 7 this is by far the best source.  So go check it out.

...the next step of course, is to make sure you have requested via the HTTP Header context that the server return the content in compressed encoding.  This can save upwards of 75% on size.

The way this content encoding is provided via the header shows up like this.

Browsers and servers have brief conversations over what they'd like to receive and send. Using HTTP headers, they zip messages back and forth over the ether with their content shopping lists. A compression-aware browser tells servers it would prefer to receive encoded content with a message in the HTTP header like this:

GET / HTTP/1.1
Host: www.webcompression.org
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) 
  Gecko/20031007 Firebird/0.7
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,
  text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive 

An HTTP 1.1-compliant server would then deliver the requested document with using an encoding accepted by the client. Here's a sample response.

HTTP/1.1 200 OK
Date: Thu, 04 Dec 2003 16:15:12 GMT
Server: Apache/2.0
Vary: Accept-Encoding
Content-Encoding: gzip
Cache-Control: max-age=300
Expires: Thu, 04 Dec 2003 16:20:12 GMT
X-Guru: basic-knowledge=0, general-knowledge=0.2, complete-omnipotence=0.99
Content-Length: 1533
Content-Type: text/html; charset=ISO-8859-1

Client Code for Requesting Compression

So how does one get the content type programmatically?  Easy, and here's a quick example I put together in C# using standard HttpWebRequest objects to request compression.

namespace Sdk.Tests
{
    [TestFixture]
    public class TestsProvidingCodeSamples
    {
        [Test]
        public void TestBaselineCompressedRequest()
        {
            // Use Twitter or whatever other service is available.
            var request = (HttpWebRequest)WebRequest.Create("https://somedomain/somepage.aspx");
            request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
            request.Credentials = new NetworkCredential("someUser", "somePassword");
 
            var response = request.GetResponse();
            var responseStream = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            string getTheResults = responseStream.ReadToEnd();
 
            Assert.IsNotNull(responseStream);
            Assert.IsNotNull(getTheResults);
        }
    }
}

This should get anyone kick started to assuring that your data over the Internet is compressed and efficiently being transferred.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 3/24/2009 at 5:07 PM
Tags: , , , , ,
Categories: How-To, Samples, and Such
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Kickin' It Out

Silverlight leaves the browser behind!  This is what I've been waiting for.  Silverlight now effectively has all the parts & features I want to effectively rule out the need for Flex, Flash & Air.  With Silverlight moving outside of the browser we provide, finally, a true speedy application for RIAs.  Of course, yeah yeah yeah, Java did this over a decade ago, but it did so poorly.  Silverlight is FAST.  I'd gather it is faster than Air, and possibly faster than Flash in the majority of measurable ways.

Now the big question that remains, is what will happen to WPF.  This significantly decreases the need for WPF for use as a web connected apps framework.  WPF is now relegated to only Windows.  WPF seems like a less viable platform than ever with Silverlight being enabled in and out of the browser, at least for LOB business apps and that ilk.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 3/24/2009 at 7:36 AM
Tags: , ,
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

TFS Sync & VS Bugz :: Tip o' The Day

If you receive this error, "TF31005: Team Foundation cannot retrieve the list of team projects because it cannot connect to Team Foundation Server", or if you are debugging and the code you see on screen is not what is being stepped through or you see VS stepping through white space lines, try this out.

Clear out the cache here on Vista...

C:\Users\userName\AppData\Local\Microsoft\Team Foundation\2.0\Cache 

...or try clearing out this directory on XP/Server 2003.

C:\Documents and Settings\userName\Local Settings\Application Data\Microsoft\Team Foundation\2.0\Cache 

This should get the ball rolling for Visual Studio & TFS Synchronization again.

UPDATE:  This thing kept nagging me throughout the day until Denis (coworker) finally got into the logs and found this "Invalid length parameter passed to the SUBSTRING function".  This occurs, usually, right after a SP1 upgrade on the TFS Server.  After poking around a while Denis found this KB.  After running a simple update statistics...

use tfsintegration
 
update statistics tbl_security_identity_cache

...all was running flawlessly after that.  Only an 8 hour day lost.  :(  But hey!  At least this helps somebody out there!

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 3/23/2009 at 12:08 PM
Tags: , , , ,
Categories: Tip o' The Day
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Continuous Integration? Ha!

I just stumbled onto this entry by pure accident.  It however really struck a note with me.  I'm a BIG fan of lean agile.  Agile without the iterations, just continuous, fast, always integrating and always developing software.  It's fast, absurdly fast, and when the practice is done right, the code quality increases in a very significant way.  Deployments though have always seemed to be a little bumpy still.

Well what about Continuous Deployment? This just might be one of the major missing pieces to the whole lean agile process!  I think I might just set it up for fun and see how it transpires. 

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 3/10/2009 at 12:12 AM
Tags: ,
Categories: Agile, Theory, and Process Stuff | Just Stuff | Keeping Up
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

JSON Serialization & Deserialization, The Simple Stuff (Part 1)

Here's a few snippets outlining serialization and deserialization of a few object with JSON.  At first I started using JSON.NET but it is a bit picky about various things and the samples I found where disparate.  I then realized also that in the System.Web.Extensions Namespace there is a class that handles JSON anyway.  Might as well use it since it is already included.  Please note, I'm merely using unit tests below to showcase the functionality of the serialization and deserialization of JSON, there is no real need to unit test the class functionality, just what you'll do in your own code in isolation of the particular serialization and deserialization.  If you want to test your serializations and deserializations that is fine, I'm merely suggesting that it doesn't particularly need to be.

First things first, let's get some data serializing.  Here's my basic class I'm starting with.

public class ProfileItem
{
    public string Name;
    public string Id;
}
 
public class ReportItem
{
    public string accountID;
    public string name;
    public string ID;
}

Notice here how I've used proper code analysis naming & case convention on the ProfileItem but not on the ReportItem.  I've done this to show how the Microsoft JSON Serialize uses intelligent mapping to pair up properties that have case differences.  This is something I like since One might want to follow the conventions, while the data properties you?re consuming might break convention.

Next step was to generate some data.  First add the reference to System.Web.Script.Serialization.  Then munge up some data.  I created and verified the serialization of one object as below.

[Test]
public void TestJsonSerialization()
{
    const string serializedResult = @"{""Name"":""TheProfileName"",""Id"":""01cc6fd1-79ec-4ca9-b84c-48a5cf35e666""}";
 
    var javaScriptSerializer = new JavaScriptSerializer();
 
    var profileItem =
        new ProfileItem
            {
                Id = new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e666").ToString(),
                Name = "TheProfileName"
            };
 
    var serializedProfileItem = javaScriptSerializer.Serialize(profileItem);
 
    Assert.IsNotNull(serializedProfileItem);
    Assert.AreEqual(serializedProfileItem, serializedResult);
}

Now that I?ve verified the serialization, I?m going to test the deserialization.

[Test]
public void TestJsonDeserialization()
{
    const string serializedResult = @"{""Name"":""TheProfileName"",""Id"":""01cc6fd1-79ec-4ca9-b84c-48a5cf35e666""}";
    var javaScriptSerializer = new JavaScriptSerializer();
 
    var deSerializedResult = javaScriptSerializer.Deserialize<ProfileItem>(serializedResult);
 
    Assert.AreEqual(deSerializedResult.Id, @"01cc6fd1-79ec-4ca9-b84c-48a5cf35e666");
    Assert.AreEqual(deSerializedResult.Name, "TheProfileName");
}

With that complete I have two working examples of basic serialization and deserialization.  Now for a few twists on that to see what kind of results we get.  As I pointed out above I have the ReportItem with the case convention that is, well, disliked by code anlysis/fxCop etc.  Here's an example of how one can have a serialized object with incongruent convention, but you can create an object that has your own desired casing.  Before moving forward, I created one more class, which one can tell what I'm up to by its name.

public class ReportItemMyWay
{
    public string AccountId;
    public string Name;
    public string Id;
}

Now that I have a class done the way I?d prefer the convention I?ll get some data serialized with the convention of the ReportItem class I created above.

[Test]
public void TestJsonSerializationToDeserializationCasing()
{
    const string serializedResult =
        @"{""accountID"":""01cc6fd1-79ec-4ca9-b84c-48a5cf35e661"",""name"":""Campaigns by Countries"",""ID"":""01cc6fd1-79ec-4ca9-b84c-48a5cf35e662""}";
    var javaScriptSerializer = new JavaScriptSerializer();
 
    var reportItem =
        new ReportItem
            {
                accountID = new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e661").ToString(),
                ID = new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e662").ToString(),
                name = "Campaigns by Countries"
            };
 
    var serializedReport = javaScriptSerializer.Serialize(reportItem);
 
    Assert.AreEqual(serializedResult, serializedReport);
 
    var deserializedReport = javaScriptSerializer.Deserialize<ReportItemMyWay>(serializedReport);
 
    Assert.AreEqual(deserializedReport.Id, reportItem.ID);
    Assert.AreEqual(deserializedReport.Name, reportItem.name);
    Assert.AreEqual(deserializedReport.AccountId, reportItem.accountID);
}

You'll notice that the deserialized object goes smoothly into the new class with the preferred casing & such.  Now for some other twisted bits.  Often the data will get serialized in and deserialized as Generic Lists of X Type.  The example below shows what the results look like if a list of ReportItem Objects are serialized.

At this point I stumbled on some pure genius.  If you look at the previous examples I was using the @ symbol to build all of the JSON strings.  Well, when I copy them from the value when debugging (yeah, that's how I grabbed the strings of JSON), they're all automatically escaped.  So in the example below, you'll notice how the string is escaped and I just left the @ off.  Whoduthunkit.  :/

[Test]
public void TestJsonSerializationOfLists()
{
    const string serializedResult =
        "[{\"AccountId\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e661\",\"Name\":\"Campaigns by Countries\",\"Id\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e662\"},{\"AccountId\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e663\",\"Name\":\"Geography by RSS Feeds\",\"Id\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e664\"}]";
    var javaScriptSerializer = new JavaScriptSerializer();
 
    var reportItem1 =
        new ReportItemMyWay
            {
                AccountId = new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e661").ToString(),
                Id = new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e662").ToString(),
                Name = "Campaigns by Countries"
            };
    var reportItem2 =
        new ReportItemMyWay
            {
                AccountId = new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e663").ToString(),
                Id = new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e664").ToString(),
                Name = "Geography by RSS Feeds"
            };
 
    var reportItemMyWays =
        new List<ReportItemMyWay> {reportItem1, reportItem2};
 
    var serializedList = javaScriptSerializer.Serialize(reportItemMyWays);
 
    Assert.AreEqual(serializedList, serializedResult);
}

This points out the multiple levels for the Generic List serialization.  The deserialization smoothly puts it right back into the ole object per the test below.

 
[Test]
public void TestJsonDeserializationOfLists()
{
    const string serializedResult =
        "[{\"AccountId\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e661\",\"Name\":\"Campaigns by Countries\",\"Id\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e662\"},{\"AccountId\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e663\",\"Name\":\"Geography by RSS Feeds\",\"Id\":\"01cc6fd1-79ec-4ca9-b84c-48a5cf35e664\"}]";
    var javaScriptSerializer = new JavaScriptSerializer();
 
    var serializedList = javaScriptSerializer.Deserialize<List<ReportItemMyWay>>(serializedResult);
 
    Assert.AreEqual(serializedList[0].Id,new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e662").ToString());
    Assert.AreEqual(serializedList[0].Name, "Campaigns by Countries");
    Assert.AreEqual(serializedList[0].AccountId, new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e661").ToString());
 
    Assert.AreEqual(serializedList[1].Id, new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e664").ToString());
    Assert.AreEqual(serializedList[1].Name, "Geography by RSS Feeds");
    Assert.AreEqual(serializedList[1].AccountId, new Guid(@"01cc6fd1-79ec-4ca9-b84c-48a5cf35e663").ToString());
}

I'll have some follow up entries on getting data type specifics in and out of the JSON Objects.  The JSON serialization gets tricky, annoying, and a bit confusing when I jump into data types so subscribe - cheers.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 3/9/2009 at 7:50 AM
Tags: , , , ,
Categories: How-To, Samples, and Such
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

A Binding Experience :: Tip o' The Day

I was trying to get some deserialized JSON objects to bind to my WPF application interface and was struggling.  I figured out what the fix was, I took the shortcut route on my objects and should have built them correctly.

My original objects where built as such:

public class ReportItem
{
    public string AccountId;
    public string Name;
    public string Id;
}

However, they should have appeared as follows:

public class ReportItem
{
    public string AccountId { get; set; }
    public string Name { get; set; }
    public string Id { get; set; }
}

The classes that will be bound need to have legitimate properties, not merely public members.

Now when I do a binding via the XAML

        <ComboBox 
            Margin="193,75,12,0" 
            Name="comboProfiles" 
            Height="23" 
            VerticalAlignment="Top" 
            IsEnabled="True" 
            ItemsSource="{Binding}" 
            DisplayMemberPath="Name" 
            SelectionChanged="comboProfiles_SelectionChanged" 
            SelectedIndex="0" />

and then bind at run time like this

var javaScriptSerializer = new JavaScriptSerializer();
comboProfiles.DataContext = javaScriptSerializer.Deserialize<List<ProfileItem>>(e.Result);

everything works flawlessly.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 3/8/2009 at 11:50 AM
Tags: , , , ,
Categories: How-To, Samples, and Such | Tip o' The Day
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

The Future of Human Interaction

I just finished watching this short 5 minute video of future interaction of people & machine.  As Amber Case would point out, a bit of Cyborg Anthropology comes to play.

I?ve often fussed about the lackluster state of interfaces today.

What I want is shown in this video on the main page here.

Credit for tipping me off to the video goes to Nikhil from his post on ?Inspiration for Next Generation IX?.

?the really cool thing is, almost ALL of this technology is available NOW!  We just have to get to adopting it in the market place.  I?d even venture out on a limb here and say, America needs to start or find a way to move the economic wheels so we can CONSUME this technology and make it commonplace.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 3/8/2009 at 12:17 AM
Tags: , , ,
Categories: Just Stuff | Keeping Up
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

WebTrends Data Surge & Rocking the Analytics

Almost a year ago I had left WebTrends to kick off a start up.  I had always promised I'd return to WebTrends if they'd have me back.  With that context, I completed this start up kick off and then headed back to WebTrends.  I did this for a couple of reasons.  The main one was the people I get to work with.  WebTrends without doubt has one of the best crews of people out of all the software companies in Portland.  The services department to the engineering group to the sales team are all a great team of people.  They handle their jobs well, push forward with learning, and strive to make WebTrends a great place to work and make sure that the products and services we offer get better and better by the day.

Another one of the reasons that I returned to WebTrends is because of the industry itself.  Analytics, specifically web analytics, are hot.  Everything from Twitter tracking, sales trending, site analysis, and market studies, web analytics is an awesome field to be in.  WebTrends is one of the leaders in that field.

WebTrends over the years has had varying development methodologies and this brings me to my third main point of why I returned.  WebTrends is steadily getting more and more Agile.  In the methodology sense.  Anyone that has read my blog in the past knows I"m a fairly hard core agile advocate (I"ve seen more devoted like Arlo Belshee, but I"m an advocate none the less).  From the iteration based to the kanban boards to the pair or promiscuous pairing to functional teams, the agile style of team & project work is awesome.  WebTrends has started down this road heavily and that is my cup of tea.

What I've Been Working On

I was asked recently by some fellow .NETter geeks, "what have you been working on at WebTrends?"  To which I've been happy to say, "Iz Zecret!"  or the most part, what I've been working on has been on the down low lately, however, I?ll be blogging a LOT more about it real soon.  I'll be providing examples here, and on a new site that isn't published yet, about how we'll be doing some awesome "fill in the blank" - so stay tuned for that.

Follow WebTrends

If you?d like more info on WebTrends here?s some places to check out and tune in.

Stay tuned, I'll have more coming from the WebTrends Data Pipe soon!

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 3/6/2009 at 10:22 PM
Tags: , ,
Categories: Just Stuff | Web Analytics | WebTrends
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

REST, So Many Nuances, The Self Signed SSL Cert Override

Another thing that comes up frequently is the need to do development internally against some REST Services that have SSL as the transport.  If this is your case, in client code you'll need to toss a delegate in to actually get past the SSL Self Signed Cert and get to the rest of your REST Services authentication or whatever else is next in the process.  Here's a code snippet on how to toss a delegate in.

textResults.Text = DateTime.Now.ToLongTimeString() + "\n";
if (!textUriRoot.Text.EndsWith("/"))
    textUriRoot.Text += "/";
string baseUri = textUriRoot.Text + ProfileUri;
MessageBox.Show(baseUri, "Using URI", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
 
// Deal with the self signed SSL certificate.
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
 
var webClient = new WebClient();
webClient.Credentials = new NetworkCredential(@"username", @"password");
webClient.DownloadStringCompleted += GetProfiles;
webClient.DownloadStringAsync(new Uri(baseUri));
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 3/2/2009 at 1:36 PM
Tags: , , ,
Categories: How-To, Samples, and Such
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed