Wednesday, April 28, 2010

Mvvm Resources

Here is a great list of Mvvm (Model, View, View-Model pattern) resources:

  1. Josh Smith's MSDN article on MVVM (Good introduction of Mvvm)
  2. Karl Schifflett's Begining to Explore WPF's MVVM and another validation demo, and one more, from Karl (good demo of validation and presentation of validation errors)
  3. Dan Crevier's Data-Model, View, View-Model series (nice explanation and demo of commands)
  4. Josh Smith's Using Tree View with Mvvm (and easy searching code)
  5. Josh Smith's Controlling focus from a view-model
  6. Josh Smith & Karl Schifflett Creating an Internationalised Wizard
  7. Karl Schifflett's BBQ Shack Demo Application (Excellent demo of what I would call a "marshalled" navigation strategy, and also Windows ALT-TAB style task switching).
  8. Another Josh Smith Article on Testing where the subject under test uses a Dispatch Timer.

Monday, April 19, 2010

Preventing IoC Configuration Chaos

After working with tightly coupled (read as "welded") existing code bases in many previous companies, when given a green fields opportunity, I want to ensure thorough use of IoC.  This is essential to allow automated testing. Automated testing is essential for efficient agile development.

The problem is, when you write a large system, that equates to a large config file.  Actually it will be an enormous config file.  This is unacceptable in my opinion for several reasons:

  1. Large XML / Config files are annoying to maintain, and easy to get wrong.
  2. There's no compile time checking and fast feedback for XML / Config files.
  3. Most of the time the config is static, no one will want to change it at runtime for a production system (excluding unit testing).
  4. The config is owned and stored in the app/web config but some of your DLL's are designed to be reused independently and whenever they are consumers need to find an example of config and copy and paste it.
Nasty.
So a good solution needs the following attributes:
  1. By default (with no consumer code or config) any individual DLL must own its own default config. If a consumer takes and consumes your DLL that's all they need.
  2. By default the IoC container must be preconfigured to return production instances.
  3. Any hard coded default must be override-able by config.
  4. It must be easy to trigger IoC container intitialisation on application startup.
  5. Ideally the consumer shouldn't have to maintain a list of DLL's to intitialise.
Here's some sample code that I have come up with that attempts to solves these with StructureMap.
The basic idea is that all interfaces and abstracts registered with IoC for the primary purpose of unit testing should be configured with code in a DLL specific "Startup" class.  Each Referenced assembly in the current AppDomain is "visited" using a psuedo-visitor pattern and its Startup class is located and executed.

Each assembly that contains IoC registrations that need to evaluated must be decorated with this custom attribute.

[assembly: AssemblyInitialization(typeof(MamalsStartup))]
This points to the startup class containing the code registrations. Here's an example of a Startup implementation:

public class MamalsStartup : IStartup
    {
        private readonly object syncRoot = new object();

        public bool IsInitialized { get; private set; }

        public void InitializeObjectFactory()
        {
            if (this.IsInitialized)
            {
                return;
            }

            lock (this.syncRoot)
            {
                if (this.IsInitialized)
                {
                    return;
                }

                var factory = ObjectFactory.Container;
                factory.Configure(config =>
                {
                    config.For<ICat>().Use<Cat>();
                    config.For<ICat>().Use<Cat>().Named("Felix").OnCreation(c => c.Name = "Felix");
                    config.For<IDog>().Use<Dog>();
                    config.For<IChapter>().Use<Chapter1>();
                });

                FrameworkInitialise.ObjectFactoryInitializeCompleted += this.OnObjectFactoryInitializeCompleted;
                this.IsInitialized = true;
            }
        }

        public void Shutdown()
        {
            // Trigger any shutdown / cleanup logic
        }

        private void OnObjectFactoryInitializeCompleted(object sender, System.EventArgs e)
        {
            // You can do any singleton registration here. Or any registrations that require other registrations have been completed.
            FrameworkInitialise.ObjectFactoryInitializeCompleted -= this.OnObjectFactoryInitializeCompleted;
        }
    }
Notice how I have made an event that fires once all IStartup.InitializeObjectFactory this is to allow complex registrations that require instances of standard objects or singletons to be available.  It also useful for kicking off any other intialisation that may be required.  There's also a ShutDown method, this is useful for tidying up any singleton registrations that implement IDisposable or other cleanup logic.

To trigger the whole process the consuming code only needs one line of code:


// Invoke Initialise to trigger the process of "visiting" all assemblies referenced and calling each assemblies
// startup class to configure the IoC container.
FrameworkInitialise.Initialise();

Here's the initialize method:

/// <summary>
        /// Initializes the AppDomain assemblies that have the <see cref="AssemblyInitializationAttribute"/>.
        /// </summary>
        public static void Initialize()
        {
            if (isInitialised)
            {
                return;
            }

            isInitialised = true;
            var current = AppDomain.CurrentDomain;
            current.AssemblyLoad += OnAssemblyLoad;
            current.ProcessExit += ProcessExit;

            var assemblies = (from assemblyName in Assembly.GetEntryAssembly().GetReferencedAssemblies()
                              where assemblyName.FullName.StartsWith(AssemblyPrefix, StringComparison.InvariantCultureIgnoreCase)
                              select Assembly.Load(assemblyName))
                             .AsParallel();

            var list = new Dictionary<int, AssemblyInitializationAttribute>();
            FindInitAttribute(assemblies, list);

            // Finding and accessing the AssemblyInitializationAttribute will instantiate it and its ctor will trigger that assembly's startup class.
            // By the time this point is reached all assemblies have had their Object Factories configured.
            var handler = ObjectFactoryInitializeCompleted;
            if (handler != null)
            {
                // Some Assemblies may be interested to be informed when all others have had their Object Factories configured.
                // This will allow them to perform any other intialisation code that requires dependent assemblies to be configured first.
                handler(null, EventArgs.Empty);
            }
        }

Sunday, April 11, 2010

WCF Callback aka Duplex

Resources:

In the code sample a IPC (inter-process communication) named pipe is used to communicate between client and service using a callback.  Named pipes are recommended for use when communication is only between processes on the same machine.  Here is a chart outlining selection of a binding from Soledad Pano's blog sourced from Juval Lowry's book Programming WCF Services.


There is only really two things to get right with WCF. One is configuration, and the other is serialisation of data.  Serialisation is a big topic on its own, but in my experience its best to make use of DTOs, and avoid the use of generics in DTOs.  DTO's are essentially specific objects created to transfer data from one place to another.  They only contain data properties.

Configuration:
Here is a sample WCF Server app.config. 

    1 <?xml version="1.0" encoding="utf-8" ?>
    2 <configuration>
    3   <system.web>
    4     <compilation debug="true" />
    5   </system.web>
    6 
    7   <system.serviceModel>
    8     <services>
    9       <service
   10           name="WCFCallbacks.MessageService"
   11           behaviorConfiguration="WCFCallbacks.MessageBehavior">
   12         <host>
   13           <baseAddresses>
   14             <add baseAddress = "net.pipe://myservice" />
   15           </baseAddresses>
   16         </host>
   17         <endpoint
   18             address =""
   19             binding="netNamedPipeBinding"
   20             contract="WCFCallbacks.IMessage">
   21           <identity>
   22             <dns value="localhost"/>
   23           </identity>
   24         </endpoint>
   25         <endpoint
   26             address="http://localhost:8001/myservice"
   27             binding="mexHttpBinding"
   28             contract="IMetadataExchange"/>
   29       </service>
   30     </services>
   31 
   32     <behaviors>
   33       <serviceBehaviors>
   34         <behavior name="WCFCallbacks.MessageBehavior">
   35           <serviceMetadata httpGetEnabled="False"/>
   36           <serviceDebug includeExceptionDetailInFaults="True" />
   37         </behavior>
   38       </serviceBehaviors>
   39     </behaviors>
   40   </system.serviceModel>
   41 </configuration>


Config settings can also be set using the SvcConfigEditor.exe from within Visual Studio.

Here's a sample Client Config file:

    1 <?xml version="1.0" encoding="utf-8" ?>
    2 <configuration>
    3 
    4     <system.serviceModel>
    5         <bindings>
    6             <netNamedPipeBinding>
    7                 <binding name="NetNamedPipeBinding_IMessage" closeTimeout="00:01:00"
    8                     openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    9                     transactionFlow="false" transferMode="Buffered"transactionProtocol="OleTransactions"
   10                     hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288"
   11                     maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536">
   12                     <readerQuotas maxDepth="32" maxStringContentLength="8192"maxArrayLength="16384"
   13                         maxBytesPerRead="4096" maxNameTableCharCount="16384" />
   14                     <security mode="Transport">
   15                         <transport protectionLevel="EncryptAndSign" />
   16                     </security>
   17                 </binding>
   18             </netNamedPipeBinding>
   19         </bindings>
   20         <client>
   21             <endpoint address="net.pipe://myservice/" binding="netNamedPipeBinding"
   22                 bindingConfiguration="NetNamedPipeBinding_IMessage"contract="MessageService.IMessage"
   23                 name="NetNamedPipeBinding_IMessage">
   24                 <identity>
   25                     <dns value="localhost" />
   26                 </identity>
   27             </endpoint>
   28         </client>
   29     </system.serviceModel>
   30 </configuration>

It is recommended to only use config files to configure a service that needs to be changed at runtime. If for example the service does not need designed to be changed at runtime, rather programmatically set the service properties.

Hosting:
Options include:
  • IIS
    The advantage of using IIS, is management of service life cycle, and starting up on first call etc.  Only Http(s) bindings can be used.
  • WAS
    The Windows Activation Service can host any WCF service using any binding and still has all the advantages of IIS's life time management.  The WAS feature is only available in Vista and above.
  • Self Hosting using the ServiceHost class.
    This gives the developer the ability to host within a Windows service, console, or any other application.  The ServiceHost class is not available in the Client framework; ie not available in Silverlight.

Consuming a service client side there may be more limitations based on client environment.  If hosting within a Silverlight application, only Http(s) bindings are available, and wsDualHttpBinding is unavailable meaning callbacks are not possible.