Sharing Master Pages amongst Applications by Embedding it in a Dll

If you need to share Master Pages across applications and you don't want to create a ton of virtual directories, below is a way to do that. You can embed the Master Page as a Resource in your Dll and use VirtualPathProvider mechanism to call the Resource.

VirtualPathProvider is a new functionality provided in .Net Framework 2.0, this functionality allows you to retrieve pages/resources from a virtual file system. This means that you can create web application to serve pages from a Database, Zip file, etc.

You will need to inherit and provide functionality for these 3 classes –

1. VirtualPathProvider class provides a set of methods to implement the Virtual File System. It has methods which you will need to override like –

a. FileExists – indicates whether a file exists in the virtual file system

b. GetFile –This method gets the file from the virtual file system.

c. DirectoryExists - indicates whether a directory exists in the virtual file system.

d. GetDirectory – This method gets a virtual directory from the virtual file system.

2. VirtualFile class represents a file object in a virtual file or resource space. You will need to override Open() method.

3. VirtualDirectory class Represents a directory object in a virtual file. I am not including this functionality in this example, as its not used.

First, I will create the Master page (and its code behind) and embed it as a Resource

Set build action to Embedded Resource

Next I will create the VirtualPathProvider, by inheriting from System.Web.Hosting.VirtualPathProvider. You need to override FileExists and GetFile methods

 

public override bool FileExists(string virtualPath)

{

   if (IsPathVirtual(virtualPath))

   {

   MasterPageVirtualFile file = (MasterPageVirtualFile)GetFile(virtualPath);

      return (file == null) ? false : true;

   }

   else

   {

   return Previous.FileExists(virtualPath);

   }

}

public override VirtualFile GetFile(string virtualPath)

{

   if (IsPathVirtual(virtualPath))

   {

   return new MasterPageVirtualFile(virtualPath);

   }

   else

   {

   return Previous.GetFile(virtualPath);

   }

}

Both the methods call IsPathVirtual method to check if the file requested is a Virtual file.

private static bool IsPathVirtual(string virtualPath)

{

String checkPath = VirtualPathUtility.ToAppRelative(virtualPath);

return checkPath.StartsWith(VirtualMasterPagePath, StringComparison.InvariantCultureIgnoreCase);

}

Next I will create the VirtualFile and implement Open()

public MasterPageVirtualFile(string virtualPath): base(virtualPath)

{

this.virPath = virtualPath;

}

public override Stream Open()

{

return ReadResource(virPath);

}

private static Stream ReadResource(string embeddedFileName)

{

string resourceFileName = VirtualPathUtility.GetFileName(embeddedFileName);

      Assembly assembly = Assembly.GetExecutingAssembly();

return assembly.GetManifestResourceStream(

Constants.MasterPageKeys.VirtualPathProviderResourceLocation + "." + resourceFileName);

}

Now I will use this VirtualPathProvider in the Web Application.
First you need to Register the VirtualPathProvider with the Application. You can do that in the Application_Start of Global.asax.

void Application_Start(object sender, EventArgs e)

{

    MasterPageVirtualPathProvider vpp = new MasterPageVirtualPathProvider();

    HostingEnvironment.RegisterVirtualPathProvider(vpp);

}

Next, you will need to register the Master page in the PreInit event of the page.

protected override void OnPreInit(EventArgs e)

{

   MasterPageFile = MasterPageVirtualPathProvider.MasterPageFileLocation;

   base.OnPreInit(e);

}

The advantages are plentiful with this approach –

1. You can distribute Master pages inside Dll’s.

2. You can share Master pages amongst different applications.

3. You can extend this approach for Themes, Pages, etc.

Having said the advantages you need to note that this approach has these shortcomings –

1. No designer support.

2. You cannot bind the Master page inside the ASPX in the <%@Page%> directive.

 

EmbedMasterPage.zip