C#, WPF

Sonic : Things Keep Getting Better And Better

A while ago now I published my last article on LINQ/WPF goodness, which was a fully searchable working media library written using some pretty cool stuff. This article scooped the highly prized www.codeproject.com best C# article for Feb 2009 and also best overall article, and to top that it has also won the 1st price for the February Smart Client App comp over at www.codeproject.com, which has some Microsoft funding, and judges. So I am pretty happy about that one.

There are some good articles in the Smart Client App comp, for example a very good one is Daniel Vaughan Perceptor, which uses a Neural Network to predict possible user navigation paths inside a WPF app. Nice. Daniel could/and always has in the past provided some very very thought provoking articles, I urge you all to read and encourage Daniels efforts. The kid knows what he is doing.

I think Daniel could actually win the Smart Client App comp overall, though I have to say "it aint over til the fat lady sings" and I just may have a few more smart client articles yet.

Advertisements
C#, CodeProject, Silverlight, WPF

Scrollable Friction Canvas For Silverlight

A while back I published a post about creating a friction enabled scrolling canvas in WPF (the old post can be found at http://sachabarber.net/?p=225), which I thought was way cool. It turns out that I was not the only one that thought this, and one of my WPF Buddies and fellow WPF Disciples Jeremiah Morrill thought it was so cool that he turned it into a Silverlight Content control. Thoughtful old Jerimiah even sent me the code back, which I think is awesome of him.

As a result I thought I would let you all have it. So here goes.

This is what Jer has done, here is the actual ContentControl, which has my friction stuff in it

   1:  using System;
   2:  using System.Windows;
   3:  using System.Windows.Controls;
   4:  using System.Windows.Input;
   5:  using System.Windows.Threading;
   6:  
   7:  namespace FlickScrollerApp
   8:  {
   9:      [TemplatePart(Name = "PART_ScrollViewer",
             Type = typeof(ScrollViewer))]
  10:      public class FlickScrollView : ContentControl
  11:      {
  12:          private readonly DispatcherTimer m_animationTimer =
  13:          new DispatcherTimer();
  14:          private double m_friction;
  15:          private Point m_currentMousePos;
  16:          private Point m_previousPoint;
  17:          private Point m_scrollStartOffset = new Point();
  18:          private Point m_scrollStartPoint;
  19:          private Point m_scrollTarget = new Point();
  20:          private Vector m_velocity;
  21:          private ScrollViewer scrollViewer;
  22:  
  23:          public FlickScrollView()
  24:          {
  25:              DefaultStyleKey = typeof(FlickScrollView);
  26:  
  27:              m_friction = 0.98;
  28:  
  29:              m_animationTimer.Interval = new
                     TimeSpan(0, 0, 0, 0, 20);
  30:              m_animationTimer.Tick += HandleWorldTimerTick;
  31:              m_animationTimer.Start();
  32:  
  33:              MouseMove += MouseMoveHandler;
  34:              MouseLeftButtonUp += MouseLeftButtonUpHandler;
  35:              MouseLeftButtonDown += MouseLeftButtonDownHandler;
  36:          }
  37:  
  38:          private bool IsMouseCaptured { get; set; }
  39:  
  40:          public double Friction
  41:          {
  42:              get { return 1.0 - m_friction; }
  43:              set { m_friction =
                       Math.Min(Math.Max(1.0 - value, 0), 1.0); }
  44:          }
  45:  
  46:          public override void OnApplyTemplate()
  47:          {
  48:              base.OnApplyTemplate();
  49:              scrollViewer = GetTemplateChild("PART_ScrollViewer")
                      as ScrollViewer;
  50:          }
  51:  
  52:          private void MouseLeftButtonDownHandler(object sender,
  53:          MouseButtonEventArgs e)
  54:          {
  55:              if (scrollViewer == null)
  56:                  return;
  57:  
  58:              m_scrollStartPoint = e.GetPosition(this);
  59:              m_scrollStartOffset.X = scrollViewer.HorizontalOffset;
  60:              m_scrollStartOffset.Y = scrollViewer.VerticalOffset;
  61:  
  62:              CaptureMouse();
  63:  
  64:              IsMouseCaptured = true;
  65:          }
  66:  
  67:          private void MouseLeftButtonUpHandler(object sender,
  68:          MouseButtonEventArgs e)
  69:          {
  70:              if (!IsMouseCaptured)
  71:                  return;
  72:  
  73:              ReleaseMouseCapture();
  74:              IsMouseCaptured = false;
  75:          }
  76:  
  77:          private void MouseMoveHandler(object sender, MouseEventArgs e)
  78:          {
  79:              if (scrollViewer == null)
  80:                  return;
  81:  
  82:              m_currentMousePos = e.GetPosition(this);
  83:  
  84:              if (IsMouseCaptured)
  85:              {
  86:                  Point currentPoint = e.GetPosition(this);
  87:  
  88:                  // Determine the new amount to scroll.
  89:                  var delta = new Point(m_scrollStartPoint.X -
  90:              currentPoint.X, m_scrollStartPoint.Y - currentPoint.Y);
  91:  
  92:                  m_scrollTarget.X = m_scrollStartOffset.X + delta.X;
  93:                  m_scrollTarget.Y = m_scrollStartOffset.Y + delta.Y;
  94:  
  95:                  // Scroll to the new position.
  96:                  scrollViewer.ScrollToHorizontalOffset(m_scrollTarget.X);
  97:                  scrollViewer.ScrollToVerticalOffset(m_scrollTarget.Y);
  98:              }
  99:          }
 100:  
 101:          private void HandleWorldTimerTick(object sender, EventArgs e)
 102:          {
 103:              if (scrollViewer == null)
 104:                  return;
 105:  
 106:              if (IsMouseCaptured)
 107:              {
 108:                  Point currentPoint = m_currentMousePos;
 109:                  m_velocity.X = m_previousPoint.X - currentPoint.X;
 110:                  m_velocity.Y = m_previousPoint.Y - currentPoint.Y;
 111:                  m_previousPoint = currentPoint;
 112:              }
 113:              else
 114:              {
 115:                  if (m_velocity.Length > 1)
 116:                  {
 117:                      scrollViewer.ScrollToHorizontalOffset(m_scrollTarget.X);
 118:                      scrollViewer.ScrollToVerticalOffset(m_scrollTarget.Y);
 119:                      m_scrollTarget.X += m_velocity.X;
 120:                      m_scrollTarget.Y += m_velocity.Y;
 121:                      m_velocity *= m_friction;
 122:                  }
 123:              }
 124:          }
 125:      }
 126:  }

.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; }And here is how you would use it in XAML

   1:  <UserControl x:Class="FlickScrollerApp.MainPage"
   2:               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:               xmlns:FlickScrollerApp="clr-namespace:FlickScrollerApp"
   5:               Width="400"
   6:               Height="300">
   7:      <Grid x:Name="LayoutRoot"
   8:            Background="White">
   9:          <FlickScrollerApp:FlickScrollView>
  10:              <StackPanel>
  11:                  <Rectangle Fill="Red"
  12:                             Width="400"
  13:                             Height="200"
  14:                             IsHitTestVisible="False" />
  15:                  <Rectangle Fill="Blue"
  16:                             Width="400"
  17:                             Height="200"
  18:                             IsHitTestVisible="False" />
  19:                  <Rectangle Fill="Red"
  20:                             Width="400"
  21:                             Height="200"
  22:                             IsHitTestVisible="False" />
  23:                  <Rectangle Fill="Blue"
  24:                             Width="400"
  25:                             Height="200"
  26:                             IsHitTestVisible="False" />
  27:                  <Rectangle Fill="Red"
  28:                             Width="400"
  29:                             Height="200"
  30:                             IsHitTestVisible="False" />
  31:                  <Rectangle Fill="Blue"
  32:                             Width="400"
  33:                             Height="200"
  34:                             IsHitTestVisible="False" />
  35:                  <Rectangle Fill="Red"
  36:                             Width="400"
  37:                             Height="200"
  38:                             IsHitTestVisible="False" />
  39:              </StackPanel>
  40:          </FlickScrollerApp:FlickScrollView>
  41:      </Grid>
  42:  </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; }

And another nice thing Jer has done is provide a Theme

   1:  <ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   2:                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:                      xmlns:FlickScrollerApp="clr-namespace:FlickScrollerApp">
   4:      <Style TargetType="FlickScrollerApp:FlickScrollView">
   5:          <Setter Property="IsEnabled"
   6:                  Value="true" />
   7:          <Setter Property="HorizontalContentAlignment"
   8:                  Value="Left" />
   9:          <Setter Property="VerticalContentAlignment"
  10:                  Value="Top" />
  11:          <Setter Property="Cursor"
  12:                  Value="Arrow" />
  13:          <Setter Property="Background"
  14:                  Value="#00000000" />
  15:          <Setter Property="Template">
  16:              <Setter.Value>
  17:                  <ControlTemplate TargetType="FlickScrollerApp:FlickScrollView">
  18:                      <Border Background="{TemplateBinding Background}"
  19:                              BorderBrush="{TemplateBinding BorderBrush}"
  20:                              BorderThickness="{TemplateBinding BorderThickness}"
  21:                              CornerRadius="2">
  22:                          <ScrollViewer x:Name="PART_ScrollViewer">
  23:                              <ContentControl Content="{TemplateBinding Content}"
  24:                                ContentTemplate="{TemplateBinding ContentTemplate}"
  25:                                Cursor="{TemplateBinding Cursor}"
  26:                                HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
  27:                                HorizontalContentAlignment=
  28:                  "{TemplateBinding HorizontalContentAlignment}"
  29:                                FontFamily="{TemplateBinding FontFamily}"
  30:                                FontSize="{TemplateBinding FontSize}"
  31:                                FontStretch="{TemplateBinding FontStretch}"
  32:                                Foreground="{TemplateBinding Foreground}"
  33:                                Margin="{TemplateBinding Padding}"
  34:                                VerticalAlignment="{TemplateBinding VerticalAlignment}"
  35:                                VerticalContentAlignment=
  36:                  "{TemplateBinding VerticalContentAlignment}" />
  37:                          </ScrollViewer>
  38:                      </Border>
  39:                  </ControlTemplate>
  40:              </Setter.Value>
  41:          </Setter>
  42:      </Style>
  43:  </ResourceDictionary>

