Deployment of EPiServer add-on modules as ZIP packages

November 24, 2014

Many of you have seen how some of the EPiServer modules are being deployed as compressed ZIP packages and have asked if you can do the same with your own modules. To cater for these requests we added a virtual path provider with support for ZIP files to the EPiServer.Framework package called ZipArchiveVirtualPathProvider. This addition was released as a part of version 7.15.0.

Before reading further on how to use this provider, please not that EPiServer does NOT recommend using it in end user scenarios with high resource utilization. It is also not recommended to use it if your add-on contains large content files as its uses an in-memory cache to prevent the single threaded read access to the ZIP archive from becoming a bottle neck.

Convention based registration

If you want to deploy your add-on as a compressed module, simply create a ZIP file with the module content and give it the same name as your module, with the addition of the .zip extension of course, and place it in the content folder root. The EPiServer Shell module framework uses a simple convention based registration that will scan all module folders on initialization and configure a virtual path provider for any ZIP files that matches this criteria.

As an example, once installed, a protected module named ‘MyModule’ should have a ZIP file called ‘MyModule.zip’ directly in its module folder, e.g. ‘~/modules/_protected/MyModule/MyModule.zip’

Files contained in the zip file can then be accessed using the same path as if they had been extracted into the add-ons folder. If files has been added to the ZIP with a relative path, this will be combined with the base path. For example, a content image named ‘icon.png’ placed in the folder ‘ModuleImages’ inside the archive for the protected add-on module ‘MyModule’ on a site with the protected root path configured to ‘~/EPiServer/’, can be accessed by the path ‘~/EPiServer/MyModule/ModuleImages/icon.png’.

Using this pattern also means that it is easy to change back to using standard file access. Just unpack the ZIP file into its folder and all paths will stay the same. Just remember to delete the ZIP file or the provider will continue to serve files from the archive.

Static file content

By default, requests for static file content, such as images and style sheets, are handled directly by the IIS and the virtual path provider will never get the chance to evaluate it. For protected modules, a section is already added to the base web.config as the protected folder itself is served by another virtual path provider. For public modules we can get around this by adding a web.config file in the add-on folder next to the ZIP file with the appropriate handlers section. Depending on what files you want to serve, it could look something like the following:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="epijpg" path="*.jpg" verb="*" type="EPiServer.Web.StaticFileHandler, EPiServer.Framework" />
      <add name="epipng" path="*.png" verb="*" type="EPiServer.Web.StaticFileHandler, EPiServer.Framework" />
      <add name="epigif" path="*.gif" verb="*" type="EPiServer.Web.StaticFileHandler, EPiServer.Framework" />
      <add name="epicss" path="*.css" verb="*" type="EPiServer.Web.StaticFileHandler, EPiServer.Framework" />
      <add name="epijs" path="*.js" verb="*" type="EPiServer.Web.StaticFileHandler, EPiServer.Framework" />
      <add name="BlockDirectAccessToModuleZip" path="MyModule.zip" verb="*" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

Note the final handler that will prevent users from accessing the zip file itself directly.

Limitations to file access

If you decide to start using the ZIP provider, you should not have to make any changes to the add-on code, with one exception. Any direct access to content files using System.IO will no longer work, instead you need to go through the Virtual Path Provider system for any access. Note that this might also include indirect access, such as through XML readers etc.

So if you for example is reading a file using System.IO:

var mappedPath = HttpContext.Current.Server.MapPath(virtualPath);
using (var stream = File.OpenRead(archiveFileName))
{
    // Use of file stream...
};

It must be replaced by something along the lines of:

var virtualFile = HostingEnvironment.VirtualPathProvider.GetFile(virtualPath);
using (var stream = virtualFile.Open())
{
    // Use of file stream...
};

Please note that the examples above are kept short for clarity reasons. Make sure that you add any appropriate safe guards such as checking that the file exists in your implementations.

Advertisements
%d bloggers like this: