Wednesday, December 30, 2009

WCF RIA Services – Domain Service Lifecycle

Frederik Normén posted a really good article on the message flow through a Domain Service. Domain Services differ from standard WCF service in that you normally don’t call their operations directly:

For each object you want to expose and edit on your application you expose at least one query method (something that returns an IQueryable of the object) and the CUD methods for that entity.

At the client side that object is exposed in a EntitySet (a set of the entity) where you can add, remove or change entities. Those actions (ChangeSetEntry) will be recorded and collected into a ChangeSet. Once you are finished with the current business operation you call SubmitChanges(). This call will in practice create a wcf request to a service prepared to accept the ChangeSet as a request message. The article explains how the service handles that call. It can be found here.

Wednesday, November 25, 2009

ItemsControl – A simple way to edit and display lists of objects

This control makes me remind of the Repeater control in ASP.NET. It is quite easy to create a very simple list of objects using it. It simply creates one instance of the controls inside the DataTemplate tag per each element in the enumerable object that is bound to ItemsSource.

   1: <navigation:Page x:Class="PlayWithSilverlightControls.Views.PlayWithItemsControl"
   2:            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:            mc:Ignorable="d"
   7:            xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
   8:            d:DesignWidth="640" d:DesignHeight="480"
   9:            Title="PlayWithItemsControl Page">
  10:  
  11:     <Grid x:Name="LayoutRoot">
  12:         <Grid.RowDefinitions>
  13:             <RowDefinition Height="*" />
  14:             <RowDefinition Height="30" />
  15:         </Grid.RowDefinitions>
  16:         <ItemsControl ItemsSource="{Binding ModelItems}">            
  17:             <ItemsControl.ItemTemplate>
  18:                 <DataTemplate>
  19:                     <StackPanel Margin="3,10,0,0">
  20:                         <Rectangle Height="2" Fill="Black" />
  21:                         <TextBlock Text="{Binding Name}" />
  22:                         <TextBox Text="{Binding Comment}" />
  23:                     </StackPanel>
  24:                 </DataTemplate>
  25:             </ItemsControl.ItemTemplate>
  26:         </ItemsControl>
  27:         <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Height="25">
  28:             <Button Content="Submit" Width="150"/>
  29:             <Button Content="Cancel" Width="150"/>
  30:         </StackPanel>
  31:     </Grid>
  32: </navigation:Page>

I used this very simple ViewModel to render some data:

   1: public class Model
   2:     {
   3:         public string Name
   4:         {
   5:             get;
   6:             set;
   7:         }
   8:  
   9:         public string Comment
  10:         {
  11:             get;
  12:             set;
  13:         }
  14:     }
  15:  
  16:     public class PlayWithItemsControlViewModel
  17:     {
  18:         private ObservableCollection<Model> items = new ObservableCollection<Model>();
  19:  
  20:         public PlayWithItemsControlViewModel()
  21:         {
  22:             this.items.Add(new Model { Name = "Model A" });
  23:             this.items.Add(new Model { Name = "Model B" });
  24:             this.items.Add(new Model { Name = "Model C" });
  25:             this.items.Add(new Model { Name = "Model D" });
  26:             this.items.Add(new Model { Name = "Model E" });
  27:         }
  28:  
  29:         public IEnumerable<Model> ModelItems
  30:         {
  31:             get
  32:             {
  33:                 return this.items;
  34:             }
  35:         }
  36:     }

The Model class is not implementing core interfaces such as INotifyPropertyChanged or IEditableObject and therefore most Silverlight features will not work with it. I hope to post some notes on how these interfaces can be implemented and used to enable those features.

We can quickly see the results by placing this code on the view code behind:

   1: // Executes when the user navigates to this page.
   2: protected override void OnNavigatedTo(NavigationEventArgs e)
   3: {
   4:      this.DataContext = new PlayWithItemsControlViewModel();
   5: }

I think it is a good practice to use the ViewModel as the DataContext of the Page and to define bindings assuming just that.

To host it create a Navigation application and go to the MainPage.xaml and add a new navigation button at the bottom of the xaml:

   1: <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
   2:  
   3: <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" 
   4:     NavigateUri="/PlayWithItemsControl" TargetName="ContentFrame" Content="Items Control"/>

Have fun,

Tuesday, November 24, 2009

Moq – Port to Silverlight 4

 

If you are in love with TDD you know Moq. It is one of the best Mocking frameworks out there… I’m working on SL4 and could not live without it! The problem is binaries for SL4 are not available yet.

To compile Moq on Silverlight 4 you just need the Castle dlls compiled for the runtime 4 and to recompile the source code. I ported the castle source code to Silverlight 4 and sent the patch to Castle project. Hope this will get on trunk soon. In the meantime you can download Moq and Castle compiled to SL4 here:

Castle.Core

Castle.DynamicProxy2

Moq Debug Compilation

