Thursday 31 May 2012

Silverlight OverlapStackPanel

Here’s an example of displaying items within a panel with the optional benefit of letting them overlap, rotate and offset from the top or left hand side.

In this screenshot we have 3 OverlapStackPanels, each with 3 rectangles within them:

OverlapStackPanel

<UserControl x:Class="OverlapStackPanelDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:OverlapStackPanelDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="600"
d:DesignWidth="400"
mc:Ignorable="d">

<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<StackPanel>
<local:OverlapStackPanel LeftOffset="10"
Orientation="Vertical"
Overlap="90"
Rotation="355"
UpperOffset="10">
<Rectangle Width="100"
Height="100"
Fill="Blue" />
<Rectangle Width="100"
Height="100"
Fill="Red" />
<Rectangle Width="100"
Height="100"
Fill="Yellow" />
</local:OverlapStackPanel>
<local:OverlapStackPanel LeftOffset="10"
Orientation="Horizontal"
Overlap="90"
Rotation="355"
UpperOffset="10">
<Rectangle Width="100"
Height="100"
Fill="Green" />
<Rectangle Width="100"
Height="100"
Fill="Purple" />
<Rectangle Width="100"
Height="100"
Fill="Silver" />
</local:OverlapStackPanel>
<local:OverlapStackPanel LeftOffset="10"
Orientation="Vertical"
Overlap="90"
Rotation="355"
UpperOffset="10">
<Rectangle Width="100"
Height="100"
Fill="Blue" />
<Rectangle Width="100"
Height="100"
Fill="Red" />
<Rectangle Width="100"
Height="100"
Fill="Yellow" />
</local:OverlapStackPanel>
</StackPanel>
</Grid>
</UserControl>

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace OverlapStackPanelDemo
{
public class OverlapStackPanel : Panel
{
#region Dependency Properties

public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(OverlapStackPanel), new PropertyMetadata((Orientation.Vertical)));
public Orientation Orientation { get { return (Orientation) GetValue(OrientationProperty); } set { SetValue(OrientationProperty, (Enum) value); } }

public static readonly DependencyProperty OverlapProperty = DependencyProperty.Register("Overlap", typeof(double), typeof(OverlapStackPanel), new PropertyMetadata(double.NaN));
public double Overlap { get { return (double)GetValue(OverlapProperty); } set { SetValue(OverlapProperty, value); } }

public static readonly DependencyProperty RotationProperty = DependencyProperty.Register("Rotation", typeof(double), typeof(OverlapStackPanel), new PropertyMetadata(double.NaN));
public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } }

public static readonly DependencyProperty LeftOffsetProperty = DependencyProperty.Register("LeftOffset", typeof(double), typeof(OverlapStackPanel), new PropertyMetadata(double.NaN));
public double LeftOffset { get { return (double)GetValue(LeftOffsetProperty); } set { SetValue(LeftOffsetProperty, value); } }

public static readonly DependencyProperty UpperOffsetProperty = DependencyProperty.Register("UpperOffset", typeof (double), typeof (OverlapStackPanel), new PropertyMetadata(double.NaN));
public double UpperOffset { get { return (double)GetValue(UpperOffsetProperty); } set { SetValue(UpperOffsetProperty, value); } }

#endregion

#region Overrides

protected override Size MeasureOverride(Size availableSize)
{
var desiredSize = new Size();
var childrenResolved = 0;

if (Orientation == Orientation.Vertical)
availableSize.Height = double.PositiveInfinity;
else
availableSize.Width = double.PositiveInfinity;

foreach (UIElement child in Children.Where(child => child != null))
{
child.Measure(availableSize);

if (Orientation == Orientation.Vertical)
{
desiredSize.Width = LeftOffset + Math.Max(desiredSize.Width, child.DesiredSize.Width);
desiredSize.Height += UpperOffset + child.DesiredSize.Height - Overlap;
}
else
{
desiredSize.Height = UpperOffset + Math.Max(desiredSize.Height, child.DesiredSize.Height);
desiredSize.Width += LeftOffset + child.DesiredSize.Width - Overlap;
}
childrenResolved++;
}

// take into account the first item doesn't overlap
if (Orientation == Orientation.Vertical)
{
desiredSize.Height += Overlap;
}
else
{
desiredSize.Width += Overlap;
}

return desiredSize;
}

protected sealed override Size ArrangeOverride(Size arrangeSize)
{
int childrenResolved = 0;
double itemX = 0;
double itemY = 0;
foreach (UIElement child in Children.Where(child => child != null))
{
double itemOverlap = (childrenResolved == 0)
? 0
: Overlap;

Rect targetRect;
if (Orientation == Orientation.Vertical)
{
targetRect = new Rect
{
X = LeftOffset + (LeftOffset * childrenResolved),
Y = itemY + UpperOffset + (UpperOffset * childrenResolved) - itemOverlap,
Width = child.DesiredSize.Width,
Height = child.DesiredSize.Height
};

itemY += child.DesiredSize.Height - itemOverlap;
}
else
{
targetRect = new Rect
{
X = itemX + LeftOffset + (LeftOffset * childrenResolved) - itemOverlap,
Y = UpperOffset + (UpperOffset * childrenResolved),
Width = child.DesiredSize.Width,
Height = child.DesiredSize.Height
};

itemX += child.DesiredSize.Width - itemOverlap;
}
child.Arrange(targetRect);

var rotate = new RotateTransform {Angle = Rotation};
child.RenderTransform = rotate;

childrenResolved++;
}
return arrangeSize;
}

#endregion

#region Constructor

public OverlapStackPanel()
{
}

#endregion
}
}

Source code:  http://stevenhollidge.com/blog-source-code/OverlapStackPanelDemo.zip

Silverlight Metro Info Tile

A quick prototype for displaying information in a clear and consistent manner in the Metro style.

prototype

 

MetroInfoTile

These tiles could be used to present constituents of a package, perhaps with the addition of a metric in the top right hand corner to visualise risk or projected yields.

It doesn’t currently support passing in a tree, dynamic sizing or an info section either statically positioned on the page or a popup / tooltip of some kind.

