# Monday, August 23, 2010

* Download Complete Source Code

In an attempt to be a Pragmatic Programmer I make an effort to learn a new programming language yearly.  This year the language of choice is Ruby, including Rails.  About a month ago I started the Build Your Own Blog :: Rails series at TekPub.  In this series Rob Conery instructs on creating a blog engine using Rails and focusing on Behavior Driven Development.  Rob introduces some amazing tools, such as Cucumber and Pickle, that make BDD on Rails easy and dare I say…fun!

If you have been following along at home with my previous serious of blog posts you know that in my day job I am currently architecting a large WPF MVVM composite application using Prism.  My development methodology for .Net development is TDD and not BDD, because I just don’t feel the tools are there yet in the .Net space for efficient BDD.  I am at the point in the project where I am starting work on the UI and being fresh of learning the wonderful BDD tools available in the Rails stack it was really annoying me that I had no way to TDD my UI.  Grant it, using MVVM I was able to get much closer to the actual UI than I otherwise would, but it still wasn’t the same.  Finally I got to the point where I just had to research the idea of Cucumber style testing in WPF.  What I found out was it is possible using IronRuby.  Don’t be mistaken, it does not offer the same ease and simplicity as it does on the Rails stack but it is certainly a leap in the right direction.

The tool that is going to make this all possible was written by Nathaniel Ritmeyer and is called Bewildr!

Here are the steps to getting your environment setup…

  1. Follow the steps in my previous blog post to get Ruby, IronRuby, and Cucumber installed. 
  2. Install Bewildr.
  3. Install UISpy.

I am going to be testing the UI created in my previous series: Rolling Your Own Module Level Security for a WPF MVVM Composite Application

Detailed information on Cucumber can be found here.  But, basically Cucumber allows you to write plain-text functional descriptions as automated tests.  Cucumber code consists of two main pieces; Features/Scenarios and Step Definitions.  This is not meant to be a Cucumber tutorial so if you are not familiar with Cucumber I would suggest reading up on it prior to continuing.

OK.  So, now that your familiar with Cucumber you are probably asking yourself how is this going to allow me to do automated UI testing?  This is where Bewildr enters the party.  Bewildr is a Ruby GEM that uses the MS UI Automation Framework to gain programmatic access to a WPF UI.  Basically, I can spin up a WPF application and manipulate the UI, click buttons, enter text in text boxes, etc, all via code.

So, let’s start with a simple scenario.  (I apologize for the formatting/highlighting…need to find a good formatter plug-in for Cucumber code.

  1. @application
  2. @window
  4. Feature: Application Interaction
  6.   Scenario: The Log On window should be displayed on application start
  7.     Given I ensure that there are no instances of "CompositeAppPoc.Shell.exe" running
  8.     When I start "C:\\development\\research\\wpf\\CompositeAppPoc\\CompositeAppPoc.Shell\\CompositeAppPoc.Shell\\bin\\Debug\\CompositeAppPoc.Shell.exe"
  9.     Then 1 window is displayed with name "Log On"
  10.       And Terminate the app

If we go ahead and run this feature Cucumber is going to puke on us because we haven’t created our steps yet.  But, when Cucumber pukes…it pukes in a helpful way.  It is going to give us the shell for the steps we need to create in order to execute this feature.


As you can see Cucumber lets us know that we need to define 4 steps in order to get our Feature and Scenario running.  So let’s do that.  Since 3 of the steps deal with the application itself and 1 deals specifically with a window I am going to create 2 step files.

  1. require 'bewildr'
  3. Given /^I ensure that there are no instances of "([^"]*)" running$/ do |app|
  4.   Bewildr::Application.kill_all_processes_with_name(app)
  5. end
  7. When /^I start "([^"]*)"$/ do |app|
  8.   @application = Bewildr::Application.start(app)
  9. end
  11. When /^Terminate the app$/ do
  12.   @application.kill
  13. end

  1. require 'bewildr'
  3. Then /^ (\d+) window is displayed with name "([^"]*)"$/ do |count,name|
  4.       @window = @application.wait_for_window(name)
  5.       @application.windows.size.should == count.to_i
  6.       @window.name.should match(name)
  7. end

