WPF Line of Business – Introduction

Click image to view full size in new window.

WPFLOBMVVM

Demo Application Solution Items

WPFLOBMVVMSolutionItems

Introduction

This is the introduction to a series of MVVM articles related to WPF Line of Business applications (LOB).

Please ensure that you have read the M-V-VM home page and Introduction to M-V-VM before proceeding.  That foundational information will not be repeated here.  (Introduction to M-V-VM will be published soon.)

This post is targeted to those that are new to MVVM or don’t have a full understanding of WPF LOB layers.  This post provides an introduction to the layers and their purpose and how they fit into the larger picture of an application.

The supplied demo application takes full advantage of the Ocean Framework and the Ocean Framework source code is part of the application.

Layers

The above diagram shows common layers found in WPF MVVM LOB applications.  The layers can be co-located on one computer or spread out across several computers.  Additionally the computers can be located behind a single firewall or across the Internet.

When looking at layers we are looking logical separation and not necessarily physical separation. 

The supplied demo application has all of the above layers and is contained within a single solution, including the database.  The above bottom image shows the physical separation provided by the individual projects.

Dividing an application into layers provides many benefits.  Different developers or teams can work on different parts of the application without stepping on each others work.  The layers provide a natural separation of concerns.  Layers reduce application dependencies that so often make them brittle and difficult to change without exerting major effort.  Application layers make it possible to swap out an entire layers without having to rewrite the entire application.  Layers provide a natural boundary for unit testing.  Layers give the best chance of code reuse when deploying applications to new UI technologies.

Programming in layers provides a built in sanity check during the design and development processes.  If you find yourself fighting to get your design to have a natural flow, take a step back, you are probably heading down the wrong path.  Layers will help keep your applications simple too.

Unit Test

The ability to easily unit test your WPF LOB applications is a major benefit.  ViewModel’s and underlying layers can easily be unit tested with the included Test features found in Visual Studio 2008 Professional and above.

It is universally accepted that software maintenance costs more over the lifetime of an application than development, specifications, requirements gathering or installation.

Having a solid suite of unit tests reduces regressions when application features are added or code fixes are made.  It also eases the pain when moving an application to a new operating system or version of the .NET Framework.

Unit test suites also make it very easy to test an application that features a high number of configuration settings or a complex configuration setting matrix.

This is one area that software companies can invest in with a guaranteed high and immediate ROI.  It will also make your customers very happy that they don’t feel like they are doing your testing for you.

The unit test layer is a project that is added to the solution.  This project consists of one or more classes that interact with your application by instantiating its classes, running methods, checking properties while validating actual results against expected results.  Visual Studio 2008 Professional makes it very easy to get application unit tests up and running. 

While not part of the above layers diagram, in addition to the test harness running tests against the ViewModels, it also runs unit tests directly against the Business Layer, Models and Data Layers.  The ensures wide and deep test coverage.

FYI:  The Test features of Visual Studio allow the testing of private methods and properties on classes.  The great feature is invaluable when you need to test code private code but don’t want to expose it as part of the public API.

View

The view layer is represented by the XAML files and the associated code behind files.  View files are typically  named by appending the word, “View” to the end of the file and class name.  ViewModel’s also follow this naming convention.

Each View has a corresponding ViewModel.  While a View can potentially be associated with more than one ViewModel, this is not the norm.

Views can be data templates, UserControls or Windows.  They can be instantiated by declaring them in a XAML file or by allowing the WPF Resource system to render them as part of a DataTemplate lookup based on DataType at run-time.

This example shows the ContactView instantiated in XAML.  Note its DataContext being assigned.

<local:ContactView x:Name="objContactView" Grid.Row="1" DataContext="{Binding ContactViewModel}" />

This example shows the ContactView being associated with the ContactViewModel.  This is an example of a WPF Resource lookup based on DataType.  ContactViewModel is the DataType, ContactView is the DataTemplate used to render the data.

<DataTemplate DataType="{x:Type local:ContactViewModel}">
    <local:ContactView />