Moq Release Compilation

Moq Source Code with updated projects

Have fun,

Thursday, September 24, 2009

Guid properties and XAML serialization in Silverlight

Today I found that the XAML parser of Silverlight can’t handle Guids. You need to set a type converter to handle them! In WPF Guid properties are handled automatically.

To get it working you need to add this converter to your project:

   1: public class GuidConverter : TypeConverter
   2: {
   3:     public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
   4:     {
   5:         if (sourceType == typeof(string))
   6:         {
   7:             return true;
   8:         }
   9:  
  10:         return base.CanConvertFrom(context, sourceType);
  11:     }
  12:  
  13:     public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
  14:     {
  15:         if (destinationType == typeof(Guid))
  16:         {
  17:             return true;
  18:         }
  19:  
  20:         return base.CanConvertTo(context, destinationType);
  21:     }
  22:  
  23:     public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  24:     {
  25:         return new Guid((string)value);
  26:     }
  27:  
  28:     public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
  29:     {
  30:         return ((Guid)value).ToString();
  31:     }
  32: }

And them place this on top of the Guid property:

   1: [TypeConverter(typeof(GuidConverter))]
   2: public new Guid SystemId
   3: {
   4:     get;
   5:     set;
   6: }

Works on my machine!

Have fun,

Pedro

Tuesday, September 15, 2009

Get started with .NET RIA Services

This week I finally got the time to do a deep dive into the world of Silverlight and RIA Services. I’m impressed. This is a really great framework and really takes out some of the pains we had before on business application development. Most applications have a large portion of data-driven stuff in them and this framework reduces the code you need to put-up to run such features to almost nothing.

To get started download and install:

Visual Studio Tools for Silverlight 3

Expression Blend 3 (Not really required but very useful to design silverlight xaml controls.)

Silverlight 3 Toolkit

.NET Ria Services (Don’t forget to download the overview pdf because it contains documentation and hands-on labs.)

SQL Server 2008 Express Edition with Advanced Services

SQL Server 2008 Sample Databases (In this one I choose to install only the files and them run the scripts in management studio.)

The first project

Once everything is installed you can find the Silverlight Business Application template in the Silverlight area for new projects.

ria - create the project

This template will output two projects. One for the Silverlight client and one for the Web Application that contains the server side of the .NET Ria Services.

ria - project structureIf you go to the properties page of the silverlight client you will something called .NET RIA Services link. This setting is telling the extensions that RIA installed in visual studio to project code from the given Web Site into this project. But what does projecting mean?

ria - project linkIf you click on the option to see all files under the client project you will see a folder called Generated_Code. This will contain one file with a name similar to the web site that makes us think they are somehow related. And they are. Projecting means that parts of the code that we are writing at the server will get transformed into equivalent client side code. The word transform here is important because in some cases it is not a simple copy.

ria - exploring code projection 1 

In this article I am following most of the steps included in here.

More advanced stuff – Entity Framework and POCOs

The first thing to get is this sample. If you are already using visual studio 2010 there is a better approach because POCOs are already supported in a CTP here. What these downloads contains is the infrastruture to use simple C# objects as entities in Entity Framework.

 

Have Fun,

Deep dive into WCF Channels

The binding element reads configuration both at the client and server side and assembles the channel factory and the channel listener respectively. It must put the binding elements in the correct order. The recommended order is TransactionFlow, ReliableSession, Security, CompositeDuplex, OneWay, StreamSecurity, MessageEncoding and Transport.

binding element

The following picture ilustrates the relationship between the ChannelListener and the ChannelFactory in WCF. The listener creates the channel at the server side and the factory at the client side. There are several interfaces for the kind of channel that is to be built. In WCF literature those are known as shapes.

Factory and Listener Architecture

One of the possible shapes is the request and reply shape. I like to think on the channel shape as the way each party in the communication sees the channel. In this example the client wants to use the channel to send requests so it is natural that the it sees the channel as a IRequestChannel. In the other hand the server gets the requests from the channel and wants to use it to send the reply back to the client and so it sees the channel as a IReplyChannel.By the way if you are looking for the method the send the reply back it is a member of the RequestContext class.

request reply channel shape

Inside the Transport Binding Element

When assembling the channel one of the first things that WCF does is checking what shapes the channel supports. It does that by calling CanBuildChannelListener and CanBuildChannelFactory.

This snippet shows the source code for a channel with Request and Reply as well as Input and Output shapes.

   1: public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
   2: {
   3:  return
   4:     typeof(TChannel) == typeof(IOutputChannel) ||
   5:     typeof(TChannel) == typeof(IRequestChannel);
   6: }
   7:  
   8: public override bool CanBuildChannelListener<TChannel>(BindingContext context)
   9: {
  10:  return
  11:     typeof(TChannel) == typeof(IInputChannel) ||
  12:     typeof(TChannel) == typeof(IReplyChannel);
  13: }

At some point in the future WCF will call the factory methods to get the listener in the server side and the factory in the client side. In these methods we should validate if it is possible to assemble the factory or the listener based on the current state of the binding and them instantiate them.

   1: public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
   2: {
   3:    if (context == null)
   4:    {
   5:        throw new ArgumentNullException("context");
   6:    }
   7:  
   8:    if (!this.CanBuildChannelFactory<TChannel>(context))
   9:    {
  10:        throw new InvalidOperationException(string.Format("Channel Not Supported - {0}", typeof(TChannel).Name));
  11:    }
  12:  
  13:    if (base.ManualAddressing)
  14:    {
  15:        throw new InvalidOperationException("Manual Addressing Not Supported");
  16:    }
  17:  
  18:    return new CustomChannelFactory<TChannel>(this, context); 
  19: }
  20:  
  21: public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
  22: {
  23:    if (typeof(TChannel) == typeof(IReplyChannel))
  24:    {
  25:        return (IChannelListener<TChannel>)(new CustomReplyChannelListener(this, context));
  26:    }
  27:  
  28:    if (typeof(TChannel) == typeof(IInputChannel))
  29:    {
  30:        return (IChannelListener<TChannel>)(new CustomInputChannelListener(this, context));
  31:    }
  32:  
  33:    throw new InvalidOperationException("Unsupported channel listener.");
  34: }

In the channel listener we must provide a way to accept a new channel to receive messages from clients. One importing that I notice is that at the server side it is important to implement assynchronous way to accept the channel but at the client side we can implement only the synchronous way to send messages (requests) to the server.

The OnAcceptChannel method can be called multiple times and in this case there would be several opened channels at the same time. This sample is based on the Null channel sample and in this case it would not make sense. This is wait a AutoResetEvent is used. The component requesting the second channel will block until the first component releases it or the operation expires.

If you are using multiple channels don’t forget to disconnect the event handlers on the close handler to prevent memory from leaking.

   1: protected override IReplyChannel OnAcceptChannel(TimeSpan timeout)
   2: {
   3:     if (base.State != CommunicationState.Opened)
   4:     {
   5:         throw new CommunicationObjectFaultedException(string.Format("The channel {0} is not opened", this.GetType().Name));
   6:     }
   7:  
   8:     if (currentChannel != null)
   9:     {
  10:         //Please revisit this as we must accept multiple channels.
  11:         waitChannel.WaitOne(int.MaxValue, true);
  12:  
  13:         lock (ThisLock)
  14:         {
  15:             // re-open channel
  16:             if (base.State == CommunicationState.Opened && currentChannel != null && currentChannel.State == CommunicationState.Closed)
  17:             {
  18:                 currentChannel = new CustomReplyChannel(this, localAddress);
  19:                 currentChannel.Closed += new EventHandler(OnCurrentChannelClosed);
  20:             }
  21:         }
  22:     }
  23:     else
  24:     {
  25:         lock (ThisLock)
  26:         {
  27:             // open channel at first time
  28:             currentChannel = new CustomReplyChannel(this, localAddress);
  29:             currentChannel.Closed += new EventHandler(OnCurrentChannelClosed);
  30:             int count = CustomListeners.Current.Add(filter, this);
  31:         }
  32:     }
  33:  
  34:     return currentChannel;
  35: }
  36:  
  37: protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
  38: {
  39:     this.OnAcceptChannel(timeout);
  40:     return new CompletedAsyncResult(callback, state);
  41: }
  42:  
  43: protected override IReplyChannel OnEndAcceptChannel(IAsyncResult result)
  44: {
  45:     CompletedAsyncResult.End(result);
  46:     return currentChannel;
  47: }

In the channel factory the logic to create the channel is here. It is also import to understand the rationale behind this. The client side is creating the channel and the server side is accepting it. As you can imagine the server can reject it and throw an exception.

   1: protected override TChannel OnCreateChannel(System.ServiceModel.EndpointAddress address, Uri via)
   2: {
   3:     if (!string.Equals(address.Uri.Scheme, this.element.Scheme, StringComparison.InvariantCultureIgnoreCase))
   4:     {
   5:         throw new ArgumentException(string.Format("The scheme {0} specified in address is not supported.", address.Uri.Scheme), "remoteAddress");
   6:     }
   7:  
   8:     if (typeof(TChannel) == typeof(IOutputChannel))
   9:     {
  10:         return (TChannel)(object)new CustomOutputChannel(this, address, via);
  11:     }
  12:     else if (typeof(TChannel) == typeof(IRequestChannel))
  13:     {
  14:         return (TChannel)(object)new CustomRequestChannel(this, address, via);
  15:     }
  16:     else
  17:     {
  18:         throw new InvalidOperationException("Can not create channel");
  19:     }
  20: }

In the next part we will take a look at how the channels actually work.

Have fun,

Pedro