In the steps coded above you can begin to see what Bewildr allows us to do.  Now if you run this feature you should see the output below as well as the app physically spinning up and closing.


And as you can see our scenario passed.

This is really just scratching the surface of what you can do.  I would suggest downloading the code and get an understanding of some of the more advanced scenarios and then start creating your own.

* Download Complete Source Code

posted on Monday, August 23, 2010 6:04:00 PM (Central Daylight Time, UTC-05:00)  #    Comments [138]
# Monday, August 16, 2010

Note: This expands on the code created in my previous post: Requiring Log-On in a WPF MVVM Composite Application

* Download Complete Source Code

Continuing on my WPF MVVM Adventures...  Well, I am still waiting on the business to finalize the requirements so I am going to take a shot at coding it to what I think the final specs will be.  Although this is a very common situation, when you take this slippery slope you need to be careful that you don’t end up creating throw away code.   Make sure you:

  1. Program to Interfaces. (FYI – you should be doing this anyway!)
  2. Add Abstraction layers that will allow you to swap out implementation. (See step 1)
  3. Keep all the possible solutions to the problem in mind when designing/coding.  In my case I am 99% certain the business will want security down to the composite module level, but I am still going to leave paths open that will allow me to implement field level security without too much re-work.

The first thing I need is to define by security roles.  Since the actual roles are TBD I am just going to create a simple Enumeration.

  1. namespace CompositeAppPoc.Infrastructure.Enumerations {
  3.     public enum AuthorizationLevel {
  4.         ReadOnly,
  5.         ReadWrite,
  6.         Admin
  7.     }
  8. }

In thinking about what the Authentication method of my yet to be created service will return I decided it was going to need to return multiple things.

  1. Boolean representing whether or not the credentials where able to be authenticated.
  2. Level of authorization granted to credentials.
  3. List of modules that credentials are able to view.

Knowing I was going to need to return multiple values I created a data transfer object (DTO) to handle it.

  1. using System.Collections.Generic;
  2. using CompositeAppPoc.Infrastructure.Enumerations;
  4. namespace CompositeAppPoc.Infrastructure.DataTransferObjects {
  6.     public class AuthenticationContext {
  8.         public bool IsAuthorized { get; set; }
  10.         public AuthorizationLevel AuthLevel { get; set; }
  12.         public IList<string> AllowedModules { get; set; }
  14.     }
  15. }

Now I can create my service.  This is going to reside in my Infrastructure project and will allow me to push(abstract) the implementation of the actual authentication farther down the stack.  Sticking to what I recommended at the beginning of this post I am going to create a simple interface for the service.  The interface will declare one signature, Authenticate, that accepts a username and password and returns an AuthenticationContext.

  1. using CompositeAppPoc.Infrastructure.DataTransferObjects;
  3. namespace CompositeAppPoc.Infrastructure.Interfaces {
  5.     public interface IAuthenticationService {
  6.         AuthenticationContext Authenticate(string userName, string password);
  7.     }
  8. }