</DataTemplate>

The ViewModel is typically the DataContext for the View.  Controls in the View, are data bound to properties on the corresponding ViewModel.  This data bound information includes Model data, ViewModel state and ICommands exposed by the ViewModel.

In addition to data transfer, the WPF data binding pipeline provides change notification.  This enables the smooth back and forth flow of information without having to write a lot of additional plumbing code.

Developers do need to implement the System.ComponentModel.INotifyProperyChanged interface on their ViewModels and if required on their Model entities.  This ensures that when property values change in the Model or ViewModel the View will be notified and the UI updated.

Looking at the above diagram, you can see that data binding and change notification has three potential scenarios.  A typical MVVM applications could have all three scenarios in play in the application, possibly in a single Model – View – ViewModel relationship.

The View generally has very little or no code in the associated code behind file.  I tend to shy away from a purest view that the View can not have any code in the code behind file.  If you need code in the code behind, then do it and don’t feel bad about it.

Here is an example from the demo application.  Check out the EditContactsAjaxComboBoxSelectionView.xaml.vb code behind file.

All of the code is associated with the AjaxStyleComboBox control that is included in the Ocean Framework.  This control does not have any exposed commands, so I needed to handle events raised by the control.  If you look close, all non-UI actions are delegated to the ViewModel.  All of these actions handled by the ViewModel are easily to unit test.  Don’t drive yourself crazy trying to put a square peg in a round hole.  Use code behind when required.

When programming requirements dictate, the View can call methods on the ViewModel since it has a reference to the ViewModel.  Remember, the ViewModel is the DataContext for the View, so a simple cast operation and the View has access as required without needing to inject the ViewModel into the View.

ViewModel

The ViewModel abstracts Model.  The ViewModel adapts the Model to the View.  It is the middle man and traffic cop.  It stores and manages state.  It has direct access to the Business Layer and Model objects commonly called business entity objects.  The ViewModel has no access to the Data Layer whatsoever.  In most applications, projects that contain the ViewModel do not have references to projects that contain the Data Layers. 

I like to program my MVVM applications so that the ViewModel has no knowledge of the View at all.  My ViewModels have properties that raise change notifications and some ViewModels have their own events the View can handle.  It is a fairly simple relationship to understand, program and maintain over time.

The ViewModel exposes public ICommand properties that act as targets for the View’s UIControls that act as CommandSources.  For example, a View may have a ToolbarButton that when clicked causes the ICommand it’s data bound to to execute.  This CommandSource data bound to an ICommand is a direct relationship that does not travel down the element tree like a RoutedCommand does.

A great benefit of using ICommands is the built-in CanExecute notification the WPF Command system provides.  This radically simplifies the programming required to enable and disable UIElements based on a condition or application state.

The ViewModel exposes ICommand properties for functions like saving or deleting a record, closing a TabItem or Window or executing other business functions required by the WPF LOB application.

Exposing application functionality in the form of ICommands has the added benefit of making unit testing very easy and straightforward.

The below code is an example of an ICommand that permits the user to view a blog in Internet Explorer.  The BlogNavigateExecute method is called when the BlogNaviateCommand is executed by the UI or test harness.  The CanBlogNavigateExecute method returns a Boolean indicating if the command is enabled or not.  The RelayCommand is covered in great detail in ICommand & RelayCommand article.

Public ReadOnly Property BlogNavigateCommand() As ICommand
    Get

        If _cmdBlogNavigateCommand Is Nothing Then
                _cmdBlogNavigateCommand = _
                    New RelayCommand(AddressOf BlogNavigateExecute, _
                                     AddressOf CanBlogNavigateExecute)
        End If

        Return _cmdBlogNavigateCommand
    End Get
End Property
Business Layer

The purpose of the Business Layer is to service requests from the ViewModels and other business objects.  This layer enforces business rules, performs calculations and forwards requests for data or data persistence to the Data Layer.

