August 2011

Volume 26 Number 08

Multi-Platform Development - Portable Class Libraries: A Primer

By Bill Kratochvil | August 2011

A Portable Class Library (PCL)project will generate a managed assembly that can be referenced by Windows Phone 7, Silverlight, the Microsoft .NET Framework and Xbox 360 platforms. This can maximize reuse of your code and reduce the number of required projects, particularly in multi-targeted applications that share the same codebase, as is the case of the demo application that accompanies this article. I invested time in writing a Windows Phone 7 application for this article, and the WPF/Silverlight applications came for free. The only constraint is that the PCL can’t reference platform-specific projects; it can only reference other PCL projects. On the surface this can appear limiting, especially for applications that utilize Prism and dependency injection (DI). But with careful planning, you can work around this constraint and create efficient PCL projects that will help enforce good development practices.

Prior to PCL projects, solution projects could only reference assemblies of the same platform. Silverlight projects referenced other Silverlight assemblies, .NET projects other .NET assemblies and so on. To code effectively, we could accumulate an unmanageable number of projects; when creating shared codebases (code that can be used across all platforms), we’d have to create a project for each platform.

A Multi-Targeted Password Manager Solution

The Password Manager solution (passwordmgr.codeplex.com) is a multi-targeted application with a single codebase (hosted by the Windows Phone 7 projects with the Silverlight and WPF projects linking to the Phone project files). As you can see, this small application has a daunting number of projects.

Why so many projects? That’s a popular question that I often hear from developers as I architect frameworks for client solutions. A typical refrain is, “They make the solution confusing and difficult to understand,” which is a good argument.

My answer is always: “To have a clear separation of concerns and to maximize reuse.” Each project should have one purpose (and do it well in a loosely coupled manner). As a case in point, note the apparent separation available in the PasswordMgr solution and the ability to easily substitute a different data access layer (DAL) using DI. Nevertheless, you’d be forced to pull in the SQLite assemblies and associated projects to reuse this code, even if you didn’t plan on using SQLite (perhaps you’d be using SQL Server for your DAL).

Once you reference another project, your project can become tightly coupled, forcing you to drag not only it, but also any dependencies it has, to the other projects. If you only have a few projects, it makes it increasingly more difficult to reuse the code in other solutions.

A PCL can significantly reduce the number of projects you have to manage, particularly if you want to have a clear separation of concerns permitting you to easily reuse your projects in other modules or solutions. The key is to keep your projects loosely coupled by programming against interfaces. This will permit you to use DI frameworks, such as the Managed Extensibility Framework (MEF) and Unity, which allow you to easily configure the implementation for the interfaces. That is, the DAL implementation for interfaces could be SQL Server, the cloud or SQLite classes.

Once you install the prerequisites (as outlined in the MSDN documentation at bit.ly/fxatk0), you’ll have a new feature under “Add New Project” to create a PCL.

Using DI Frameworks

A question that will quickly arise as you attempt to use these powerful DI frameworks is, “How do I use the PCL with these frameworks if I can’t reference the DI framework components—that is, the [Dependency] or [Export] attributes?” For example, the SecurityViewModel in the following code has a Unity [Dependency] attribute, which will resolve the implementation of the ISecurityViewModel:

namespace MsdnDemo.MvpVmViewModels

{

  public class SecurityViewModel : PresentationViewModelBase

  {

    [Dependency]

    public ISecurityViewModel UserInfo { get; set; }



    public bool IsAuthenticated

    {

      get { return UserInfo.IsAuthenticated; }

      set

      {

        UserInfo.IsAuthenticated = value;

        OnPropertyChanged("IsAuthenticated");



        if(value)

        {

          IsAdmin = UserInfo.IsInRole("Admin");

          IsGuest = UserInfo.IsInRole("Guest");

        }

      }

    }

  }

}

Because you can only reference other PCL projects, it may seem impractical to use a PCL with DI or other shared resources that you have in your reusable libraries. In reality, this constraint can actually help enforce a clear separation of concerns, making your projects even more reusable—you may have projects in the future that won’t utilize DI but could benefit from your PCL project.

I’ll demonstrate the principles involved in using the PCL with DI using a demo application. It’s a simple application that has two modules (guest and main) that are loaded on-demand using role-based security. Available features for these modules and Views will be determined by the roles attached to both the module and logged-in user. There are three users: Admin, Guest and Jane Doe (user). A business rule is that the Guest account can never access the main module.