Here’s the code for the basic prototype:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MetroInfoTiles
{
public class DisplayTile : Control
{
public static readonly DependencyProperty TitleTextProperty =
DependencyProperty.Register("TitleText", typeof (string), typeof (DisplayTile), new PropertyMetadata(default(string)));

public string TitleText
{
get { return (string) GetValue(TitleTextProperty); }
set { SetValue(TitleTextProperty, value); }
}

public static readonly DependencyProperty DescriptionTextProperty =
DependencyProperty.Register("DescriptionText", typeof (string), typeof (DisplayTile), new PropertyMetadata(default(string)));

public string DescriptionText
{
get { return (string) GetValue(DescriptionTextProperty); }
set { SetValue(DescriptionTextProperty, value); }
}

public static readonly DependencyProperty SideBarColourProperty =
DependencyProperty.Register("SideBarColour", typeof (SolidColorBrush), typeof (DisplayTile), new PropertyMetadata(default(SolidColorBrush)));

public SolidColorBrush SideBarColour
{
get { return (SolidColorBrush) GetValue(SideBarColourProperty); }
set { SetValue(SideBarColourProperty, value); }
}
}
}

 

<Application x:Class="MetroInfoTiles.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MetroInfoTiles"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Application.Resources>
<Style TargetType="local:DisplayTile">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DisplayTile">
<Grid>
<Border x:Name="OuterBorder"
Width="350"
Height="120"
Background="#FFF2F2F2"
BorderBrush="#FFB5B5B5"
BorderThickness="1,1,1,1"
CornerRadius="5">
<Grid>
<Border x:Name="SideBarBorder"
Width="5"
Margin="-1,-1,0,-1"
HorizontalAlignment="Left"
Background="{TemplateBinding SideBarColour}"
CornerRadius="5,0,0,5" />
<TextBlock x:Name="TitleTextBlock"
Height="35.4700012207031"
Margin="20,5,20,0"
VerticalAlignment="Top"
FontFamily="/MetroInfoTiles;component/Fonts/Fonts.zip#Segoe UI Light"
FontSize="20"
Foreground="#FF686868"
Text="{TemplateBinding TitleText}" />
<TextBlock x:Name="DescriptionTextBlock"
Height="35"
Margin="20,0,20,10"
VerticalAlignment="Bottom"
FontFamily="/MetroInfoTiles;component/Fonts/Fonts.zip#Segoe UI"
FontSize="12"
Foreground="#FF686868"
Text="{TemplateBinding DescriptionText}"
TextWrapping="Wrap" />
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="LevelOneBrush" Color="#FFFAA634" />
<SolidColorBrush x:Key="LevelZeroBrush" Color="#FF5DA9DD" />
<SolidColorBrush x:Key="ConnectionBrush" Color="#FF8B8B8B"/>
</Application.Resources>
</Application>

<UserControl x:Class="MetroInfoTiles.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:l="clr-namespace:MetroInfoTiles"
Width="850"
Height="350"
xml:space="preserve">
<Canvas>
<l:DisplayTile x:Name="LevelZeroDisplayTile"
Canvas.Left="250"
Canvas.Top="50"
DescriptionText="High level description for package, dashboard symbols for movements or value indicators for yields, rates etc."
SideBarColour="{StaticResource LevelZeroBrush}"
TitleText="FX Swap: 1,000 EURO" />
<l:DisplayTile x:Name="LevelOneDisplayTileSpot"
Canvas.Left="50"
Canvas.Top="200"
DescriptionText="Date: 31 May 2012 09:02:31 USD = 0.806884&#10;Posted trade, settlement timeframe 2 days."
SideBarColour="{StaticResource LevelOneBrush}"
TitleText="FX Spot" />
<l:DisplayTile x:Name="LevelOneDisplayTileForward"
Canvas.Left="450"
Canvas.Top="200"
DescriptionText="Date: 15 June 2012 09:02:31 Estimated USD = 0.78219&#10;Posted trade, current price as of 31 May 2012 09:05:31"
SideBarColour="{StaticResource LevelOneBrush}"
TitleText="FX Forward" />
<l:VConnection Height="30" Canvas.Left="200" Canvas.Top="170" Width="451"/>
</Canvas>
</UserControl>

 

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
mc:Ignorable="d"
x:Class="MetroInfoTiles.VConnection"
d:DesignWidth="451" d:DesignHeight="30">

<Grid x:Name="LayoutRoot">
<ed:LineArrow
Height="15"
ArrowSize="0"
BendAmount="0"
EndArrow="NoArrow"
Fill="#FFF4F4F5"
Stroke="{StaticResource ConnectionBrush}"
Margin="225,0"
VerticalAlignment="Top" />
<ed:LineArrow
Height="1"
ArrowSize="0"
BendAmount="0"
EndArrow="NoArrow"
Fill="#FFF4F4F5"
Stroke="{StaticResource ConnectionBrush}"
Margin="0,0,1,14"
VerticalAlignment="Bottom" />
<ed:LineArrow
Width="1"
Height="15"
ArrowSize="0"
BendAmount="0"
EndArrow="NoArrow"
Fill="#FFF4F4F5"
Stroke="{StaticResource ConnectionBrush}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom" />
<ed:LineArrow
Width="1"
Height="15"
ArrowSize="0"
BendAmount="0"
EndArrow="NoArrow"
Fill="#FFF4F4F5"
Stroke="{StaticResource ConnectionBrush}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom" />
</Grid>
</UserControl>

Full source:  http://stevenhollidge.com/blog-source-code/MetroInfoTiles.zip

Monday 28 May 2012

Silverlight Metro Charms

Here’s a quick example of a Silverlight application with a Charms style menu from Windows 8.

The menu slides in and out as the user moves the mouse over the right hand side of the screen.  When displayed the menu holds ImageButtons that when clicked, display a UIMessage to the user.

Give it a try by moving your mouse over the right hand side of this iframe, over the tall black rectangle:

MainPage.xaml