The business layer must be programmed defensively.  Do not make any assumptions about data coming from the UI layers.  Treat this data has an unknown hostile force, trying to break into your system.  This is especially important with respect to Silverlight applications that have a public facing.  Treat Silverlight applications just like you would an ASP.NET application.  A robust business layer also protects the application from bugs introduced in the UI layer code.

The below method is from the ContactBLL.vb file.  The very first task is to verify that the Contact has been validated.  If not an exception is thrown.  This is an example of defensive programming and ensures the UI developer has performed the required validation before passing the Contact class to the Business Layer.

Public Function Update(ByVal obj As Contact) As Integer

    If obj.HasBeenValidated Then
        Return ContactDAL.CreateInstance.Update(obj)

    Else
        Throw New InvalidOperationException("Contact has not yet been validated for update.")
    End If

End Function

Model

Model’s are also referred to as business entity objects.  Models provide an abstraction for the application data. 

If the Model is read-write then I always implement change notification and data validation.

Change notification is surfaced by implementing the System.ComponentModel.INotifyProperyChanged interface.  The data binding pipelines of WPF and Silverlight fully support working with this interface.

Data validation will be treated in a separate post.  For now, just know that your application needs data validation.  I like having my validation rules attached to the Model.  This way, was the Model moves between layers its validation rules move with it.

One of the reasons I wrote Ocean is because I needed a light weight validation engine that would work in ASP.NET, WPF, Silverlight, Winforms, console applications and class libraries.

Data validation functions are provided in the Ocean.OceanFramework.Validation namespace and data validation errors on a Model are surface through the System.ComponentModel.IDataErrorInfo interface.  Additionally the Ocean.OceanFramework.BusinessEntity.BusinessEntityBase class provides additional properties for getting data validation information.

IDataErrorInfo is recognized by WPF.  Unfortunately Silverlight has not integrated support for IDataErrorInfo into its data binding pipeline.  Perhaps in the future.  I have written my own Silverlight implementation for IDataErrorInfo and will release this soon.  This enables both WPF and Silverlight to consume the same exact business objects.

The below code snippet from the Contact class shows how easy the Ocean validation features make it to add validation to a Model property.  A natural reading of the attributes decorating the properties make it very clear what rules are applied and their parameters.

<CharacterCasingFormatting(CharacterCasing.ProperName)> _
<StringLengthValidator(1, 30)> _
Public Property LastName() As String
    Get
        Return _strLastName
    End Get
    Set(ByVal Value As String)
        MyBase.SetPropertyValue("LastName", _strLastName, Value)
    End Set
End Property

<CompareValueValidator(ComparisonType.GreaterThanEqual, 0, RequiredEntry.No)> _
Public Property NumberOfComputers() As Integer
    Get
        Return _intNumberOfComputers
    End Get
    Set(ByVal Value As Integer)
        MyBase.SetPropertyValue("NumberOfComputers", _intNumberOfComputers, Value)
    End Set
End Property

Note the last parameter of CompareValueValidator.  For all my attributes,  I chose not to use a Boolean property, instead I used an Enumeration.  This makes reading the attribute much easier and cleaner, no guessing what True or False applies to.

Special Note:  I got the idea to replace Boolean properties with Enumerations from reading Krzysztof Cwalina & Brad Abrams book, “Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition).”  I’ve studied both the first and second editions.  If you are writing any sort of reusable .NET framework libraries, I strongly recommend that you study this book, it will help and challenge you to be a better .NET developer.

Data Layer

The Data Layer provides services for executing data requests.  In the demo application the ContactDAL.vb file contains the entire Data Layer.

Like the Business Layer, the Data Layer must be programmed defensively for the same reasons given in the Business Layer section.

If multiple data stores need to be accessed in an application, the Data Layer provides the necessary code to meet this requirement.  In complex systems where some data is local, other data is remote, Data Layers are sometimes implemented using the abstract factory pattern.  This is once technique for shielding the implementation details from the rest of the application.

Data Layers normally rely on helper classes for making the actual calls to and from the data store. 