The magic of this application lies in its simplicity; you’ll find no codebehind in the Views or domain objects polluted by UI requirements. The ViewModels hold UI-specific state and the Presenters manage the Views/ViewModels associated with their concerns through the use of business logic and DALs. Plumbing is handled by the infrastructure, such as button clicks, freeing up the developer to focus on business logic. Developers new to an application will quickly learn where to begin locating code—always start with the Presenter.

Tightly Coupled Components

The only tight coupling is shown in Figure 1. This coupling is to be expected with the Model-View-Presenter ViewModel (MVPVM) pattern using Prism and DI. With this pattern, the module is responsible for instantiating the Presenter, which in turn instantiates the required View and ViewModel, wiring them up as required. The modules and their components have no knowledge of one another.

Tightly Coupled Components

Figure 1 Tightly Coupled Components

Ideally I would create separate projects for each module (ApplicationController, Main and Guest) so that I could reuse these modules (with this framework) in other solutions. (Note: Because both the GuestPresenter and MainPresenter share the MainViewModel, I’d also have to move this ViewModel into a shared project that could be accessed by both of them. You can see how quickly I can accumulate projects in the name of separating concerns and reusability, particularly if I were coding for multiple platforms.) You’ll also see that, because I kept my demo simple, the only reusability it offers is copy and paste. The key is finding the balance, and the PCL helps provide that.

Figure 2 demonstrates how all layers (presentation, business and data) share PCL resources. Because security is a concern with nearly any application, I can safely integrate it—with its entities—in UC0100, which will be my PCL, with the notion that it may be the only reusable component that this demo application has (and a useful one at that).

All Layers and Shared PCL Resources

Figure 2 All Layers and Shared PCL Resources

It’s beyond the scope of this article to cover all aspects of the PCL that I’ll be using to manage my infrastructure; however, I’ll cover the use cases highlighted in blue in Figure 3.

PCL Use Cases

Figure 3 PCL Use Cases

UC0100-020 Base Use Case

To improve extensibility in enterprise applications, it’s helpful to have a consistent standard for wiring up the platform. This will help new developers as well as experienced developers who may not have frequented a module for a while. They’ll be able to ramp up quickly to get required tasks done; minimal time will be spent hunting down code. With this in mind, I created a ModuleBase that’s designed to work with the Prism IModule interface—more specifically, with the Initialize method. The issue here was that IModule wasn’t available because it resides in a Prism (a non-PCL) assembly. I wanted the base to have logging capabilities, so the ILogger interface must be provided an instance before the Initialize method is called. This ModuleBase now can serve as a contract for all modules, in all solutions and projects, because it implements the IModule Initialize method, shown in Figure 4.

Figure 4 The Initialize Method in the ModuleBase Class

public class ModuleBase

{

  public ILogger Logger { get; set; }



  /// <summary>

  /// Called by Prism catalog manager. Provides hook 

  /// to register types/views and initialize the view model.

  /// </summary>

  public virtual void Initialize()

  {

    try

    {

      // Provide hooks for registrations

      RegisterTypes();

      RegisterViews();



      InitializeModule();

    }

    catch (Exception ex)

    {

      Logger.Log("ERROR in [{0}] {1}{2}", 

        GetType().Name, ex.Message, ex.StackTrace);

    }

  }

Unlike the PCL, my MsdnDemo.Phone project does have a platform-specific reference to my Prism assembly, so the DI code can reside in a PresentationModuleBase class within this project; it will be the base class for all modules. In a real-world application, this class, like other DI base classes, would reside in separate reusable projects.

When the module is resolved (instantiated) by the DI container, it will set Logger as configured by my GwnBootstrapper. When the Logger property value is set, it will pass the instance to the base Logger, effectively providing the ModuleBase ILogger reference for the Initialize (and other) virtual methods (see Figure 5).

Figure 5 Setting the Logger Property

public class PresentationModuleBase : ModuleBase, IModule

{

  [Dependency]

  public override ILogger Logger {get;set;}



  [Dependency]

  public IUnityContainer Container { get; set; }



  [Dependency]

  public IRegionManager RegionManager { get; set; }



  [Dependency]

  public IEventAggregator EventAggregator { get; set; }



  [Dependency]

  public IRegionViewRegistry RegionViewRegistry { get; set; }

