Introduction

The article AOP Container introduced an AOP model that enables any IoC container to have AOP capabilities
by configuration. As examples, the model was applied to MEF, Unity,
and Windsor Containers. In this article, I discuss how the AOP Container together with Unity Container
is used to add AOP capabilities to a WPF application.

Background

It is quite easy to add aspects to business objects using an AOP Container. You define aspect methods, configure them in the application configuration file to associate them
with business components, and use one of the customized AOP Containers to instantiate your business objects. The AOP Container attaches aspects to objects automatically
based on the configuration settings.

WPF (Windows Presentation Foundation) provides some very powerful features to improve UI development experience, i.e., data binding between data sources
and user controls, event processing between user actions and data sources. This powerfulness comes with dependencies and limits. In this article, I discuss
how the AOP Container is used to add AOP capabilities to a WPF application and how to address issues between WPF and the business object model based on the AOP Container.

Problem

In this article, we try to build a rather complicated application to demonstrate component design, aspect design, and configuration, and address issues related to WPF application.

As functional (business) requirements, this application displays employees based on the selection of a department. A user can also modify existing employees, add new employees,
or delete existing employees.

In addition to the above functional requirements, we also like the application to meet non-functional (system) requirements like logging and security checking. We also
like to have some flexibility to sort employees by different criteria from a business point of view, e.g., sorting by employee's last name, by employee's birth day, etc.

The application development involves common tasks like business component design, aspect design and configuration, and tasks specific to WPF application like data binding
and change notifications, etc.

Common Tasks

Common tasks are independent of an application type. They include business component design, aspect design, and configuration.

Business Components

The two business components, Employee and Department, are defined as follows. They are simple classes implementing the interfaces IEmployee
and IDepartment, respectively.

For Employee, there is a corresponding RepositoryEmployee component to contain a collection of objects of Employee.
For Department, there is a corresponding RepositoryDepartment component to contain a collection of objects of Department. They are defined as follows.

Note that the data set is passed in using the DataSource property of IRepository<T> for both RepositoryEmployee
and RepositoryDepartment. RepositoryEmployee uses data from DataTableEmployee of the data set while RepositoryDepartment
uses data from DataTableDepartment of the data set.

You can use either container or aopcontainer to create an object. The difference between them is that an object created
by aopcontainer may have aspects attached while an object created by container has no aspects.

Aspect Design

Aspects are cross-cutting concerns. For an AOP Container, an aspect is a method that takes an AspectContext type object as its first parameter
and an object[] type object as its second parameter and returns void.

You may design your aspects in a more general way to use them in various situations. You may also design your aspects for some particular situations.
For example, you can define your entering/exiting log aspects in a general way and put them in the class SharedConcerns as follows.

In the above code, the SecurityCheck method can only check WindowsPrincipal for security while SortEmployeeByLastname
and SortEmployeeByBirthday can only be used by a target of RepositoryEmployee.

Note: You may already have noticed that there is a static constructor in each of the classes SharedConcerns and AppConcerns.
Inside the static classes, each of the aspect methods defined in the classes is used to create an instance of Decoration which is then added
to a dictionary ConcernsContainer.runtimeAspects. The definition of ConcernsContainer is as follows.

The purpose of this Dictionary and the static constructors is to keep an inventory for all Decoration objects based on the aspect methods
defined in the application and make them accessible by the corresponding method names. It makes possible to configure aspects in the application configuration file
by specifying the corresponding method names.

Aspect Configuration

In the configuration file, you specify how aspects are associated with business components. Here are some examples to demonstrate how the aspects are configured.

First of all, you need to add a section <DynamicDecoratorAspect> in your configuration file. You also need to add an applicationPath key
to the <appSettings> to specify the physical path of the Web application. It is required for a Web application since a Web application path is different
from the execution program path. Then, inside <objectTemplates> of <DynamicDecoratorAspect>, you add individual elements.
For each element inside <objectTemplates>, the following attributes need to be specified:

type - target type

interface - interface returned

methods - names of target methods which will be attached to the aspects specified by predecoration and postdecoration

predecoration - preprocessing aspect

postdecoration - postprocessing aspect

Notes:

The names in the value of the methods attribute are comma separated. For example, "DetailsByLevel,get_EmployeeID".

The value of the predecoration attribute has two parts and is separated by a comma. The first part specifies the aspect name while the second part
specifies the assembly name in which the aspect is defined, for example, "SharedLib.SharedConcerns.EnterLog,SharedLib". If the second
part is not specified, it is assumed that the aspect is defined in the entry assembly, for example, "WpfApplication.AppConcerns.SecurityCheck".

The value of the postdecoration attribute has two parts and is separated by a comma. The first part specifies the aspect name while the second part
specifies the assembly name in which the aspect is defined. If the second part is not specified, it is assumed that the aspect is defined in the entry assembly.

WPF Application Tasks

Before we apply the above business object model to a WPF application, we need to address several issues. WPF has limits on the binding
source (Binding Sources Overview). One issue is that WPF binding fails to work with
interface proxies (see WPF binding to a Windsor proxied
component and NHibernate, PropertyChanged event, and WPF).
So, it fails to work with the AOP Container which is based on interface proxies. Another issue is that to provide change notifications, a binding source
must implement the INotifyPropertyChanged interface. Most types of business components do not implement this interface. Therefore, the business
object model developed above can not be used by a WPF application directly.

Intermediate Classes

To get around the above limits, intermediate classes are created to wrap our business objects. The intermediate classes should meet all the requirements
of a WPF data source while delegating all requests to the wrapped business objects. EmployeeProxy and DepartmentProxy are the intermediate
classes for business components Employee and Department, respectively, and are displayed as follows.

EmployeeProxy is a Proxy Pattern for Employee. It provides the same interface as the original business object empOrig
and delegates all calls to the corresponding methods of the original object. It also implements INotifyPropertyChanged so that whenever a property changes, the bound WPF control
will be notified. It also has a static public instance aopcontainer of type AOPContainer. The aopcontainer is used to create a new business
object in the default constructor. The default constructor is called by a bound WPF user control when adding a new entry from the user interface.

Instead of explicitly putting an OnPropertyChanged call in each of the property set methods, PostSharp can be used to inject the code in each
of the property set methods. I am not going to discuss it in detail here. However, the download AopContainerWpfWithPostSharp.zip uses PostSharp to inject
the call to the property set methods. You will need to install PostSharp to get it to work.

DepartmentProxy is a Proxy Pattern for Department, which provides the same interface as the original business object depOrig.
However, it doesn't implement the INotifyPropertyChanged interface, which means it will not send change notifications to the bound WPF user control.
It doesn't have a default constructor, which means the bound WPF user control will not be able to add a new entry from the user interface.

Now, we are ready to work on the WPF application.

Application Class

A few application wide setups/cleanups need to be addressed at the application level. Here is the code of the App class:

In App_Startup, first, we redirect the console output to a file. This way, the aspects EnterLog and ExitLog
will write logs to the file instead of the console. Then, we create a UnityContainer object and register a few types to it. An AOPUnityContainer object
is also created. Both the UnityContainer object and the AOPUnityContainer are assigned to the corresponding public static members, respectively,
and will be used in other places of the application. We also set the Parameters property of the SecurityCheck aspect to WindowsPrincipal
so that we can check security during the execution of the application.

The code in App_Exit does some cleanups.

Main Window

The Main Window is the GUI for the application. Its XAML code is listed as follows.

In the event handler Window_Loaded, an XML file employees.xml is loaded into the DataSetdsDB.
This XML file persists data for departments and employees and plays a database role for the application. Of course, you can use a real database and its tables
to persist data and load them into the DataSet.

Note that rpDepartment.RepList is a list of interface proxies, we need to convert it to a list of DepartmentProxy objects
and bind the list of DepartmentProxy to comboBox1. For the same reason, we have to convert rpEmployee.RepList
to a list of EmployeeProxy objects and bind the list of EmployeeProxy to dataGrid1. Note also that
a ObservableCollection<EmployeeProxy> is assigned to dataGrid1, which means notifications will be generated when items
get added to or removed from the collection.

The event handler comboBox1_SelectionChanged is executed when a department is selected. Then, the employees associated with the department are displayed.

The event handler button1_Click is executed when pressing the PropertyChanged button. The code toggles
the first employee's EmployeeID between 1 and 100. Note that ObjectProxyFactory.CreateProxy is called to add the security check before changing the EmployeeID.
The important point here is that you can chain aspects to object in the code no matter whether it is configured in the configuration file or not.
The best practice for this scenario is that since your application may have a lot of employees and an employee may have a lot of properties, it is better
to add aspects to an employee object using code as needed instead of configuring aspects to the employee component in the configuration file.

The event handler button2_Click is executed when pressing the CollectionChanged button. The code simply adds or removes
an employee from the employee collection with EmployeeID 1001.

The event handler button3_Click is executed when pressing the Save button. The code persists changes of employees to the "employees.xml" file.

Run the application, the MainWindow looks as follows:

When a department is selected, the employees for that department are displayed.

Close the application and open the file hrlog.txt. You will see the following logs:

Now, comment out the line Thread.GetDomain().SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); in App_Startup of the App class.
Build and run the application. When the MainWindow is up, click the PropertyChanged button, and you will see the following message:

You were not allowed to change the EmployeeID since you failed the security check.

As you may have noticed, the above application sorts the employee by the employee's last name. What if you want to sort employees by their birthday?
You change the configuration entry for WpfApplication.RepositoryEmployee by replacing WpfApplication.AppConcerns.SortEmployeeByLastname
with WpfApplication.AppConcerns.SortEmployeeByBirthday. That's it. Now, your application sorts employees by their birthday.

Points of Interest

AOP Container makes extending functionality of business components or adding AOP capabilities to them very easy. You define your aspect methods, and configure them
in the configuration file to associate aspects to business components.

You can also mix adding aspects using configuration and adding aspects using code. This way, you can use aspect configuration for general purpose while using
code to chain more aspects to meet your specific requirements as needed.

The Proxy Pattern is a neat way to apply the power of WPF to business objects based on interface interception technology.

Although this article discusses AOP container with Unity IoC container, you should be able to easily combine an AOP Container with other IoC containers like MEF and Windsor.

Mobile development is not just another type of front end. The real challenge is actually in the back end: How to present meaningful information in time to mobile users with exponentially increased data flooding around? Here is my first mobile solution: SmartBars - Barcode Reader, Price Comparison and Coupons.

Gary lives in southeast Michigan. My first programming language is FORTRAN. For the last a few years, I have primarily focused on .NET technologies with Mobile Development as my newest interest.