<UserControl x:Class="MetroCharms.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:MetroCharms"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">

<Grid x:Name="LayoutRoot">

<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="HideShowMenu">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.3" />
</VisualStateGroup.Transitions>
<VisualState x:Name="HideMenu" />
<VisualState x:Name="ShowMenu">
<Storyboard>
<DoubleAnimation d:IsOptimized="True"
Duration="0"
Storyboard.TargetName="menuPanel"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
To="-60" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>

<local:UIMessage x:Name="Message" />

<StackPanel x:Name="menuPanel"
Grid.Column="1"
Width="68"
Height="340"
Margin="0,0,-60,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Background="Black">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<ei:GoToStateAction StateName="ShowMenu" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<ei:GoToStateAction StateName="HideMenu" />
</i:EventTrigger>
</i:Interaction.Triggers>
<StackPanel.RenderTransform>
<CompositeTransform />
</StackPanel.RenderTransform>

<local:ImageButton x:Name="imageButtonSettings"
Width="48"
Height="48"
Margin="10"
Click="imageButtonSettings_Click"
Image="/MetroCharms;component/images/settings.png"
PressedImage="/MetroCharms;component/images/settings.png"
Template="{StaticResource ImageButtonControlTemplate}" />
<local:ImageButton x:Name="imageButtonSave"
Width="48"
Height="48"
Margin="10"
Click="imageButtonSave_Click"
Image="/MetroCharms;component/images/save.png"
PressedImage="/MetroCharms;component/images/save.png"
Template="{StaticResource ImageButtonControlTemplate}" />
<local:ImageButton x:Name="imageButtonCamera"
Width="48"
Height="48"
Margin="10"
Click="imageButtonCamera_Click"
Image="/MetroCharms;component/images/camera.png"
PressedImage="/MetroCharms;component/images/camera.png"
Template="{StaticResource ImageButtonControlTemplate}" />
<local:ImageButton x:Name="imageButtonFavs"
Width="48"
Height="48"
Margin="10"
Click="imageButtonFavs_Click"
Image="/MetroCharms;component/images/favs.png"
PressedImage="/MetroCharms;component/images/favs.png"
Template="{StaticResource ImageButtonControlTemplate}" />
<local:ImageButton x:Name="imageButtonFlag"
Width="48"
Height="48"
Margin="10"
Click="imageButtonFlag_Click"
Image="/MetroCharms;component/images/flag.png"
PressedImage="/MetroCharms;component/images/flag.png"
Template="{StaticResource ImageButtonControlTemplate}" />
</StackPanel>

</Grid>
</UserControl>

ImageButton.cs

public class ImageButton : Button
{
public ImageButton()
{
DefaultStyleKey = typeof(ImageButton);

MouseEnter += (o, args) => Cursor = Cursors.Hand;
MouseLeave += (o, args) => Cursor = Cursors.None;
}

public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButton), null);

public ImageSource Image
{
get { return (ImageSource)this.GetValue(ImageProperty); }
set { this.SetValue(ImageProperty, value); }
}

public static readonly DependencyProperty PressedImageProperty =
DependencyProperty.Register("PressedImage", typeof(ImageSource), typeof(ImageButton), null);

public ImageSource PressedImage
{
get { return (ImageSource)this.GetValue(PressedImageProperty); }
set { this.SetValue(PressedImageProperty, value); }
}
}

App.xaml

<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MetroCharms"
x:Class="MetroCharms.App">

<Application.Resources>
<ControlTemplate x:Key="ImageButtonControlTemplate" TargetType="local:ImageButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="PressedImage">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="NormalImage">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image x:Name="NormalImage" Source="{TemplateBinding Image}"/>
<Image x:Name="PressedImage" Source="{TemplateBinding PressedImage}" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Application.Resources>
</Application>

Source


https://github.com/stevenh77/MetroCharms

Sunday 27 May 2012

Silverlight Async Rest Wcf

Here is a simple example application that shows off:

  • “Aync” and “await” within Silverlight 5 in Visual Studio 11
  • Calling a simple RESTful WCF interface hosted with no config or svc file

image

image

image

MainPage.xaml.cs (code behind)

private async void LoadDataButton_Click(object sender, RoutedEventArgs e)
{
var request = new WebClient();
var uri = new Uri("http://localhost:5349/services/cars");
var jsonString = await request.DownloadStringTaskAsync(uri);

using (var stream = new MemoryStream(Encoding.Unicode.GetBytes(jsonString.ToCharArray())))
{
var serializer = new DataContractJsonSerializer(typeof (Car[]));
var cars = (Car[]) serializer.ReadObject(stream);
CarsListBox.ItemsSource = cars;
}
}

Service Interface

[ServiceContract]
interface IService<T>
{
[OperationContract]
IList<T> GetAll();

[OperationContract]
T Get(string id);

[OperationContract]
void Insert(T entity);

[OperationContract]
void Update(string id, T entity);

[OperationContract]
void Delete(string id);
}

Service Implementation

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class CarService : IService<Car>
{
private readonly IRepository<Car> _repo;

public CarService()
{
_repo = new FakeCarRepository();
}

public CarService(IRepository<Car> repo)
{
_repo = repo;
}

[WebGet(UriTemplate = "Cars", ResponseFormat = WebMessageFormat.Json)]
public IList<Car> GetAll()
{
var cars = _repo.GetAll();
return cars;
}

[WebGet(UriTemplate = "Car/{id}", ResponseFormat = WebMessageFormat.Json)]
public Car Get(string id)
{
var car = _repo.GetById(id);
return car;
}

[WebInvoke(UriTemplate = "Car", Method = "POST")]
public void Insert(Car car)
{
_repo.Insert(car);
}

[WebInvoke(UriTemplate = "Car/{id}", Method = "PUT")]
public void Update(string id, Car car)
{
_repo.Update(car);
}

[WebInvoke(UriTemplate = "Car/{id}", Method = "DELETE")]
public void Delete(string id)
{
_repo.Delete(id);
}
}

DTO

[DataContract]
public class Car
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Make { get; set; }
[DataMember]
public string Model { get; set; }
[DataMember]
public int Year { get; set; }
}