 (Note: Because constructor injection occurs before setter injection—in the Unity framework—the constructor of ModuleBase can’t have logging statements, because it will be null.)

Derived from PresentationModuleBase, the following MainModule code is the same code/file for all three platforms (Windows Phone 7, Silverlight and WPF):

public class MainModule : PresentationModuleBase

{

  protected override void RegisterViews()

  {

    base.RegisterViews(); 



    // Instantiate the presenter, which in turn will instantiate

    // (resolve) the View and ViewModel

    var presenter = Container.Resolve<MainPresenter>();



    // Load this presenters view into the MainRegion

    RegionViewRegistry

      .RegisterViewWithRegion(MvpVm.MainRegion, () => presenter.View);



    // Activate the presenters view after module is loaded

    RaiseViewEvent(MvpVm.MainModule, presenter.View.GetType().Name,      

      ProcessType.ActivateView);

  }

}

UC0200-050 Entities Use Case

Using Plain Old CLR Objects (POCOs) provides the best reusability. Even though the PCL supports INotifyPropertyChanged, I may not always be using these entities with XAML. I may want to also use them with an ASP.NET MVC 3 project or the Entity Framework. So my UserEntity and SecurityEntity objects can be enterprise-level POCO classes that can be easily reused in any application on any platform, as shown in Figure 6.

Figure 6 The UserEntity and SecurityEntity Objects

public class UserEntity 

{

  public int Id { get; set; }

  public string FirstName { get; set; }

  public string LastName { get; set; }

  public string PrimaryEmail { get; set; }

  public string Password { get; set; }

  public override string ToString()

  {

    return string.Format("{0} {1} ({2})", FirstName, LastName, Password);

  }

}



public class SecurityEntity : ISecurityViewModel

{

  private string _login;

  public int Id { get; set; }

  public bool IsAuthenticated { get; set; }

  public IEnumerable<string> Roles { get; set; }



  public string Login

  {

    get { return _login; }

    set 

    { 

      _login = value;

      Id = 0;

      IsAuthenticated = false;

      Roles = new List<string>();

    }

  }



  public bool IsInRole(string roleName)

  {

    if (Roles == null)

      return false;

     

    return Roles.FirstOrDefault(r => r == roleName) != null;

  }



  public bool IsInRole(string[] roles)

  {

    return roles.Any(role => IsInRole(role));

  }

}

If the UserEntity POCO is going to be used on a ViewModel, it will have to be wrapped. The ViewModel will raise the notifications and, under the hood, the data will be transferred to the POCO, as shown in the excerpt from the MainViewModel class in Figure 7.

Figure 7 Transferring Data to the POCO

public UserEntity SelectedUser

{

  get { return _selectedUser; }

  set

  {

    _selectedUser = value;



    OnPropertyChanged("SelectedUser");

    OnPropertyChanged("FirstName");

    OnPropertyChanged("LastName");

    OnPropertyChanged("Password");

    OnPropertyChanged("PrimaryEmail");

  }

}



public string FirstName

{

  get { return _selectedUser.FirstName; }

  set

  {

    _selectedUser.FirstName = value;

    OnPropertyChanged("FirstName");

  }

}

Note that I only show the FirstName property, but all of the UserEntity properties have a comparable wrapper. If I update SelectedUser, it will raise the property changed notification for all of the UserEntity properties so that XAML will be notified to update the UI fields as applicable.

UC0100-060 Events Use Case

Event aggregation, a function of Prism, provides a means to loosely couple applications while providing an excellent way to communicate between decoupled components. It does this by allowing each component to simply publish events without knowledge of the subscribers. Likewise, components can subscribe to events and handle responses without any knowledge of the publisher.

Some would argue that event aggregation makes code hard to follow, but with proper logging, it’s actually the opposite. For example, I may have a drop-down list in another module that permits the user to switch the currency to use for financial values. A component I’m working on is dependent on this setting and is used to calculate the value for a ViewModel property, and there are layers of logic between my component and the component with the drop-down list (perhaps even in a separate module). If this value changes and my component doesn’t get notified, it would be easier to debug using event aggregation than to trace through all of the potential logic trails to complete the path (or multiple paths) using other means. With event aggregation, there are only two points to debug: the subscriber and publisher. If I logged both (as the demo application does), it narrows a problem to a single point of failure.

The Prism event has to reside in the MsdnDemo.Phone project because of its dependencies on the Prism CompositePresentationEvent; as such, it can’t reside in the PCL:

public class MessageEvent : CompositePresentationEvent<MessageEventArgs>

{

}

The EventArgs, on which the events have dependencies, are served well by the PCL because I can have a common set of event arguments—which will be used across numerous enterprise applications—within it. Figure 8 shows the MessageEventArgs that’s handled by the previous MessageEvent.

Figure 8 The MessageEventArgs Handled by the MessageEvent

public class MessageEventArgs : EventArgs

{