Here is a small Silverlight 3 project that demonstrates this.

flickscrollerapp.zip

Cheers Jer, you rock

C#, Lambdas / Anonomous delegates, LINQ, WPF

Double Whammy Goodness

I just got an email from Chris Maunder today to tell me that my Sonic article (http://www.codeproject.com/KB/smart/Sonic.aspx) has won the 2 following awards, that’s 2 awards

  • Best C# article of February 2009
  • Best overall article of February 2009

Excellent today winning articles, tomorrow the world. Muah Ha Ha

 

Too be honest I was very pleased with Sonic, so I am happy it has done well.

CodeProject, Lambdas / Anonomous delegates, WPF

MVVM Mediator Pattern

About 1 year ago a good friend of mine Marlon Grech wrote a lovely article on MVC + M. You can read all about Marlons great article over at http://marlongrech.wordpress.com/2008/03/20/more-than-just-mvc-for-wpf/

Essentially what Marlon did was create a message system to allow disparate MVC classes to communicate with each other. The original code by Marlon was spot on, but I just didn’t like the way he was using strings for his messages, but other than that there is very little change from my code here to his code. So well done Marlon, you are ace.

Anyway the idea behind Marlons original post was using the MVC pattern along with an additional class called the Mediator whom knew about messages and who to notify when something happened that warrants a message being sent out.

These days most folk will use the MVVM pattern when developing WPF. I have a small demo app that does the following.

  1. It has 2 textboxes, one of which is a writable textbox, which is used to send messages via the Mediator
  2. The 2nd textbox is refreshed via the message that is sent via the Mediator when the 1st textbox changes

Lets have a look at some code:

1st a helper class (lifted from Marlons blog)

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  
   6:  namespace MediatorDemo
   7:  {
   8:      /// <summary>
   9:      /// The multi dictionary is a dictionary that contains 
  10:      /// more than one value per key
  11:      /// </summary>
  12:      /// <typeparam name="T">The type of the key</typeparam>
  13:      /// <typeparam name="K">The type of the list contents</typeparam>
  14:      public class MultiDictionary<T, K>
  15:          : Dictionary<T, List<K>>
  16:      {
  17:  
  18:          #region Private Methods
  19:          //checks if the key is already present
  20:          private void EnsureKey(T key)
  21:          {
  22:              if (!ContainsKey(key))
  23:              {
  24:                  this[key] = new List<K>(1);
  25:              }
  26:              else
  27:              {
  28:                  if (this[key] == null)
  29:                      this[key] = new List<K>(1);
  30:              }
  31:          }
  32:          #endregion
  33:  
  34:          #region Public Methods
  35:          /// <summary>
  36:          /// Adds a new value in the Values collection
  37:          /// </summary>
  38:          /// <param name="key">The key where to place the 
  39:          /// item in the value list</param>
  40:          /// <param name="newItem">The new item to add</param>
  41:          public void AddValue(T key, K newItem)
  42:          {
  43:              EnsureKey(key);
  44:              this[key].Add(newItem);
  45:          }
  46:  
  47:  
  48:          /// <summary>
  49:          /// Adds a list of values to append to the value collection
  50:          /// </summary>
  51:          /// <param name="key">The key where to place the item in the value list</param>
  52:          /// <param name="newItems">The new items to add</param>
  53:          public void AddValues(T key, IEnumerable<K> newItems)
  54:          {
  55:              EnsureKey(key);
  56:              this[key].AddRange(newItems);
  57:          }
  58:  
  59:          /// <summary>
  60:          /// Removes a specific element from the dict
  61:          /// If the value list is empty the key is removed from the dict
  62:          /// </summary>
  63:          /// <param name="key">The key from where to remove the value</param>
  64:          /// <param name="value">The value to remove</param>
  65:          /// <returns>Returns false if the key was not found</returns>
  66:          public bool RemoveValue(T key, K value)
  67:          {
  68:              if (!ContainsKey(key))
  69:                  return false;
  70:  
  71:              this[key].Remove(value);
  72:  
  73:              if (this[key].Count == 0)
  74:                  this.Remove(key);
  75:  
  76:              return true;
  77:          }
  78:  
  79:          /// <summary>
  80:          /// Removes all items that match the prediacte
  81:          /// If the value list is empty the key is removed from the dict
  82:          /// </summary>
  83:          /// <param name="key">The key from where to remove the value</param>
  84:          /// <param name="match">The predicate to match the items</param>
  85:          /// <returns>Returns false if the key was not found</returns>
  86:          public bool RemoveAllValue(T key, Predicate<K> match)
  87:          {
  88:              if (!ContainsKey(key))
  89:                  return false;
  90:  
  91:              this[key].RemoveAll(match);
  92:  
  93:              if (this[key].Count == 0)
  94:                  this.Remove(key);
  95:  
  96:              return true;
  97:          }
  98:          #endregion
  99:      }
 100:  }

.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 simply allows more than 1 object to be registered for a particular message

Next comes the Mediator which is a singleton, and know how to send and register messages against callback, which is what I have changed. In Marlons original code he used Strings, where as I am now using Action<Object> delegates as callbacks. A minor improvement I feel.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  
   6:  namespace MediatorDemo
   7:  {
   8:      /// <summary>
   9:      /// Available cross ViewModel messages
  10:      /// </summary>
  11:      public enum ViewModelMessages { UserWroteSomething = 1 };
  12:  
  13:  
  14:      public sealed class Mediator
  15:      {
  16:          #region Data
  17:          static readonly Mediator instance = new Mediator();
  18:          private volatile object locker = new object();
  19:  
  20:          MultiDictionary<ViewModelMessages, Action<Object>> internalList
  21:              = new MultiDictionary<ViewModelMessages, Action<Object>>();
  22:          #endregion
  23:  
  24:          #region Ctor
  25:          //CTORs
  26:          static Mediator()
  27:          {
  28:  
  29:  
  30:          }
  31:  
  32:          private Mediator()
  33:          {
  34:  
  35:          }
  36:          #endregion
  37:  
  38:          #region Public Properties
  39:  
  40:          /// <summary>
  41:          /// The singleton instance
  42:          /// </summary>
  43:          public static Mediator Instance
  44:          {
  45:              get
  46:              {
  47:                  return instance;
  48:              }
  49:          }
  50:  
  51:          #endregion
  52:  
  53:          #region Public Methods
  54:          /// <summary>
  55:          /// Registers a Colleague to a specific message
  56:          /// </summary>
  57:          /// <param name="callback">The callback to use 
  58:          /// when the message it seen</param>
  59:          /// <param name="message">The message to 
  60:          /// register to</param>
  61:          public void Register(Action<Object> callback,
  62:              ViewModelMessages message)
  63:          {
  64:              internalList.AddValue(message, callback);
  65:          }
  66:  
  67:  
  68:          /// <summary>
  69:          /// Notify all colleagues that are registed to the 
  70:          /// specific message
  71:          /// </summary>
  72:          /// <param name="message">The message for the notify by</param>
  73:          /// <param name="args">The arguments for the message</param>
  74:          public void NotifyColleagues(ViewModelMessages message,
  75:              object args)
  76:          {
  77:              if (internalList.ContainsKey(message))
  78:              {
  79:                  //forward the message to all listeners
  80:                  foreach (Action<object> callback in
  81:                      internalList[message])
  82:                          callback(args);
  83:              }
  84:          }
  85:          #endregion
  86:  
  87:      }
  88:  }

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

So how does this work, well lets see a ViewModel that sends a message via the mediator, notice the NotifyColleagues(..) method usage below.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Linq;
   5:  using System.Text;
   6:  using System.Windows.Input;
   7:  using System.Windows.Data;
   8:  
   9:  
  10:  namespace MediatorDemo
  11:  {
  12:      public class WritersViewModel : ViewModelBase
  13:      {
  14:          private String writerText = null;
  15:  
  16:  
  17:          public WritersViewModel()
  18:          {
  19:  
  20:  
  21:          }
  22:  
  23:          public String WriterText
  24:          {
  25:              get { return writerText; }
  26:              set
  27:              {
  28:                  writerText = value;
  29:                  NotifyChanged("WriterText");
  30:                  //alert others about this change
  31:                  //via Mediator
  32:                  Mediator.Instance.NotifyColleagues(
  33:                      ViewModelMessages.UserWroteSomething,
  34:                          writerText);
  35:              }
  36:          }
  37:  
  38:      }
  39:  }

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

And how about dealing with a message from the Mediator, this is fairly simple, though we do have to cast the results from Object to the Type we are expecting. This is necessary as the Mediator uses Action<Object> delegates as callbacks, where Object could be any Type of course.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Linq;
   5:  using System.Text;
   6:  using System.Windows.Input;
   7:  
   8:  
   9:  namespace MediatorDemo
  10:  {
  11:      public class ReadersViewModel : ViewModelBase
  12:      {
  13:          private String readText = String.Empty;
  14:  
  15:  
  16:          public ReadersViewModel()
  17:          {
  18:              //register to the mediator for the 
  19:              //UserWroteSomething message
  20:              Mediator.Instance.Register(
  21:  
  22:                  //Callback delegate, when message is seen
  23:                  (Object o) =>
  24:                  {
  25:                      ReadText = (String)o;
  26:                  }, ViewModelMessages.UserWroteSomething);
  27:          }
  28:  
  29:  
  30:          public String ReadText
  31:          {
  32:              get { return readText; }
  33:              set
  34:              {
  35:                  readText = value;
  36:                  NotifyChanged("ReadText");
  37:              }
  38:          }
  39:      }
  40:  }

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

And that is really all there is to it. You now have a Writer ViewModel that will notify a totally disconnected Reader ViewModel about a change, via the messaging providing by the Mediator/Action<Object> delegate callbacks, that were registered for the message by the class that wants to do something based on the message being registered with the Mediator.

As I say this is all thanks to Marlon, well done Marlon.

And here is a small demo app for you to play with

mediatordemo.zip

WCF

RESTful WCF Part 2 of n

A while back (can’t remember exactly when) I started saying I was going to write a bit about RESTFul WCF, you can see my 1st post at http://sachabarber.net/?p=460. In that post I mentioned that I would probably do the following:

The schedule of posts is probably going to be something like this

  1. The new RESTful WCF attributes
  2. Serialization options (this article)
  3. Hosting
  4. CRUD operations using RESTful WCF

 

Well this is basically part2. Your options for serialization when working with RESTful WCF

In this blog entry we will be covered the following serialization options.

Message

  • DataContract
  • XML
  • Hybrid
  • JSON

This blog entry says nothing about how to deal with the resources once they are made available from the RESTful WCF service, is is assumed that the reader will know what to do with the exposed resources.

Here is a hint, have a look at XLINQ or any of the numerous XML APIs.

 

Helper Methods

Before we start I would just like to point out that the attached service looks like this

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.ServiceModel.Channels;
   7:  using System.Text;
   8:  using System.ServiceModel.Web;
   9:   
  10:  namespace DataService
  11:  {
  12:      [ServiceContract(SessionMode = 
  13:          SessionMode.NotAllowed)]
  14:      public interface ISomeService
  15:      {
  16:   
  17:          /// <summary>
  18:          /// The OperationContracts below show how to use different 
  19:          /// Serialization techniques such as 
  20:          /// <list type="Bullet">
  21:          /// <item>Message (the most customizable/flexability)</item>
  22:          /// <item>DataContract</item>
  23:          /// <item>XML</item>
  24:          /// <item>Hybrid approach</item>
  25:          /// </list>
  26:          /// </summary>
  27:   
  28:          [OperationContract]
  29:          [WebGet(UriTemplate = "/")]
  30:          Message GetRoot();
  31:   
  32:          [OperationContract]
  33:          [WebGet(UriTemplate = "/DC/{firstName}/{lastName}")]
  34:          Person GetRootPersonUsingDataContract(String firstName, 
  35:              String lastName);
  36:   
  37:          [OperationContract]
  38:          [WebGet(UriTemplate = "/DC/PeopleList")]
  39:          PersonList GetRootPersonListUsingDataContract();
  40:   
  41:          [OperationContract]
  42:          [XmlSerializerFormat()]
  43:          [WebGet(UriTemplate = "/XMLSer/{animalBreed}")]
  44:          Animal GetRootAnimalUsingXmlSerialization(String animalBreed);
  45:   
  46:          [OperationContract]
  47:          [XmlSerializerFormat()]
  48:          [WebGet(UriTemplate = "/XMLSer/AnimalList")]
  49:          AnimalList GetRootAnimalListUsingXmlSerialization();
  50:   
  51:   
  52:          [OperationContract]
  53:          [WebGet(UriTemplate = "/HYBRID/{firstName}/{lastName}")]
  54:          Message GetRootPersonUsingHybridStylee(String firstName,
  55:              String lastName);
  56:   
  57:          [OperationContract]
  58:          [WebGet(UriTemplate = "/HYBRID/PeopleList")]
  59:          Message GetRootPersonListUsingHybridStylee();
  60:   
  61:   
  62:          /// <summary>
  63:          /// The OperationContracts below show how to use different 
  64:          /// ResponseFormats such as XML/JSON
  65:          /// </summary>
  66:   
  67:          [OperationContract]
  68:          [WebGet(UriTemplate = "/DC/XML/{firstName}/{lastName}", 
  69:              ResponseFormat=WebMessageFormat.Xml)]
  70:          Person GetRootPersonUsingDataContractXML(String firstName, 
  71:              String lastName);
  72:   
  73:          [OperationContract]
  74:          [WebGet(UriTemplate = "/DC/XML/PeopleList", 
  75:              ResponseFormat = WebMessageFormat.Xml)]
  76:          PersonList GetRootPersonListUsingDataContractXML();
  77:   
  78:   
  79:   
  80:          [OperationContract]
  81:          [WebGet(UriTemplate = "/DC/JSON/PeopleList",
  82:              ResponseFormat = WebMessageFormat.Json)]
  83:          PersonList GetRootPersonListUsingDataContractJSON();
  84:   
  85:      }
  86:  }

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

That the service implementation makes use of several helper methods that look like this

   1:  private Person GetPerson(
   2:      String firstName, String lastName)
   3:  {
   4:      return new Person { FirstName = firstName, LastName = lastName };
   5:  }
   6:   
   7:  private PersonList PersonList()
   8:  {
   9:      return new PersonList {
  10:          new Person { FirstName = "firstName1", LastName = "lastName1" },
  11:          new Person { FirstName = "firstName2", LastName = "lastName2" },
  12:          new Person { FirstName = "firstName3", LastName = "lastName3" },
  13:          new Person { FirstName = "firstName4", LastName = "lastName4" }
  14:      };
  15:  }

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

 

 

Message

Message is the most flexable of all the different Serialization techniques offered my WCF, as its the closest to the actual Channel that is used to transmit the Message, and it also offers the most freedom to customise the serialization process. As a side effect it also requires the most work.

For example when we have a service method like this

 

   1:  [OperationContract]
   2:  [WebGet(UriTemplate = "/")]
   3:  Message GetRoot();

 

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

And the actual service implementation looks like this.

 

   1:  //Matches [WebGet(UriTemplate = "/")]
   2:  public Message GetRoot()
   3:  {
   4:   
   5:      var stream = new MemoryStream();
   6:      XmlDictionaryWriter writer =
   7:          XmlDictionaryWriter.CreateTextWriter(stream);
   8:      writer.WriteStartDocument();
   9:      writer.WriteStartElement("Root");
  10:      writer.WriteStartElement("Hello");
  11:      writer.WriteElementString("Name", "sacha");
  12:      writer.WriteEndElement();
  13:      writer.WriteEndElement();
  14:      writer.WriteEndDocument();
  15:      writer.Flush();
  16:      stream.Position = 0;
  17:   
  18:      XmlDictionaryReader reader =
  19:          XmlDictionaryReader.CreateTextReader(
  20:          stream, XmlDictionaryReaderQuotas.Max);
  21:      return Message.CreateMessage(
  22:          MessageVersion.None, "", reader);
  23:  }

 

We would get the following

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

image

Which is cool, but this is a lot of work to get these resources, which we could get in other ways. Lets consider some of the other options.

 

DataContract

Is by far the easiest approach as we simply rely on the existing WCF DataContractSerializer, which does all the heavy work for us. The issue with this approach is that the XML we end up with may not always be what we are after, and we don’t have that much control over it. So if this is an issue, you could always go for Message type Serialization or one of the other options here.

In order to demonstrate DataContract Serialization we start with an actual DataContract class/DataContract collection, which for the attached demo code look like this

   1:  [DataContract()]
   2:  public class Person
   3:  {
   4:      [DataMember]
   5:      public String FirstName;
   6:   
   7:      [DataMember]
   8:      public String LastName;
   9:   
  10:  }
  11:   
  12:   
  13:  [CollectionDataContract(Name = "People", Namespace = "")]
  14:  public class PersonList : List<Person>
  15:  {
  16:  }

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

 

So we can then have some service methods that are defined like this.

 

   1:  [OperationContract]
   2:  [WebGet(UriTemplate = "/DC/{firstName}/{lastName}")]
   3:  Person GetRootPersonUsingDataContract(String firstName, 
   4:      String lastName);
   5:   
   6:  [OperationContract]
   7:  [WebGet(UriTemplate = "/DC/PeopleList")]
   8:  PersonList GetRootPersonListUsingDataContract();

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

 

And the actual service implementation looks like this.

 

   1:  //Matches [WebGet(UriTemplate = "/DC/{firstName}/{lastName}")]
   2:  public Person GetRootPersonUsingDataContract(
   3:      String firstName, String lastName)
   4:  {
   5:      return GetPerson(firstName, lastName);
   6:  }
   7:   
   8:   
   9:  //Matches [WebGet(UriTemplate = "/DC/PeopleList")]
  10:  public PersonList GetRootPersonListUsingDataContract()
  11:  {
  12:      return PersonList();
  13:  }

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

 

Here is an example of this running through the browser.

image

 

XML

XML Serialization has been around a while and to make use of it we need to adorn our classes with special attributes to aid the serialization process. In the example code we use the following class.

   1:  [XmlRoot(Namespace = "", ElementName = "Animal")]
   2:  public class Animal
   3:  {
   4:      [XmlAttribute(AttributeName="breed")]
   5:      public String Breed;
   6:  }
   7:   
   8:   
   9:  [XmlRoot(Namespace = "", ElementName="Animals")]
  10:  public class AnimalList : List<Animal>
  11:  {
  12:  }

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

So we can then have some service methods that are defined like this.

   1:  [OperationContract]
   2:  [XmlSerializerFormat()]
   3:  [WebGet(UriTemplate = "/XMLSer/{animalBreed}")]
   4:  Animal GetRootAnimalUsingXmlSerialization(String animalBreed);
   5:   
   6:  [OperationContract]
   7:  [XmlSerializerFormat()]
   8:  [WebGet(UriTemplate = "/XMLSer/AnimalList")]
   9:  AnimalList GetRootAnimalListUsingXmlSerialization();

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

And the actual service implementation looks like this.

   1:  //Matches[WebGet(UriTemplate = "/XMLSer/{animalBreed}")]
   2:  public Animal GetRootAnimalUsingXmlSerialization(String animalBreed)
   3:  {
   4:      return new Animal { Breed = animalBreed};
   5:  }
   6:   
   7:   
   8:  //Matches[WebGet(UriTemplate = "/XMLSer/AnimalList")]
   9:  public AnimalList GetRootAnimalListUsingXmlSerialization()
  10:  {
  11:      return new AnimalList {
  12:          new Animal { Breed = "breed1"},
  13:          new Animal { Breed = "breed2"},
  14:          new Animal { Breed = "breed3"},
  15:          new Animal { Breed = "breed4"}
  16:      };
  17:  }

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

 

Here is an example of this running through the browser.

 

image

 

Hybrid Approach

If you want to work with strongly typed object but also want to use Messages where you have more control over the serialization process you can go for a hybrid approach which works something like this. We could have some service methods that are defined like this.

   1:  [OperationContract]
   2:  [WebGet(UriTemplate = "/HYBRID/{firstName}/{lastName}")]
   3:  Message GetRootPersonUsingHybridStylee(String firstName,
   4:      String lastName);
   5:   
   6:  [OperationContract]
   7:  [WebGet(UriTemplate = "/HYBRID/PeopleList")]
   8:  Message GetRootPersonListUsingHybridStylee();

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

 

And the actual service implementation looks like this.

   1:  //Matches [WebGet(UriTemplate = "/HYBRID/{firstName}/{lastName}")]
   2:  public Message GetRootPersonUsingHybridStylee(String firstName,
   3:      String lastName)
   4:  {
   5:      Person p = GetPerson(firstName, lastName);
   6:      return Message.CreateMessage(MessageVersion.None, "*", p);
   7:  }
   8:   
   9:   
  10:  //Matches [WebGet(UriTemplate = "/HYBRID/PeopleList")]
  11:  public Message GetRootPersonListUsingHybridStylee()
  12:  {
  13:      PersonList pl = PersonList();
  14:      return Message.CreateMessage(MessageVersion.None, "*", pl);
  15:  }

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

Using the same helper methods as before.

This approach allows us to use strongly typed DataContract objects but use Messages, which allow us to have more control over the serialization process, as it is in the developer control rather than the actual DataContractSerializers.

 

Here is an example of this running through the browser.

 

image

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

 

JSON

Some of you out there may actually be used to web development and are well used to (and even into, just for the record I am not a web guy) working with Javascript/manual Ajax calls. As I say I am most certainly not a web chap, but for completeness let’s look at how we might serialize some RESTful resource results to JSON.

As before most of the heavy lifting is done by way of the some WCF attributes.

Lets firstly look at the service interface method which looks like this, it can be seen that we simply use the WebMessageFormat.Json enum to specify that we want the resources serialized as JSON

   1:  [OperationContract]
   2:  [WebGet(UriTemplate = "/DC/JSON/PeopleList",
   3:      ResponseFormat = WebMessageFormat.Json)]
   4:  PersonList GetRootPersonListUsingDataContractJSON();

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

And then  for the actual service implementation we have this

   1:  //Matches [WebGet(UriTemplate = "/DC/JSON/PeopleList", 
   2:  //          ResponseFormat = WebMessageFormat.Json)]
   3:  public PersonList GetRootPersonListUsingDataContractJSON()
   4:  {
   5:      return PersonList();
   6:  }

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

 

 

Using the same helper methods as before.

And to ensure this works we could use a small sample HTML page (included with the demo code), which I have only tested and got working with IE7. It should work with FF but I didn’t spend too much time on it, as that is not the point I am trying to make, I am merely showing you how the RESTful JSON stuff works.

   1:  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
   2:  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   3:  <html>
   4:  <head>
   5:  <title>JSON Test</title>
   6:  <script type="text/javascript">
   7:   
   8:  function getXmlHttp()
   9:  {
  10:      var xmlHttp;
  11:      try {
  12:          xmlHttp = new XMLHttpRequest();
  13:      }
  14:      catch(e) {
  15:          try {
  16:              xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
  17:          }
  18:          catch (e) {
  19:              try {
  20:                  xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
  21:              }
  22:              catch (e) {
  23:                  alert("the sample only works in browsers with Ajax support");
  24:                  return false;
  25:              }
  26:          }
  27:      }
  28:   
  29:      return xmlHttp;
  30:  }
  31:   
  32:   
  33:  var serviceURI = "http://localhost:8085/SomeService/DC/JSON/PeopleList";
  34:   
  35:  function getStuff()
  36:  {
  37:   
  38:      var xmlHttp=getXmlHttp();
  39:      xmlHttp.onreadystatechange = function() {
  40:          if (xmlHttp.readyState == 4) {
  41:              alert("xmlHttp.readyState");
  42:              var result = (eval(xmlHttp.responseText));
  43:              var person = null;
  44:              alert(result);
  45:              for (var i = 0; i < result.length; i++) {
  46:                  person = result[i];
  47:                  alert("Person found, Firstaname : " + 
  48:                  person.FirstName + " LastName : " + person.LastName);
  49:              }
  50:          }
  51:   
  52:      }
  53:      xmlHttp.open("GET", serviceURI, true);
  54:      xmlHttp.setRequestHeader("Accept","application/json");
  55:      xmlHttp.send(null);
  56:      
  57:  }
  58:   
  59:  </script>
  60:   
  61:  </head>
  62:   
  63:  <body >
  64:  <form name="form1" action="javascript:getStuff()">
  65:  <input type="submit" value="Enter"> </form>
  66:  </body>
  67:  </html>

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

And here is a demo of it running (again against the simple WCF service console host app, that is included with the attached demo code)

image

As I say I am NOT a web man, but again for completeness I WILL be showing you how to host RESTFul WCF services inside ASP .NET/IIS and how to work with a ASP .NET AJAX ScriptManager object in the subsequent post. Which to my mind if I was into the web, would be how you would want to go about things, as you would then get away with not having to write all this crappy javascript AJAX code. Ouch. That simply can not be cool. I know ASP .NET  AJAX is heavy but come on, that xmlHttp.onreadystatechange YUUUUUCKKKK

 

 

Here is a small demo project for this blog entry : simplerestful_serializationexamples.zip

Enjoy

Introduction

WPF 3D Just Got A Bit Easier

For those of you that have worked with WPF will know it does 3D, and know how compelling this can make your apps. Unfortunately it does require a little bit of effort to get something cool up and running in 3D within WPF.

However lady luck is on your side, Josh Smith (WPF Master) has just released 2 open source 3D controls (I’d like to think one of those was actually directly related to a question I once asked Josh, but he of course made it better) which aid in the development of some cool 3D scenarios.

He is calling this offering Thriple, and you can check it out over at the Thriple home page over at codeplex. Here is a link Thriple Home Page

At present it offers a 3D Panel and a 3D Flip Panel with front and back hosts. But if I know Josh there will be more to come.

Enjoy