Prism's Plugin Architecture


Url: http://wilderminds.blob.core.windows.net/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://wilderminds.blob.core.windows.net/downloads/CustomModularity.zip

 


Ready to Learn Vue with ASP.NET Core?

Shawn's 4-hour course will get you up to speed in no time. Vue.js is a great middle-ground between React and Angular for people who don't like the complexity of Angular, and the overly componentized React. Learn today at Wilder Minds Training!

Enroll Today


Shawn
Shawn Wildermuth
Author, Teacher, and Coach




My Courses

Wilder Minds Training
Vue.js by Example (Now Available)
Bootstrap 4 by Example
Intro to Font Awesome 5 (Free Course)
Pluralsight
Less: Getting Started (Coupon Available)
Building a Web App with ASP.NET Core, MVC6, EF Core, Bootstrap and Angular (updated for 2.1)
Using Visual Studio Code for ASP.NET Core Projects
Implementing ASP.NET Web API
Web API Design

Application Name WilderBlog Environment Name Production
Application Ver v4.0.30319 Runtime Framework x86
App Path D:\home\site\wwwroot\ Runtime Version .NET Core 4.6.27019.06
Operating System Microsoft Windows 10.0.14393 Runtime Arch X86