How come no config or svc file?


Global.asax

public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add(new ServiceRoute("services", new WebServiceHostFactory(), typeof(CarService)));
}
}

Web.config

<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
</configuration>

Source


http://stevenhollidge.com/blog-source-code/SilverlightAsyncRestWcf.zip

Code Contracts

I started writing a blog post about Code Contracts that I believe will end up working its way into all future .NET software, particularly APIs.  Then I came across this excellent write up that I highly recommend:

http://devjourney.com/blog/code-contracts-part-1-introduction/

Code Contracts in action

using System;
using System.Diagnostics.Contracts;

namespace CodeContracts
{
public interface IRandomGenerator
{
int Next(int min, int max);
}

public class RandomGenerator : IRandomGenerator
{
private readonly Random _random = new Random();

public int Next(int min, int max)
{
return _random.Next(min, max);
}
}

public class Randomizer
{
private readonly IRandomGenerator _generator;

public Randomizer(IRandomGenerator generator)
{
_generator = generator;
}

public int GetRandomFromRangeContracted(int min, int max)
{
Contract.Requires<ArgumentOutOfRangeException>(
min < max,
"Min must be less than max"
);

Contract.Ensures(
Contract.Result<int>() >= min &&
Contract.Result<int>() <= max,
"Return value is out of range"
);

return _generator.Next(min, max);
}
}
}

The above code Post build

public class Randomizer
{
// Fields
private readonly IRandomGenerator _generator;

// Methods
public Randomizer(IRandomGenerator generator)
{
this._generator = generator;
}

public int GetRandomFromRangeContracted(int min, int max)
{
int Contract.Old(min);
int Contract.Old(max);
__ContractsRuntime.Requires<ArgumentOutOfRangeException>(min < max, "Min must be less than max", "min < max");
try
{
Contract.Old(min) = min;
}
catch (Exception exception1)
{
if (exception1 == null)
{
throw;
}
}
try
{
Contract.Old(max) = max;
}
catch (Exception exception2)
{
if (exception2 == null)
{
throw;
}
}
int CS$1$0000 = this._generator.Next(min, max);
int Contract.Result() = CS$1$0000;
__ContractsRuntime.Ensures((Contract.Result() >= Contract.Old(min)) && (Contract.Result() <= Contract.Old(max)), "Return value is out of range", "Contract.Result<int>() >= min && Contract.Result<int>() <= max");
return Contract.Result();
}
}


Unit tests with Moq and NUnit test cases

using System;
using Moq;
using NUnit.Framework;

namespace CodeContracts.Tests
{
[TestFixture]
public class Given_mocked_RandomGenerator
{
private Mock<IRandomGenerator> _randomMock;
private Randomizer _randomizer;

[SetUp]
public void Setup()
{
_randomMock = new Mock<IRandomGenerator>();
_randomizer = new Randomizer(_randomMock.Object);
}

[TestCase(1, 0)]
[TestCase(2, 1)]
[TestCase(100, 10)]
[TestCase(0, -1)]
[TestCase(-1, -2)]
[TestCase(-10, -100)]
public void When_min_is_greater_than_max_Then_should_throw_exception(int min, int max)
{
Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(0, 0)]
[TestCase(1, 1)]
[TestCase(10000, 10000)]
[TestCase(-1, -1)]
[TestCase(-10000, -10000)]
public void When_min_is_equal_to_max_Then_should_throw_exception(int min, int max)
{
Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(1, 2, 0)]
[TestCase(10, 100, 7)]
[TestCase(-100, -10, -107)]
public void When_return_value_is_less_than_min_Then_should_throw_exception(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(10, 100, 102)]
public void When_return_value_is_more_than_max_Then_should_throw_exception(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(0, 2, 1)]
[TestCase(10, 100, 50)]
[TestCase(-100, 10, 5)]
[TestCase(int.MinValue, int.MaxValue, 1)]
[TestCase(int.MinValue, int.MaxValue, 0)]
[TestCase(int.MinValue, int.MaxValue, -1)]
public void When_min_is_less_than_max_Then_should_equal_expected_result(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

var actual = _randomizer.GetRandomFromRangeContracted(min, max);

Assert.AreEqual(expected, actual);
}

[TestCase(0, 2, 0)]
[TestCase(10, 100, 10)]
[TestCase(-100, 10, -100)]
[TestCase(int.MinValue, int.MaxValue, int.MinValue)]
public void When_min_is_less_than_max_and_result_equals_min_Then_should_equal_expected_result(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

var actualResult = _randomizer.GetRandomFromRangeContracted(min, max);

Assert.AreEqual(expected, actualResult);
}

[TestCase(0, 2, 2)]
[TestCase(10, 100, 100)]
[TestCase(-100, 10, 10)]
[TestCase(int.MinValue, int.MaxValue, int.MaxValue)]
public void When_min_is_less_than_max_and_result_equals_max_Then_should_equal_expected_result(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

var actualResult = _randomizer.GetRandomFromRangeContracted(min, max);

Assert.AreEqual(expected, actualResult);
}
}
}

Source


http://stevenhollidge.com/blog-source-code/CodeContracts.zip

Saturday 26 May 2012

Silverlight Fluid Move Behavior

Check out this excellent tutorial on http://xaml.tv where Victor Guadioso shows how to use the Fluid Move Behavior in Expression Blend:

What you will learn:

  1. How to create sample data (text and images);
  2. How to create a ListBox and bind the ItemsSource to the sample data;
  3. How to create a Details Grid that reflects the selected item of the ListBox;
  4. How to use the Fluid Move and Fluid Set Tag Behaviors to make the selected item animate from the ListBox to the Master Details Grid;

For more Xaml tips check out http://xaml.tv and follow Victor on twitter:  https://twitter.com/victorgaudioso

Wednesday 23 May 2012

WCF Bindings

Carrying on from an excellent MSDN blog post by Rick Rainey comparing the performance of various WCF bindings here is an example including NetNamePipes and ProtoBuf-Net:

Test results

Original blog post:  http://blogs.msdn.com/b/rickrain/archive/2012/05/20/which-wcf-binding-is-best.aspx

protobuf-net

Is available via Nuget or its Google project hosting: http://code.google.com/p/protobuf-net/

AddressAccessDeniedException

If you come across the following exception:

HTTP could not register URL http://+:9001/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).

Either run Visual Studio using “Run as Administrator” or visit the following link for a more complete resolution:

http://blogs.msdn.com/b/amitlale/archive/2007/01/29/addressaccessdeniedexception-cause-and-solution.aspx

Source

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using ProtoBuf;
using ProtoBuf.ServiceModel;

namespace BindingTest
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
void Execute(TestData data);
}

[DataContract]
[ProtoContract]
public class TestData
{
[DataMember]
[ProtoMember(1)]
public List<string> Data { get; set; }
}

public class TestService : ITestService
{
public void Execute(TestData data)
{
// empty service implementation
}
}

class Program
{
static void Main(string[] args)
{
var bindingElements = new BindingElement[] {
new BinaryMessageEncodingBindingElement(),
new ReliableSessionBindingElement(true),
new HttpTransportBindingElement()
};

var bindings = new Binding[]
{
new WSHttpBinding() { MaxReceivedMessageSize = Int32.MaxValue },
new NetTcpBinding
{
Name = "NetTcpBinding (SecurityMode.Message)",
Security = { Mode = SecurityMode.Message },
MaxReceivedMessageSize = Int32.MaxValue
},
new CustomBinding(bindingElements)
{
Name = "CustomBinding (HTTP/Binary/ReliableSession(ordered)/NoSecurity"
},
new NetTcpBinding(),
new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport),
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
};

var payloadSize = 15000;
var iterations = 5;

OutputTitle(payloadSize, iterations);

// Compare all the bindings in the bindings array.
CompareBindings(bindings, payloadSize, iterations, false);

// Compare all the bindings using protobuf-net
CompareBindings(bindings, payloadSize, iterations, true);

OutputNote();
}

public static void OutputTitle(int payloadSize, int iterations)
{
Console.WriteLine("Test parameters: {0} byte payload, {1} iterations",
payloadSize.ToString("N0"),
iterations);
Console.WriteLine();
}

private static void OutputNote()
{
Console.WriteLine();
Console.WriteLine("NOTE: NetNamedPipe is only used for same machine inter process communication");
Console.WriteLine();
}

public static string GenerateRandomStringData(int stringSize)
{
var r = new Random();
var sb = new StringBuilder(stringSize);
while (sb.Length < stringSize)
sb.Append((char)(r.Next(0, 256)));
return sb.ToString();
}

public static TestData GenerateTestData(int payloadSize)
{
const int itemDataSize = 4096;

var data = new TestData {Data = new List<string>()};

int numDataItems = payloadSize / itemDataSize;

for (int item = 0; item < numDataItems; item++)
data.Data.Add(GenerateRandomStringData(itemDataSize));

data.Data.Add(GenerateRandomStringData(payloadSize - (numDataItems * itemDataSize)));

return data;
}

public static void CompareBindings(Binding[] bindings, int payloadSize, int iterations, bool useProtoBuf)
{
Console.WriteLine("Using {0} serialisation", useProtoBuf ? "protobuf" : "normal");
var data = GenerateTestData(payloadSize);

foreach (var b in bindings)
{
try
{
// Run the test on this binding.
Stopwatch result = TestBinding(b, data, iterations, useProtoBuf);

// Output the results.
Console.Write(b.Name);
//Console.WriteLine(string.Format("Payload Size: {0}, Iterations: {1}", payloadSize, iterations));
//Console.WriteLine(" Binding Elements:");
//foreach (BindingElement be in b.CreateBindingElements())
// Console.WriteLine(" {0}", be.GetType());
Console.WriteLine(", time: {0} ms", result.ElapsedMilliseconds);
}
catch (Exception e)
{
Console.WriteLine("EXCEPTION: {0}", e.Message);
}
}
Console.WriteLine();
}

public static Stopwatch TestBinding(Binding binding, TestData data, int iterations, bool useProtoBuf)
{
var address = GetAddress(binding);

// Start the host using the binding provided
var host = new ServiceHost(typeof(TestService), new Uri(address));
var endpoint = host.AddServiceEndpoint(typeof(ITestService), binding, "");

if (useProtoBuf)
endpoint.Behaviors.Add(new ProtoEndpointBehavior());

host.Open();

var sw = new Stopwatch();
sw.Restart();

// Create a client proxy using the binding provided
var cf = new ChannelFactory<ITestService>(binding, address);
ITestService proxy = cf.CreateChannel();

// Call the service
for (int count = 0; count < iterations; count++)
proxy.Execute(data);

// Close the client proxy and host.
cf.Close();
sw.Stop();
host.Close();

return sw;
}

private static string GetAddress(Binding binding)
{
var machine = "localhost";
var port = (binding.Scheme == "net.pipe")
? ""
: ":9001";

return string.Concat(binding.Scheme, "://", machine, port, "/", Guid.NewGuid().ToString());
}
}
}

Download:  http://stevenhollidge.com/blog-source-code/BindingTestSolution.zip

Reporting Test Tool

This app was developed to regression test Crystal Reports. The data for the reports is taken from two SQL databases, a before and after the upgrade version. Reports are generated from both databases and exported to HTML. The user then clicks on the HTML report template to select what objects they wish to be compared during the testing. SQL profiling technology is used to also show the user the slowest sql statements whilst running the reports.

For a better quality video watch it here:  https://vimeo.com/stevenhollidge/reporting-test-tool

Sunday 20 May 2012

Silverlight and SSRS

As part of the agile mantra, release early and often, I’m publishing this blog post as I develop the solution.

Architecture

image

Wireframe Prototype

SSRS Reports in Silverlight

The reports are loaded from a RESTful JSON web service on the Silverlight host web server.  This in turn calls the web services from the SSRS to retrieve the full list of reports for the user along with the require parameter metadata.