  public object Sender { get; set; }

  public Enum Type { get; set; }

  public string Message { get; set; }

  public bool IsError { get; set; }

  public bool IsInvalid { get; set; }

  public int StatusCode { get; set; }

  public int ErrorCode { get; set; }

  private Exception _exception;

  public Exception Exception

  {

    get { return _exception; }

    set

    {

      _exception = value;

      IsError = true;

    }

  }

}

UC0100-100 MvpVmBase Use Case

The highest benefit of code reuse is reliability; it’s highly likely, as in the case of the MsdnDemo.Phone application, that unit tests are checking most of the code’s functionality. This, combined with time in the field, will result in stable, reusable code. This will provide increased velocity and reliability for your team members, particularly when they have to reuse it for a new requirement. Additional benefits are that the code becomes easier to work on, new features can have global benefits and wiring up a new application can happen within a few hours. You simply create the Views, ViewModels and Presenters (applying applicable interfaces), and your new module can be up and running.

In the MsdnDemo.Phone application, the PresentationPresenterBase (Presenter base class) simply needs to be sent the View and ViewModel that will be used by the Presenter. Note how both Presenters share the same ViewModel in Figure 9.

MsdnDemo.Phone Presenters

Figure 9 MsdnDemo.Phone Presenters

The PresentationPresenterBase derives from MvpVmPresenter, a class in my PCL, which will serve as a contract for all shared Presenters and their ViewModels across my enterprise applications. Its code is shown in Figure 10.

Figure 10 The PresentationPresenterBase

public class MvpVmPresenter<TView,TViewModel> 

  : IMvpVmPresenter

    where TView: IView

    where TViewModel : IMvpVmViewModel

{



  public IShell Shell { get; set; }

  public TView View { get; set; }

  public TViewModel ViewModel { get; set; }



  /// <summary>

  /// Called when the view is activated (by Application controller)

  /// </summary>

  public virtual void ViewActivated(ViewEventArgs e){}

}

As with ILogger referenced in the PresentationModuleBase class earlier, I’ll have to wrap ILogger in a similar fashion (passing the instance to the base) as well as the Shell, View and ViewModel, because these are injected via DI.

The PresentationPresenterBase, like the PresentationModuleBase, will have the responsibility of handling all DI-related services because it has references to the Prism and Unity platform-specific assemblies. As the process matures, more responsibility can be moved to their base classes in the PCL.

Note that in Figure 11, when the DI container resolves the specified ViewModel (TViewModel), it will set the bindings for the ButtonCommand on the ViewModel (line 99). This permits the Presenter to handle all button clicks via the ExecuteButtonCommandHandler on line 56 in Figure 9.

The Presenter Base Class

Figure 11 The Presenter Base Class

Having the Presenters handle button clicks, versus the ViewModels, is one of the many benefits that inspired “olden day” architects to evolve from the Presentation-Model-Pattern and the Application-Model-Pattern to the Model-View-Presenter pattern.

ViewModels can be shared, as is the case with the MainViewModel, and each Presenter can use the MainViewModel in different ways based on its requirements. Had I moved the button clicks into the ViewModel, I would’ve had to use conditional statements, which in time would cause code bloat and require regression testing, as new code could affect logic for modules that weren’t in the development cycle. Keeping Views and ViewModels clean of business logic allows for their maximum reuse.

Wrapping Up

The PCL can significantly reduce the number of projects required for multi-targeted applications while providing contracts for enterprise-level applications. The constraint of not being able to reference non-PCL assemblies lends itself to better coding practices, enabling projects to have a clear separation of concerns. Combining these benefits of the PCL with DI will maximize the ability to reuse decoupled projects that have been tested with time (and available unit tests), increasing the scalability, extensibility and the velocity of your team in completing new tasks.


Bill Kratochvil*, an independent contractor, is a lead technologist and architect for an elite team of developers working on a confidential project for a leading company in the medical industry. His own company, Global Webnet LLC, is based in Amarillo, Texas.*

Thanks to the following technical experts for reviewing this article: Christina Helton and David Kean