Prism's Plugin Architecture

  • Jul 20, 2009 at 8:16 PM
  • Shawn Wildermuth
  • 2 Comments

Url: http://wildermuth.com/downloads/CustomModularit...

Architecture

I was with a client recently and we were looking at refactoring some of their system to use Prism. This client had created a lot of infrastructure to do what Prism does (before Prism was released for Silverlight) that they wanted to opt into using Prism instead.

Out of the box Prism works well for composing your applications, but for particular cases it may not be perfect. In this case the client wanted to be able to process the .xap file before it was passed onto to the module loader. So looking through Prism's Modularity code and found that IModuleManager interface. In order to provide my own implementation I wrote a simple implementation of the interface:

public class CustomModuleManager : ModuleManager
{
  IEnumerable<IModuleTypeLoader> typeLoaders;

  public CustomModuleManager(IModuleInitializer moduleInitializer, 
                             IModuleCatalog moduleCatalog, 
                             ILoggerFacade loggerFacade) 
    : base(moduleInitializer, moduleCatalog, loggerFacade)
  {
  }

  // Replace the module loader with our own
  public override IEnumerable<IModuleTypeLoader> ModuleTypeLoaders
  {
    get
    {
      if (this.typeLoaders == null)
      {
        this.typeLoaders = new List<IModuleTypeLoader>()
                           {
                             new CustomXapModuleTypeLoader()
                           };
      }

      return this.typeLoaders;
    }

    set
    {
      this.typeLoaders = value;
    }
  }
}

This module manager is mostly used so I can get at the module loader list.  In this case I just returned a list containing my own custom XapModuleTypeLoader as shown above.  My custom module loader looks like this:

public class CustomXapModuleTypeLoader : XapModuleTypeLoader
{
  protected override IFileDownloader CreateDownloader()
  {
    return new CustomFileLoader();
  }
}

 The thin implementation of the ModuleTypeLoader is to simply inherit from the existing XapModuleTypeLoader class and just override the CreateDownloader to return a custom downloader. The custom downloader is key as that is what downloads and returns the Stream that contains the actual .xap file. By writing my own, I can intercept the .xap file before it gets returned.  Here is the CustomFileLoader:

public class CustomFileDownloader : IFileDownloader
{
  FileDownloader dler = new FileDownloader();

  public CustomFileDownloader()
  {
    dler.DownloadCompleted += 
      new EventHandler<DownloadCompletedEventArgs>(dler_DownloadCompleted);
  }

  void dler_DownloadCompleted(object sender, DownloadCompletedEventArgs e)
  {
    // Remove the event handler (so we don't leak)
    dler.DownloadCompleted -= dler_DownloadCompleted;

    // If someone cares, decrypt the stream and throw the event
    if (DownloadCompleted != null)
    {
      if (e.Cancelled || e.Error != null)
      {
        DownloadCompleted(this, e);
      }
      else
      {
        // Before you return the resulting stream,
       // make any changes you need
        DownloadCompleted(this, 
          new DownloadCompletedEventArgs(e.Result, 
            e.Error, 
            e.Cancelled, 
            e.UserState));
      }

    }
  }

  #region IFileDownloader Members

  public void DownloadAsync(Uri uri, object userToken)
  {
    dler.DownloadAsync(uri, userToken);
  }

  public event EventHandler<DownloadCompletedEventArgs> DownloadCompleted;

  #endregion
}

The downloader is pretty simple in that it uses a FileDownloader to do the downloading and just provides a place where we can intercept the download before it returns stream.

All this code was essential written to allow us to replace the default implementation of the IModuleManager. But how do we use the new IModuleManager? Since Prism uses Unity for Dependency Injection, I realized I could just register my type with the container and it would be used:

public class Bootstrapper : UnityBootstrapper
{
  // ...

  protected override void ConfigureContainer()
  {
    Container.RegisterType<IModuleManager, CustomModuleManager>();
    base.ConfigureContainer();
  }
}

By simply registering the IModuleManager with the CustomModuleManager, Prism gets injected with my implementation of the interface.  Elegant.

This holds true for many parts of Prism. If you need to replace some implementation of the Prism framework, before you start modifying the source code, make sure you can't just implement the interface and use the container to inject it into the system.

You can get the source at:

http://wildermuth.com/downloads/CustomModularity.zip

 

 


Leave a Comment

*
*
*