When the user clicks on the report the parameters listed on the right hand side are automatically displayed, with the correct data type input control (text, combo, checkbox, date picker), default values and validation.

To be continued…

As more gets added to the project I’ll update this blog post.

Wednesday 16 May 2012

Intro to SCRUM

Here is a nice eight minute introductory video to SCRUM for management or junior devs, enjoy!

Monday 14 May 2012

Converting images to paths

Just a quick trick to convert an image into a vector based path in xaml. 

To be able to handle anything more than the most basic image you’ll probably need Expression Design installed.

For an example, I’m going to use the logo for what is probably xaml’s arch enemy…. HTML 5!

Here is our example image:  http://www.w3.org/html/logo/downloads/HTML5_Logo_512.png

The first step is to download Inkscape from the web:  http://inkscape.org/

It’s an open source SVG graphics editor.  When you open your PNG file, select to “embed” the image:

image

Now select the object:

image

And from the menu choose “Path > Trace Bitmap…”:

image

Make sure the “Colors” option is selected and click Ok:

image

This will make a create a Vector Path object on top of your original image (which is a bit weird), so you need to “Edit > Copy” then “File > New” and “Edit > Paste” to create a nice clean vector image.

Now we could just “Save As > Xaml” but unfortunately the Xaml created isn’t that compatible with WPF or Silverlight so we’ve got an extra hoop to jump through.  Give it a go and see how you get on.  If the resultant xaml doesn’t work in Kaxaml for example you’ll need to follow these extra steps.

We need to get the image into Expression Design.

Still within Inkscape for now, “Save As” file type PDF (stay with me on this one) and select texts to paths

image

Now rename your “.pdf” file to “.ai” file type and you can open it in Expression Design:

image

Now finally we can export to Xaml Silverlight 4 / WPF canvas and all is good in the world.

image

Monday 7 May 2012

Troubleshooting Kerberos with Tools

Here are a few tools that can be used to diagnose Kerberos issues, along with a brief paragraph explaining what each tool does.

Enable Kerberos Logging for Windows XP

http://support.microsoft.com/kb/262177

Microsoft Windows 2000, Windows Server 2003, and Windows Server 2008 offer the capability of tracing detailed Kerberos events through the event log mechanism. You can use this information when you troubleshoot Kerberos. This article describes how to enable Kerberos event logging.

Insight for Active Directory v1.01

http://technet.microsoft.com/en-us/sysinternals/bb897539

ADInsight is an LDAP (Light-weight Directory Access Protocol) real-time monitoring tool aimed at troubleshooting Active Directory client applications. Use its detailed tracing of Active Directory client-server communications to solve Windows authentication, Exchange, DNS, and other problems.

ADInsight uses DLL injection techniques to intercept calls that applications make in the Wldap32.dll library, which is the standard library underlying Active Directory APIs such ldap and ADSI. Unlike network monitoring tools, ADInsight intercepts and interprets all client-side APIs, including those that do not result in transmission to a server. ADInsight monitors any process into which it can load it’s tracing DLL, which means that it does not require administrative permissions, however, if run with administrative rights, it will also monitor system processes, including windows services.

Process Monitor

http://technet.microsoft.com/en-us/sysinternals/bb896645

Process Monitor is an advanced monitoring tool for Windows that shows real-time file system, Registry and process/thread activity. It combines the features of two legacy Sysinternals utilities, Filemon and Regmon, and adds an extensive list of enhancements including rich and non-destructive filtering, comprehensive event properties such session IDs and user names, reliable process information, full thread stacks with integrated symbol support for each operation, simultaneous logging to a file, and much more. Its uniquely powerful features will make Process Monitor a core utility in your system troubleshooting and malware hunting toolkit.

LogMan

http://technet.microsoft.com/en-us/library/cc753820(v=ws.10).aspx

Logman creates and manages Event Trace Session and Performance logs and supports many functions of Performance Monitor from the command line.  Filters can be added to log Kerberos events.

KerbTray

http://www.microsoft.com/en-us/download/details.aspx?id=23018

This tool is used to display ticket information for a given computer running the Kerberos protocol.

KList

http://www.microsoft.com/en-us/download/details.aspx?id=11583

View and deleting the Kerberos tickets granted to the current logon session.

Setspn

http://www.microsoft.com/en-us/download/details.aspx?id=25233

http://support.microsoft.com/kb/326985

This command-line tool allows you to manage the Service Principal Names (SPN) directory property for an Active Directory™ directory service account. SPNs are used to locate a target principal name for running a service.

MIT Kerberos Client

http://web.mit.edu/kerberos/dist/

Network Identity Manager (NetIdMgr) is a graphical tool designed to simplify the management of network identities and their credentials which are used by network authentication protocols while providing secure access to network services.

When NetIDMgr is used with Kerberos v5 each network identity is a unique Kerberos principal name and the credentials are Kerberos v5 tickets. Kerberos v5 tickets can be used by NetIDMgr to obtain Andrew File System (AFS) tokens and X.509 public key certificates if the appropriate plug-ins are installed.

Process Explorer

http://technet.microsoft.com/en-us/sysinternals/bb896653

Ever wondered which program has a particular file or directory open? Now you can find out. Process Explorer shows you information about which handles and DLLs processes have opened or loaded.

The Process Explorer display consists of two sub-windows. The top window always shows a list of the currently active processes, including the names of their owning accounts, whereas the information displayed in the bottom window depends on the mode that Process Explorer is in: if it is in handle mode you'll see the handles that the process selected in the top window has opened; if Process Explorer is in DLL mode you'll see the DLLs and memory-mapped files that the process has loaded. Process Explorer also has a powerful search capability that will quickly show you which processes have particular handles opened or DLLs loaded.

The unique capabilities of Process Explorer make it useful for tracking down DLL-version problems or handle leaks, and provide insight into the way Windows and applications work.

DelegConfig v1

http://www.iis.net/community/default.aspx?tabid=34&g=6&i=1434

This is an ASP.NET application used to help troubleshoot and configure IIS and Active Directory to allow Kerberos and delegating Kerberos credentials.