Next we need to code the actual implementation of IAuthenticationService.  At this time the implementation of Authenticate will need to perform the actual authentication, which will set the IsAuthorized flag as well as the AuthLevel, and determine what modules are viewable for the AuthLevel.  Because I still have not defined the details of these process I am going to “stub” them out with a trivial implementation.

  1. using System.Collections.Generic;
  2. using CompositeAppPoc.Infrastructure.Constants;
  3. using CompositeAppPoc.Infrastructure.DataTransferObjects;
  4. using CompositeAppPoc.Infrastructure.Enumerations;
  5. using CompositeAppPoc.Infrastructure.Interfaces;
  7. namespace CompositeAppPoc.Infrastructure.Services {
  9.     public class AuthenticationService : IAuthenticationService {
  11.         private readonly AuthenticationContext _authenticationContext = new AuthenticationContext();
  13.         public AuthenticationContext Authenticate(string userName, string password) {
  14.             Authorize(userName, password);
  15.             if (_authenticationContext.IsAuthorized) {
  16.                 GetApprovedModules();
  17.             }
  18.             return _authenticationContext;
  19.         }
  21.         private void Authorize(string userName, string password) {
  22.             if (userName.Equals("admin") && password.Equals("pass")) {
  23.                 _authenticationContext.IsAuthorized = true;
  24.                 _authenticationContext.AuthLevel = AuthorizationLevel.Admin;
  25.             }
  26.             else if (userName.Equals("readwrite") && password.Equals("pass")) {
  27.                 _authenticationContext.IsAuthorized = true;
  28.                 _authenticationContext.AuthLevel = AuthorizationLevel.ReadWrite;
  29.             }
  30.             else if (userName.Equals("readonly") && password.Equals("pass")) {
  31.                 _authenticationContext.IsAuthorized = true;
  32.                 _authenticationContext.AuthLevel = AuthorizationLevel.ReadOnly;
  33.             }
  34.         }
  36.         private void GetApprovedModules() {
  37.             IList<string> modules = new List<string>();
  38.             switch (_authenticationContext.AuthLevel) {
  39.                 case AuthorizationLevel.Admin:
  40.                     modules.Add(EmployeeConstants.EmployeeEditModuleName);
  41.                     modules.Add(EmployeeConstants.EmployeeCreateModuleName);
  42.                     break;
  43.                 case AuthorizationLevel.ReadWrite:
  44.                     modules.Add(EmployeeConstants.EmployeeCreateModuleName);
  45.                     break;
  46.             }
  47.             _authenticationContext.AllowedModules = modules;
  48.         }
  49.     }
  50. }

Now we need to hop over the Shell project and start making adding in the hooks for our module level security.

This first I am going to do is change how the modules are loaded.  Initially I used the ConfigurationModuleCatalog which loads the modules from a configuration file.  I decided against this approach because I wanted to avoid configuration changes when a module was added or removed.  Luckily Prism provides another option called the DirectoryModuleCatalog.  This allows you to supply a directory path that contains the dll’s for your modules.  So, all that needs to be done in order to add a new module is to drop its dll’s in that directory.  This change needs to implemented in the bootstrapper and while we are in there we need to tell our IOC container how to wire up our AuthenticationService.

  1. using System.Windows;
  2. using CompositeAppPoc.Infrastructure.Interfaces;
  3. using CompositeAppPoc.Infrastructure.Services;
  4. using Microsoft.Practices.Composite.Modularity;
  5. using Microsoft.Practices.Composite.UnityExtensions;
  6. using Microsoft.Practices.Unity;
  8. namespace CompositeAppPoc.Shell {
  10.     public class Bootstrapper : UnityBootstrapper {
  12.         protected override DependencyObject CreateShell() {
  13.             Shell shell = new Shell();
  14.             shell.Show();
  15.             return shell;
  16.         }
  18.         protected override IModuleCatalog GetModuleCatalog() {
  19.             return new DirectoryModuleCatalog() {ModulePath=Infrastructure.Constants.GeneralConstants.ModulePath};
  20.         }
  22.         protected override void ConfigureContainer() {
  23.             base.ConfigureContainer();
  24.             Container.RegisterType<IAuthenticationService, AuthenticationService>(new ContainerControlledLifetimeManager());
  25.             Container.RegisterType<IEmployeeDataService, EmployeeDataService>(new ContainerControlledLifetimeManager());
  26.             Container.RegisterType<IModuleManager, ModuleManager>(new ContainerControlledLifetimeManager());
  27.         }
  28.     }
  29. }

