Archive

Monthly Archives: March 2009

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>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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; }
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

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" 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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 

    .csharpcode, .csharpcode pre
    {
    font-size: small;
    color: black;
    font-family: consolas, “Courier New”, courier, monospace;
    background-color: #ffffff;
    /*white-space: pre;*/
    }
    .csharpcode pre { margin: 0em; }
    .csharpcode .rem { color: #008000; }
    .csharpcode .kwrd { color: #0000ff; }
    .csharpcode .str { color: #006080; }
    .csharpcode .op { color: #0000c0; }
    .csharpcode .preproc { color: #cc6633; }
    .csharpcode .asp { background-color: #ffff00; }
    .csharpcode .html { color: #800000; }
    .csharpcode .attr { color: #ff0000; }
    .csharpcode .alt
    {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0em;
    }
    .csharpcode .lnum { color: #606060; }

  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 

    .csharpcode, .csharpcode pre
    {
    font-size: small;
    color: black;
    font-family: consolas, “Courier New”, courier, monospace;
    background-color: #ffffff;
    /*white-space: pre;*/
    }
    .csharpcode pre { margin: 0em; }
    .csharpcode .rem { color: #008000; }
    .csharpcode .kwrd { color: #0000ff; }
    .csharpcode .str { color: #006080; }
    .csharpcode .op { color: #0000c0; }
    .csharpcode .preproc { color: #cc6633; }
    .csharpcode .asp { background-color: #ffff00; }
    .csharpcode .html { color: #800000; }
    .csharpcode .attr { color: #ff0000; }
    .csharpcode .alt
    {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0em;
    }
    .csharpcode .lnum { color: #606060; }

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 

    .csharpcode, .csharpcode pre
    {
    font-size: small;
    color: black;
    font-family: consolas, “Courier New”, courier, monospace;
    background-color: #ffffff;
    /*white-space: pre;*/
    }
    .csharpcode pre { margin: 0em; }
    .csharpcode .rem { color: #008000; }
    .csharpcode .kwrd { color: #0000ff; }
    .csharpcode .str { color: #006080; }
    .csharpcode .op { color: #0000c0; }
    .csharpcode .preproc { color: #cc6633; }
    .csharpcode .asp { background-color: #ffff00; }
    .csharpcode .html { color: #800000; }
    .csharpcode .attr { color: #ff0000; }
    .csharpcode .alt
    {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0em;
    }
    .csharpcode .lnum { color: #606060; }

  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 

    .csharpcode, .csharpcode pre
    {
    font-size: small;
    color: black;
    font-family: consolas, “Courier New”, courier, monospace;
    background-color: #ffffff;
    /*white-space: pre;*/
    }
    .csharpcode pre { margin: 0em; }
    .csharpcode .rem { color: #008000; }
    .csharpcode .kwrd { color: #0000ff; }
    .csharpcode .str { color: #006080; }
    .csharpcode .op { color: #0000c0; }
    .csharpcode .preproc { color: #cc6633; }
    .csharpcode .asp { background-color: #ffff00; }
    .csharpcode .html { color: #800000; }
    .csharpcode .attr { color: #ff0000; }
    .csharpcode .alt
    {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0em;
    }
    .csharpcode .lnum { color: #606060; }

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 

    .csharpcode, .csharpcode pre
    {
    font-size: small;
    color: black;
    font-family: consolas, “Courier New”, courier, monospace;
    background-color: #ffffff;
    /*white-space: pre;*/
    }
    .csharpcode pre { margin: 0em; }
    .csharpcode .rem { color: #008000; }
    .csharpcode .kwrd { color: #0000ff; }
    .csharpcode .str { color: #006080; }
    .csharpcode .op { color: #0000c0; }
    .csharpcode .preproc { color: #cc6633; }
    .csharpcode .asp { background-color: #ffff00; }
    .csharpcode .html { color: #800000; }
    .csharpcode .attr { color: #ff0000; }
    .csharpcode .alt
    {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0em;
    }
    .csharpcode .lnum { color: #606060; }

  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

    .csharpcode, .csharpcode pre
    {
    font-size: small;
    color: black;
    font-family: consolas, “Courier New”, courier, monospace;
    background-color: #ffffff;
    /*white-space: pre;*/
    }
    .csharpcode pre { margin: 0em; }
    .csharpcode .rem { color: #008000; }
    .csharpcode .kwrd { color: #0000ff; }
    .csharpcode .str { color: #006080; }
    .csharpcode .op { color: #0000c0; }
    .csharpcode .preproc { color: #cc6633; }
    .csharpcode .asp { background-color: #ffff00; }
    .csharpcode .html { color: #800000; }
    .csharpcode .attr { color: #ff0000; }
    .csharpcode .alt
    {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0em;
    }
    .csharpcode .lnum { color: #606060; }

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 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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);
        }
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

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.

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 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

…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 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

In the last entry I covered several points about using the Policy Injection Application Block (PIAB) for some AOP based cross cutting work.  If interested, check out Part 1.

  • Setting up IIS for Self Signed SSL Certificates on Windows 2003 and Vista.  Mention IIS Toolkit, etc.
  • Show IIS security settings for Windows Auth, Basic, Digest, Anonymous, etc.
  • Setup a REST based service and a SOAP based service.
  • Setup the web.config file for the IIS based services for basic authentication w/o SSL use.
  • Setup the web.config file for the IIS based services for basic authentication w/ SSL use.

Part 3

  • Setup a client for access via ASP.NET MVC.
  • Setup a client for access via AJAX/JavaScript.
  • Setup a client for access via Silverlight.

More notes:

1. State differences between Windows 2003 and Windows 2008 (XP/Vista or IIS 6/7).  Namely the various states of execution needed for Vista/08 for the project to run in elevated administrator access.

2. State short steps, then state elaborated information for each of the configuration/code segments.

3. Make sure to point out these articles for summary:  http://www.leastprivilege.com/FinallyUsernamesOverTransportAuthenticationInWCF.aspx

4. Report on the various exceptions for Windows Vista & lack of immediate availability of security elevation for self hosted apps.

5. Report on the differences.

6. What is the System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel exception??   http://weblogs.asp.net/jan/archive/2003/12/04/41154.aspx  !!  agggh  !!  http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/bb0fc194-5bf3-4c24-94bb-c86f94c76bc2  …  http://community.salesforce.com/sforce/board/message?board.id=NET_development&message.id=3290   …   

WCF Security Sucks.

There, I've said it.  Now don't get me wrong, I don't mean the actual security itself, it is just fine.  I mean implementing the mess.  WCF security has so much configuration, by the time one is done sorting through the deluge of options then they run into the blasted use case of transport, SSL, and a whole host of other things.

With WCF, generally, if you want security, go get SSL running NOW.  Don't even beat around the bush, just go do it.  I learned this the hard way and fought and fought and fought with the damned thing.

I simply wanted to enforce a standard username and password schema on REST Services.  How hard could it be I thought?  Well, it isn't really hard, but it sure as hell is frustrating, confusing, and somewhat asinine in nature.  In addition to that IIS supports some security methods, windows service services support others, and the delusion of what goes with what gets more confusing the more one digs into all of this cluster of a mess.

The simple fact is, web services don't secure in a logical straight forward way because services weren't built with security, they were built primarily to be wide open.  Not kind of open, but totally open.  Go read the original documentation on the things and you'll see.  So were does that leave us?  The business world that wants some security around the services that is quick to build, fast to access, easy to scale, etc?  Out of luck, that's where it leaves us.

So now that I've spent the first 4 paragraphs of this entry complaining about the flagrant mess that are web services, WCF, and the associated stacks, here's how one can build out these for true Internet use in the real world.

Building WCF Transport Enabled SSL based Security

Ugh, first, setup the blasted SSL certificates needed for development.

http://www.leastprivilege.com/FinallyUsernamesOverTransportAuthenticationInWCF.aspx

This is exactly what I want to do… now the question is.  Will it work.  The various pending requirements are INSANE.  UGGGHHH.

Try a secure WCF service via a hosted console service.

Try an IIS SSL enabled virtual directory based WCF service.

Follow

Get every new post delivered to your Inbox.

Join 3,712 other followers