Kerberos SPN Viewer

http://blogs.msdn.com/b/sansom/archive/2009/10/12/kerberos-spn-viewer-and-helper-tool-sample.aspx

Simplify listing the ServicePrincipalName (SPN) and an integrated helper tool which can help us find out what SPN should we set based on the configuration that we are using.

Kinit?

http://docs.oracle.com/javase/1.4.2/docs/tooldocs/linux/kinit.html

NetMon

http://www.microsoft.com/en-us/download/details.aspx?id=4865

Tool to allow capturing and protocol analysis of network traffic.

WireShark

http://www.wireshark.org/

Network Protocol analyzer for Windows and Unix.

Tokensz

http://www.microsoft.com/en-us/download/details.aspx?id=1448

This tool will compute the maximum token size and is used to test whether a system may exhibit the issue described in KB article 327825.

Troubleshooting Kerberos Problems

http://technet.microsoft.com/en-us/library/cc786325(v=ws.10).aspx

https://developers.google.com/search-appliance/kb/secure/kerberos-troubleshooting

http://www.microsoft.com/en-us/download/details.aspx?id=21820

http://blogs.technet.com/b/askds/archive/2008/05/14/troubleshooting-kerberos-authentication-problems-name-resolution-issues.aspx

Kerberos: Authentication in Windows


Kerberos (v5) is a Network Authentication Service used by Microsoft Windows Server since 2000 that provides Single Sign On (SSO) where the user only enters their password once to access the network of servers.

The name is taken from the three headed dog in Greek mythology, due to its three pronged nature of Client, Authentication server (KDC) and Resource Server.

Kerberos assumes and protects against an open network in which packets can be sniffed and altered.

The full specification can be found here: http://tools.ietf.org/html/rfc4120

Benefits

  • Mutual authentication
  • Faster connections between client and servers, thanks to SSO (through the use of session tickets)
  • Delegation aka Impersonation

Stages

There are three stages to Kerberos in Windows, each with their own request/response message:
  • Authentication Service (AS) exchange
  • Ticket Granting Service (TGS) exchange
  • Client/Server (CS) exchange (messages are known as AP: Application Privilege)
image

Authentication Service (AS) exchange


1. The user providing a username and password.

2. The password is one way hashed and stored locally as the secret key.