So now that we did that we can more easily add new modules but it’s still all or nothing.  We need to tell Prism to not load certain modules until we tell it to…load on demand.  This is accomplished by simply by decorating the modules you want to load on demand with the Module attribute and setting the ModuleName and OnDemand properties.  As you can guess we are going to set the OnDemand property to “True”.  This tells Prism, when it is processing the modules in the directory we tell it, not to load the module just yet.  Prism notes the name of the module and waits for us to tell it when to load it.  We will do this on the EmployeeEditModule, and EmployeeCreateModule which will both require authorization but we will not do this to the EmployeeListModule because that module is viewable by all.

  1. [Module(ModuleName=EmployeeConstants.EmployeeEditModuleName, OnDemand=true)]
  2. public class EmployeeEditModule : IModule {

  1. [Module(ModuleName=EmployeeConstants.EmployeeCreateModuleName, OnDemand=true)]
  2. public class EmployeeCreateModule : IModule {

Now when you run the the shell you won’t be able to edit or create a new employee because those modules are not loaded which means that nothing is registered to the associated commands.

We already have the list of allowed secured modules being returned from the authentication service so we just need to write a method to process the list and load the modules.  This method will be in the Bootstrapper and it will load the allowed secured modules using the Module Manager.

  1. public void LoadSecuredModules(IList<string> allowedModules) {
  2.     var moduleManager = Container.Resolve<IModuleManager>();
  3.     foreach (string module in allowedModules) {
  4.         moduleManager.LoadModule(module);
  5.     }
  6. }

Lastly we need to call LoadSecuredModules.  We will do this as the last step in the App.xaml’s StartUp method.

  1. private static void StartUp(IList<string> allowedModules) {
  2.     Current.MainWindow = null;
  3.     Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
  4.     var bs = new Bootstrapper();
  5.     bs.Run();
  6.     bs.LoadSecuredModules(allowedModules);
  7. }

Now when we log in with a read-only id (readonly,pass) the edit and create new buttons are not enabled because the modules are not loaded.


* Download Complete Source Code

posted on Monday, August 16, 2010 5:40:00 PM (Central Daylight Time, UTC-05:00)  #    Comments [39]
# Friday, August 13, 2010

In doing some research I found that it is possible to do Rails type BDD/testing in WPF using IronRuby.  I am very excited about this and will be doing an in-depth post on this in the very near future.  But, for now I wanted to get a post out on how to get Cucumber up and running in IronRuby because in attempting to do this myself I ran into an issue that turns out is fairly well-known but as far as I can tell is not documented.  I would like to thank Nathaniel Ritmeyer, aka NatOnTesting, for helping me through this and take a look at his Bewildr gem…it will be a key piece of my future post.

Here are the steps for getting Cucumber up and running with IronRuby:

  1. Install Ruby (to save headaches install to c:\ruby and make sure “c:\ruby\bin” is in your Path environment variable)
  2. Install IronRuby (to save headaches install to c:\ironruby and make sure “c:\ironruby\bin” is in your Path environment variable)
  3. Install Cucumber (here is the undocumented part…until now)
    1. Because Gherkin is required by Cucumber version > 0.6.3 and Gherkin is not compatible with IronRuby we need to install Cucumber version <= 0.6.3.
    2. image
  4. Next you need to create a Cucumber wrapper script for IronRuby
    1. Go to c:\ruby\bin
    2. Create a blank text file “icucumber.bat”
    3. Open icucumber.bat in text editor
    4. Enter this text
      1. @ECHO OFF
        SET GEM_PATH=c:\ruby\lib\ruby\gems\1.9.1
        @"C:\IronRuby\bin\ir.exe" "c:\Ruby\bin\cucumber" %*

    5. Save the file
  5. Test it (results are truncated)


That’s it.  You now have Cucumber running with IronRuby.  Why is this helpful?  Stay Tuned!

posted on Friday, August 13, 2010 5:00:00 PM (Central Daylight Time, UTC-05:00)  #    Comments [6]
# Monday, August 09, 2010

Note: This expands on the code created in my previous post: Implementing Attribute Based Domain Validation In a WPF MVVM Application

* Download Complete Source Code

Continuing on my WPF MVVM Adventures... My next task was to implement security on my composite application.  Unfortunately, as is all to often the case, there where still business decisions to be made concerning the granularity of the security {is field level required} and also the source of record {LDAP, roll-our-own}.  Not wanting to loose focus on the security piece and knowing I couldn’t sit around and do nothing I decided to tackle the one piece I knew that was constant…I was going to need a UI for logging in a user.

I started this process by creating a simple/standard log on window.

image  image 

  1. <Window x:Class="CompositeAppPoc.Shell.LogOn"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         Title="Log On" SizeToContent="WidthAndHeight"
  5.         WindowStartupLocation="CenterScreen" WindowStyle="None"
  6.         ResizeMode="NoResize" MinWidth="300" BorderThickness="4" AllowsTransparency="True">
  8.     <Window.Resources>
  9.         <Style TargetType="TextBox">
  10.             <Setter Property="Margin" Value="4"/>
  11.             <Setter Property="MinWidth" Value="100"/>
  12.         </Style>
  13.         <Style TargetType="PasswordBox">
  14.             <Setter Property="Margin" Value="4"/>
  15.             <Setter Property="MinWidth" Value="100"/>
  16.         </Style>
  17.         <Style TargetType="Button">
  18.             <Setter Property="Margin" Value="4"/>
  19.             <Setter Property="MinWidth" Value="75"/>
  20.         </Style>
  21.     </Window.Resources>
  23.     <Grid>
  24.         <Grid.ColumnDefinitions>
  25.             <ColumnDefinition Width="Auto"/>
  26.             <ColumnDefinition/>
  27.         </Grid.ColumnDefinitions>
  28.         <Grid.RowDefinitions>
  29.             <RowDefinition Height="Auto"/>
  30.             <RowDefinition Height="Auto"/>
  31.             <RowDefinition Height="Auto"/>
  32.             <RowDefinition Height="Auto"/>
  33.             <RowDefinition/>
  34.         </Grid.RowDefinitions>
  35.         <!-- Header -->
  36.         <StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2">
  37.             <Label HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
  38.                    FontWeight="Bold" FontSize="16" Content="Log On">
  39.             </Label>
  40.         </StackPanel>
  41.         <!-- Main Controls -->
  42.         <Label Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" Content="User Name"/>
  43.         <TextBox Grid.Column="1" Grid.Row="1" GotFocus="CredentialsFocussed" x:Name="txtUsername"/>
  44.         <Label Grid.Column="0" Grid.Row="2" HorizontalAlignment="Right" Content="Password"/>
  45.         <PasswordBox Grid.Column="1" Grid.Row="2" GotFocus="CredentialsFocussed" x:Name="txtPassword" />
  46.         <Label Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" HorizontalAlignment="Center" Foreground="Red" FontStyle="Italic" Visibility="{Binding ShowInvalidCredentials}" Content="*Invalid User Name and/or Password"/>
  47.         <StackPanel Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="2" Orientation="Horizontal" VerticalAlignment="Bottom" Margin="5" HorizontalAlignment="Right" Height="Auto">
  48.             <Button Content="Log-on" Click="LogonClick" IsDefault="True"/>
  49.             <Button Content="Cancel" IsCancel="True"/>
  50.         </StackPanel>
  52.     </Grid>
  54. </Window>

  1. using System.ComponentModel;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Windows.Controls.Primitives;
  6. namespace CompositeAppPoc.Shell {
  8.     public partial class LogOn : Window, INotifyPropertyChanged {
  10.         #region Private Fields
  12.         private int _attempts;
  14.         #endregion
  16.         #region Public Properties
  18.         public int Attempts {
  19.             get { return _attempts; }
  20.             set {
  21.                 if (value != _attempts) {
  22.                     _attempts = value;
  23.                     OnPropertyChanged("Attempts");
  24.                 }
  25.             }
  26.         }
  28.         public Visibility ShowInvalidCredentials {
  29.             get {
  30.                 if (_attempts > 0) {
  31.                     return Visibility.Visible;
  32.                 }
  33.                 return Visibility.Hidden;
  34.             }
  35.         }
  37.         public string UserName {
  38.             get { return txtUsername.Text; }
  39.         }
  41.         public string Password {
  42.             get { return txtPassword.Password; }
  43.         }
  45.         #endregion
  47.         public LogOn() : this(string.Empty,string.Empty) {}
  49.         public LogOn(string userName, string password) {
  50.             InitializeComponent();
  51.             DataContext = this;
  52.             txtUsername.Focus();
  53.             txtUsername.Text = userName;
  54.             txtPassword.Password = password;
  55.         }
  57.         #region INotifyPropertyChanged Members
  59.         public event PropertyChangedEventHandler PropertyChanged {
  60.             add { PropertyChangedEvent += value; }
  61.             remove { PropertyChangedEvent -= value; }
  62.         }
  64.         #endregion
  66.         private void LogonClick(object sender, RoutedEventArgs e) {
  67.             DialogResult = true;
  68.             Close();
  69.         }
  71.         private void CredentialsFocussed(object sender, RoutedEventArgs e) {
  72.             TextBoxBase tb = sender as TextBoxBase;
  73.             if (tb == null) {
  74.                 PasswordBox pwb = sender as PasswordBox;
  75.                 pwb.SelectAll();
  76.             }
  77.             else {
  78.                 tb.SelectAll();
  79.             }
  80.         }
  82.         private event PropertyChangedEventHandler PropertyChangedEvent;
  84.         protected void OnPropertyChanged(string prop) {
  85.             if (PropertyChangedEvent != null)
  86.                 PropertyChangedEvent(this, new PropertyChangedEventArgs(prop));
  87.         }
  88.     }
  89. }

Now I have my Log On window but it doesn’t do anything.  I need to tell my application to show that window first.  Your first thought would be to go into the project properties and set LogOn as the startup object, but once you got in there you would notice that there is currently no startup object defined and this is by design.  Currently, because we are working with a composite application, all of that is handles by our Bootstrapper which is kicked off from App.xaml in the OnStartUp event.

App.xaml.cs (Old)
  1. using System.Windows;
  3. namespace CompositeAppPoc.Shell {
  5.     public partial class App : Application {
  7.         protected override void OnStartup(StartupEventArgs e) {
  8.             base.OnStartup(e);
  9.             new Bootstrapper().Run();
  10.         }
  12.     }
  13. }

We need to modify App.xaml.cs to:

  1. Show LogOn dialog
  2. Process result from LogOn dialog
    1. If ‘Cancel’ is clicked then close the application
    2. If ‘OK’ is clicked
      1. Perform authorization
        1. If authorized
          1. Run the bootstrapper
        2. If not authorized
          1. If exceeded the number of allowed attempts close the application
          2. Else…add 1 to the attempts, store username and password, and re-show the LogOn
App.xaml.cs (New)
  1. using System.Collections.Generic;
  2. using System.Windows;
  3. using CompositeAppPoc.Infrastructure.Entities;
  4. using CompositeAppPoc.Infrastructure.Services;
  6. namespace CompositeAppPoc.Shell {
  8.     public partial class App : Application {
  10.         #region Private Fields
  12.         private readonly AuthenticationService _authenticationService = new AuthenticationService();
  13.         private int _attempts;
  14.         private string _userName = "";
  15.         private string _pass = "";
  17.         #endregion
  19.         #region Private Methods
  21.         private void ShowLogOn() {
  22.             var logon = new LogOn(_userName,_pass);
  23.             logon.Attempts = _attempts;
  24.             bool? res = logon.ShowDialog();
  25.             if (!res ?? true) {
  26.                 Shutdown(1);
  27.             }
  28.             else {
  29.                 AuthenticationContext ac = _authenticationService.Authenticate(logon.UserName, logon.Password);
  30.                 if (ac.IsAuthorized) {
  31.                     StartUp(ac.AllowedModules);
  32.                 }
  33.                 else {
  34.                     if (logon.Attempts > 2) {
  35.                         MessageBox.Show("Application is exiting due to invalid credentials", "Application Exit", MessageBoxButton.OK, MessageBoxImage.Error);
  36.                         Shutdown(1);
  37.                     }
  38.                     else {
  39.                         _attempts += 1;
  40.                         _userName = logon.UserName;
  41.                         _pass = logon.Password;
  42.                         ShowLogOn();
  43.                     }
  44.                 }
  45.             }
  46.         }
  48.         private static void StartUp(IList<string> allowedModules) {
  49.             Current.MainWindow = null;
  50.             Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
  51.             var bs = new Bootstrapper();
  52.             bs.Run();
  53.             bs.LoadSecuredModules(allowedModules);
  54.         }
  56.         #endregion
  58.         #region Public Methods
  61.         public App() {
  62.             Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
  63.             ShowLogOn();
  64.         }
  66.         #endregion
  67.     }
  68. }

That’s it, now we are requiring logging in to our application.  You may notice that there are bits in there that we haven’t covered yet, AuthenticationContext etc., this was me planning for the actual authentication implementation and can be replaced with whatever code you need.

Stay tuned for the actual security implementation.

* Download Complete Source Code

posted on Monday, August 09, 2010 4:02:00 PM (Central Daylight Time, UTC-05:00)  #    Comments [2]
# Thursday, July 29, 2010

Note: This expands on the code created in my previous post: WPF MVVM Multi-Solution Composite App


* Download Complete Source Code

Continuing on my WPF MVVM Adventures... My next task was to architect and code a validation framework that would:

  1. Adhere to the DRY principle.
  2. Allow me to define all validation in my domain objects.
  3. Allow me to easily relay validation issues to the UI/users.
  4. Allow me to easily add/modify validation rules.
  5. Not be *too* complex :)

Not wanting to re-invent the wheel I did some Googling, on Bing of course.  The first post that caught my eye was by Karl Shifflett, whom to me is one of the Grandfathers of WPF, and despite being a VB guy, usually has the answer.  So I read Karl’s article, downloaded the code and did some investigating.  The code would get the job done, but it wasn’t DRY.  Basically every field that was required had a check for not null and not empty, all validation code was done in the IDataErrorInfo’s Item override,  and even Karl himself recommends not doing it this way, and that you should use Ocean or another validation framework.  Not to discredit Karl, and I certainly recommend reading not only this post but all of Karl’s posts, but this didn’t fill all of my requirements.  Also, I am the type of developer who won’t use a framework for something I can code myself with out too much effort.

The next post that looked promising was by Josh Smith, whose Advanced MVVM book is a must read for anyone using MVVM.  Josh’s approach is nearly identical to Karl’s in that the base of the validation logic is repeated for every field.  Josh’s example also allows for further validation to be done at the ViewModel level, and this confuses me a little, in that the domain object itself should be the *gatekeeper* of valid object state.

So, having read these two posts from two of the more prominent WPF developers, and not finding what I wanted worried me.  Maybe I am totally missing something or what I want is flawed.  But hey, that’s why I blog…if I’m wrong call me out…and tell me why.

I started throwing some designs and thoughts down on paper and kept coming back to using attributes on the properties of domain objects.  Now, I am by no means a developer that pushes or even prefers attribute based solutions, but in this case it seemed to fit.

I knew that I was going to need an Interface or Abstract Base Class that would allow me to generically process the validators and always know what I was dealing with.  In this case I decided to go with an abstract base class just so I could have it inherit from Attribute and only require my instances of Validator to inherit a single class.  As you can see below the base class is very simple, it inherits Attribute and declares an abstract Validate method.  The other thing you’ll notice is that I decided to decorate the base class with the Attribute configuration.  This may change in the future, i.e. in some instances I may want to allow multiple of the same validator…say, if each is configurable.

  1: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, 
  2:      AllowMultiple = false, Inherited = true)]
  3:  public abstract class ValidatorBase : Attribute {
  4:      public abstract string Validate(object value);
  5:  }

Now I need a validator.  Let’s start simple with a standard required field validator.  I created my class, made it inherit from ValidatorBase and coded the Validate override.

  1: public class ValidRequiredField : ValidatorBase {
  3:     private const string _INVALID_REQUIRED_FIELD = "Required Field";
  5:     public override string Validate(object value) {
  6:         try {
  7:              if (value == null || string.IsNullOrEmpty(value.ToString()))
  8:                  return _INVALID_REQUIRED_FIELD;
  9:         }
 10:         catch (NullReferenceException) {
 11:             return _INVALID_REQUIRED_FIELD;
 12:         }
 13:         return null; 
 14:     }
 15: }

The next step is decorate the properties in the domain entity with any validation attributes.  In this case I am decorating the LastName property with the ValidRequiredField attribute.

  1: [ValidRequiredField]
  2: public string LastName {
  3:     get { return _lastName; }
  4:     set {
  5:         if (_lastName != value) {
  6:             _lastName = value;
  7:             OnPropertyChanged("LastName");
  8:         }
  9:     }
 10: }

OK.  Cool.  Unfortunately, this by itself does nothing.  We have to kick off the validation and put in the processes that allow the ViewModel and UI to receive notification of validation issues.  We will start this process by creating an abstract base class that our domain entities will inherit from.  This abstract base class will implement INotifyPropertyChanged, and IDataErrorInfo.  I am sure we are all familiar with INotifyPropertyChanged so I am not going to go into detail on what needs to be done to implement that interface. 