The below methods are from the ContactDAL.vb file.  You’ll the Update method validates the Contact before executing a data base operation.  The EntityLoader helper class does the object building, taking an ADO.NET DataReader and returning one of more Model objects.

The demo application uses a SQL Compact database.  This is the in-memory database that ships with Visual Studio 2008.  SQL CE does not support stored procedures.  I mention this because you’ll see method parameters like, “My.Resources.StoredProcedures.ContactSearchByLastName.”  This is a string stored as a resource.  This make data layer free of SQL statements and it has the feel of using stored procedures.  I learned this technique from  Steve Lasker,  the master of SQL CE and you can read his blog here.

Public Function SearchByLastName(ByVal strSearchString As String) As List(Of ContactSearchResult)

    Dim objSearchResultsEntityLoader As New EntityLoader(Of ContactSearchResult)(CONNECTION_STRING)
    Return objSearchResultsEntityLoader.LoadList( _
        My.Resources.StoredProcedures.ContactSearchByLastName, _
        CommandBehavior.CloseConnection Or CommandBehavior.SingleResult, _
        BuildSQLParameter("@SEARCHSTRING", SqlDbType.NVarChar, 30, strSearchString))
End Function

Public Function [Select](ByVal intId As Integer) As Contact
        Return _objEntityLoader.LoadOne( _
            My.Resources.StoredProcedures.ContactSelectById, _
            CommandBehavior.CloseConnection Or CommandBehavior.SingleResult Or CommandBehavior.SingleRow, _
            BuildSQLParameter("@ID", SqlDbType.Int, intId))
End Function

Public Function SelectAll() As ObservableCollection(Of Contact)
        Return _objEntityLoader.LoadObservableColleciton( _
            My.Resources.StoredProcedures.ContactSelectAll, _
            CommandBehavior.CloseConnection Or CommandBehavior.SingleResult)
End Function

Public Function Update(ByVal obj As Contact) As Integer

    If Not obj.HasBeenValidated Then
        Throw New InvalidOperationException("Contact has not yet been validated for update.")
    End If

    Dim da As New DataAccess(CONNECTION_STRING)
        Return da.ExecuteNonQuery( _
            My.Resources.StoredProcedures.ContactUpdate, _
            BuildSQLParameter("@ID", SqlDbType.Int, obj.Id), _
            BuildSQLParameter("@FIRSTNAME", SqlDbType.NVarChar, 30, obj.FirstName), _
            BuildSQLParameter("@LASTNAME", SqlDbType.NVarChar, 30, obj.LastName), _
            BuildSQLParameter("@BIRTHDAY", SqlDbType.DateTime, True, _
                              IIf(obj.Birthday.HasValue, obj.Birthday, DBNull.Value)), _
            BuildSQLParameter("@NUMBEROFCOMPUTERS", SqlDbType.Int, obj.NumberOfComputers), _
            BuildSQLParameter("@BLOGURL", SqlDbType.NVarChar, 100, obj.BlogURL), _
            BuildSQLParameter("@FEEDURL", SqlDbType.NVarChar, 100, obj.FeedURL), _
            BuildSQLParameter("@COMMENT", SqlDbType.NVarChar, 50, obj.Comment))
End Function

Layers and Code Generation

As you write the Data Layer, Business Layer, Models and ViewModels you being to see how code generation comes into play.  These layers are easy to generate if you have a metadata store to drive the process.  In the coming weeks, I’ll publish Ocean’s Code Generation piece to complete the Ocean story.  I will also publish in-depth articles on Ocean, Ocean Framework and code generation pieces.

Hope you have a great day!

Just a grain of sand on the worlds beaches.

6 Responses to WPF Line of Business – Introduction

  1. [...] written about business entity validation here and here.  Most of the content in this Code Project article are applicable to Ocean as they [...]

  2. [...] written about business entity validation here and here.  Most of the content in this Code Project article are applicable to Ocean as they [...]

  3. Hi Karl

    How can I download this sample demo ?

    Thanks in advance

    Edson Ferreira

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 245 other followers