3. KRB_AS_REQ message sent from client to KDC Server, consisting of:
  • Username (Client Principal Name / User Principal Name).
  • Timestamp (for pre-authentication, it's use can be disabled for a user on the AD server).  Its use prevents Replay attacks.  Client clock is sync’d with server, with the allowance of 5 min skew.
  • Kerberos target principle name (realm, a Kerberos grouping that uses the same key [the users password]).
  • Requested life time.
  • Nonce, a random message number to prevent replay attacks.
4. KRB_AS_REP message sent back from server to client, consisting of:
  • Part one: Encrypted with the users password containing:
    1. User-TGS key (generated by the KDC).
    2. Kerberos target principle name (realm).
    3. Ticket lifetime.
  • Part Two: The TGT, encrypted using a TGS key generated by the KDC so that only the server can open it (even though it is stored by the client for use during further transactions), containing:
    1. User-TGS key (which is not retained by the KDC, but its presence within the TGT means it is available when required).
    2. Client principal name.
    3. Ticket lifetime.
    4. KDC timestamp.
    5. Client IP address (taken from the initial KRB_AS_REQ).
Part one of the message can only be used if successfully decrypted by the client using their password.

Ticket Granting Service (TGS) exchange


1. The service ticket request (KRB_TGS_REQ) from client to server containing:
  • Service principal name.
  • Requested lifetime.
  • TGT, still encrypted with the TGS key.
  • Authenticator, encrypted with the user-TGS key and containing a client timestamp, guaranteeing that the request originated from the client.
2. The KRB_TGS_REP service ticket reply is again in two parts:
  • Part one is encrypted with the user-TGS key (taken from the TGT by the KDC) and contains:
    1. Service principal name.
    2. Ticket lifetime.
    3. User service key (encrypted with a user-TGS session key, generated by the KDC).
  • Part two is the Service Ticket (ST), encrypted using the service-TGS key and contains:
    1. User service key (encrypted with a user-TGS session key, generated by the KDC).
    2. Client principal name.
    3. Ticket lifetime.
    4. KDC timestamp.
    5. Client IP address.

Client/Server (CS) exchange

(messages are known as AP: Application Privilege)


1. When the client requires access to the service, the AP exchange KRB_AP_REQ contains:
  • The service ticket (ST), still encrypted using the service-TGS key
  • An authenticator (encrypted with the user-service key). 

Conclusion


So that's how Kerberos works.  The key points to remember are that:
  • AS exchange occurs at logon, providing the client with a TGT.
  • The TGT allows the client to enter a TGS exchange (which authenticates the client), returning an ST.
  • The ST identifies the authenticated client to a service following which the service will provide access (but only if the client passes the service's own authorisation criteria).
  • Messages are encrypted so only the KDC can read the TGT & only the service can read the ST.

Saturday 5 May 2012

Silverlight ViewModel Tests

As everyone knows Microsoft didn’t exactly have test driven development as their main focus when creating Silverlight.

Nowadays whilst testing in Silverlight has greatly improved, with both Microsoft and the community providing better test options for Silverlight, the situation is still not as good as we are used to in the rest of the .NET world.  For example, it’s a real pain not being able to run NCrunch in Silverlight or use xUnit or NUnit for my tests (there is an NUnit for Silverlight project but it’s out of date at the moment).

I currently use Silverlight Unit Tests (part of the Silverlight Toolkit SDK), StatLight with TeamCity integration and AgUnit for ReSharper as the test runner within Visual Studio.

Here’s how it’s done:

image

Create a Silverlight Application which will be your main XAP file project.  The trick is that this will act as a shell containing purely your views and your app.xaml file.  You'll probably want to create it with an ASP.NET Web Server Host project.

Next up create a Silverlight Class Library that we’ll call our Presentation Layer.  This will contain all the “code” such as your commands, converters and view models, etc.

Now we can add a Silverlight class library to our solution that will contain our tests.

UI Prototype

image

Code to Interfaces

First up define the interface to your ViewModel based on our UI prototype.

namespace SilverlightValidation.Interfaces
{
public interface IUserViewModel : INotifyDataErrorInfo,
INotifyPropertyChanged,
IUserModel
{
bool IsChanged { get; }
ICommand OkCommand { get; set; }
ICommand CancelCommand { get; set; }
}

public interface IUserModel
{
string Username { get; set; }
string Email { get; set; }
string Password { get; set; }
DateTime? DateOfBirth { get; set; }
string Description { get; set; }
}

public interface ICloneable<T>
{
T Clone();
}
}

Fluent Assertions

Fluent Assertions

For our tests I use the Fluent Assertions library to help reduce code and make the tests easier to read.

Fluent Assertions on Codeplex:    http://fluentassertions.codeplex.com/

ShouldRaisePropertyChangeFor

A good example is the Event Monitoring provided by Fluent Assertions, which internally contains an assert check for the Username Property Changed event.
var subject = new UserViewModel();
subject.MonitorEvents();
subject.Username = "adminSH";
subject.ShouldRaisePropertyChangeFor(x => x.Username);

View Model Tests


Helper for tests                               https://gist.github.com/2624206

A helper class that acts as a factory for providing pre-built objects such as a default ViewModel.

Constructor tests                             https://gist.github.com/2624197

When using Dependency Injection we need to check the arguments in our constructor are valid.

Commands tests                              https://gist.github.com/2624192

Check the commands are executable and execute as required.  For example, the OK command which might normally save to the database could be using a database service which could be mocked out by the test to check it has been executed.

INotifyDataErrorInfo tests                 https://gist.github.com/2624201

Validation rules need to be adhered to so we’ll need to test data values pass, fail and boundary check our validation logic.

INotifyPropertyChanged tests           https://gist.github.com/2624203

Obviously we’re using data binding in our view so we need to make sure property change notification events are being fired as we update our properties. I love the Fluent Assertions library for this, it gives a very clean and read to easy syntax for the tests – great framework!


Test Runner Output in Visual Studio


image


TeamCity CI Server Output


With the StatLight tool added to the repo a simple build step can be added to TeamCity:

StatLight.exe -d="SilverlightValidation\SilverlightValidation.Tests\bin\Release\SilverlightValidation.Tests.dll" –teamcity


image


StatLight Output


If you want to manually run StatLight outside of the Visual Studio process:


image


Browser Test Runner


image


Screenshot of working version


image


This online demo is here:  http://stevenhollidge.com/blog-source-code/slvalidation/


TODO: UI test recording (TestComplete or Telerik)


Source code

http://stevenhollidge.com/blog-source-code/SilverlightValidation.zip

Tuesday 1 May 2012

PDFs in Silverlight

Displaying PDFs

Your three main options are:

  1. Use the native web browser control in Silverlight, which requires a few hoops to jump through

  2. Use a free third party HTML content control, the example I show is the free control from DivElements

  3. Use a commercial third party HTML content control which is more robust, Infragistics is a good option.

Approach #1: Native Silverlight Web Browser control

To view PDFs in Silverlight you need to run the application with elevated permissions.  This can be done in browser but for this simple example I’ll show how to display PDFs in a Silverlight application running “out of browser”.

The key is the WebBrowser control that automatically hosts an Adobe Reader plugin, which is required to be installed on the client machine.

First create a Silverlight Application and update the MainPage.xaml file with a WebBrowser control and set the source property:

<UserControl x:Class="PdfsInSL4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="250"
d:DesignWidth="500"
mc:Ignorable="d">

<Grid x:Name="LayoutRoot">
<WebBrowser Source="http://stevenhollidge.com/cv/SJHAP-CV.pdf" />
</Grid>
</UserControl>


For this example I’m using my online CV as the sample PDF file.  If you run the application now you’ll see the browser is blocked.



1



In the project properties check “Enable running application out of browser” and click the “Out-of-browser Settings…” button and check the “Require elevated trust when running outside the browser:



0



Now when you run the Silverlight application you can right click and get the “Install {application name} Application onto this computer…” option.



2



3



Once the application is installed with elevated trust your web browser control will load the PDF.



4



Printing PDFs



The Adobe Reader plugin provides print functionality along with Find, Paging, Zoom, Rotate functionality and more.  Here is the print dialog:



5



Approach #2: HTML Content Viewer Controls

As well as HTML viewers from Telerik and Infragistics there is a third free option from DivElements. Some drawback are whilst it’s free it require the “windowless” Silverlight param property to be set to true and it’s not the most robust control in the world.

Setting Windowless = true (index.html in the example source code)

<body>
<form id="form1" runat="server" style="height:100%">
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/DivElementTools.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="5.0.61118.0" />
<param name="autoUpgrade" value="true" />
<param name="windowless" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object>
<iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe>
</div>
</form>
</body>
</html>

MainPage.xaml

<UserControl x:Class="DivElementTools.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:divtools="clr-namespace:Divelements.SilverlightTools;assembly=Divelements.SilverlightTools"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">

<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Height="25"
Margin="10,17,10,10"
Text="Uri:" />
<TextBox x:Name="textboxUri"
Grid.Column="1"
Height="25"
Margin="10"
Text="http://stevenhollidge.com/cv/SJHAP-CV.pdf" />
</Grid>

<divtools:HtmlHost Name="htmlHost"
Grid.Row="1"
SourceUri="{Binding ElementName=textboxUri,
Path=Text}" />
</Grid>
</UserControl>


Vendor: http://www.divelements.co.uk/silverlight/tools.aspx

Online demo: http://stevenhollidge.com/blog-source-code/pdfs/

Example source code: http://stevenhollidge.com/blog-source-code/PdfsInSilverlight.zip


Approach #3: Infragistics HTML Content control


http://samples.infragistics.com/sllob/html-viewer/sl/#/navigating-and-custom-html