IDataErrorInfo is what is going to allow us to fire off our validation and communicate any issues to the ViewModel and UI.  First we are going to create a Validate function that will accept a string parameter that represents the property name.  The function will verity that the passed in property name is valid and that a property with said name exists on the domain entity.  If the property exists, its value is retrieved.  The property is then interrogated for attributes of type ValidatorBase.  If/When one is found the validation logic is performed on that property.  A the validation of the property returns something other than null that means the property is invalid and a string containing details of the validation issue is returned.  If no validation issue is found on the current attribute then the next attribute is checked and the process continues until we are out of attributes or a validation issue is found.

  1: public string Validate(string propertyName) {
  2:     string result = null;
  3:     PropertyInfo prop = GetType().GetProperty(propertyName);
  4:     if (prop != null && !prop.Name.Equals("item", StringComparison.InvariantCultureIgnoreCase)) {
  5:         object value = prop.GetValue(this, null);
  6:         var attributes = (ValidatorBase[])prop.GetCustomAttributes(typeof(ValidatorBase), false);
  7:         foreach (ValidatorBase attribute in attributes) {
  8:             result = attribute.Validate(value);
  9:             if (result != null)
 10:                 return result;
 11:             }
 12:             return result;
 13:         }
 14:         return result;
 15:     }
 16: }

Next we will implement the contract for IDataErrorInfo.  This contract requires us to implement two properties, even know WPF only uses one of them.  The Item property is an enumerator for the collection of strings representing errors.  In the getter of this property we will return the results of calling our Validate function with the supplied property name.  This will later be hooked up in a round about way to the View via the ViewModel.

  1: public string this[string propertyName] {
  2:     get { return Validate(propertyName); }
  3: }
  5: //Note: WPF does not use this function.
  6: public string Error {
  7:     get { return null; }
  8: }

This completes the plumbing for our validation framework.  There are an abundant number of blogs post on how to consume the IDataErrorInfo details in your views.  Beth Massi has done an excellent one which you can find here.

So, in wrapping up I feel like I have completed a validation framework that satisfies my goals.  Hopefully you will find it adaptable to your situation.

* Download Complete Source Code

posted on Thursday, July 29, 2010 11:00:00 PM (Central Daylight Time, UTC-05:00)  #    Comments [17]