Welcome to MSDN Blogs Sign in | Join | Help

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.

 

 

Published Friday, March 09, 2007 8:31 PM by shahpiyush
Attachment(s): EmbedMasterPage.zip

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Embedded MasterPage with VirtualPathProvider and Resource files

Tuesday, March 27, 2007 12:38 PM by Jon Gallant's Blog

Piyush Shah , a dev on my team, developed a way to embed MasterPages in assemblies using VirtualPathProvider

# Solutions With The VirtualPathProvider

Wednesday, April 04, 2007 11:55 PM by BusinessRx Reading List

The VirtualPathProvider is one of the ASP.NET pieces I looked at when 2.0 was new. I suspected then that

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, April 20, 2007 7:13 AM by Kungen

"I suspected then that"...? What?

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, April 20, 2007 1:16 PM by shahpiyush

That was a trackback from K Scott Allen's blog. Here is the link for the complete sentence -

http://odetocode.com/Blogs/scott/archive/2007/04/04/10666.aspx

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Saturday, June 30, 2007 9:35 PM by Sergio Pereira

Thanks for sharing this. I was about to try a similar thing and you saved me a lot of trouble. Just as a tip for anyone implementing all this, you do not need to embed the .master.cs file. You can compile it normally, just remove the CodeFile/Codebehind property from the master directive in the .master file (make sure the Inherits stays there).

# Master Page Reuse Across Applications

Monday, August 13, 2007 12:49 PM by Steve Caravajal's Ramblings

Interesting read...ran across this while developing for a recent POC Sharing Master Pages amongst Applications

# VirtualPathProviders - A Note on Project Types

Monday, September 24, 2007 4:36 PM by Hilton Giesenow's Jumbled Mind

I was working with VirtualPathProviders today for an upcoming talk at Tech Ed. VPPs are a technique whereby

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Tuesday, October 16, 2007 12:25 PM by Helaba

Hi,

I just tried your approach.

I opened your project(EmbedMasterPage.zip).

I just opened new web site project and added a new reference to VirtualPathProvider.dll. Then I added the OnPreInit Event to Default.aspx.cs.

Then I added new Global.asax and added Application_Start Event to it.

But the new project is not compilable - "VirtualPathProvider.MasterPageVirtualPathProvider does not contain a definition for masterPageFileLocation". Hope you can help me... otherwise I don't know how to implement the MasterPage via a DLL.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Tuesday, October 16, 2007 1:01 PM by Helaba

Additional:

Starting the app with the result:

"Server Error in '/WebSite1' Application"

"Content controls have to be top-level controls in a content Page or a nested master page that references a master page"

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, October 17, 2007 8:56 PM by shahpiyush

Can you make sure you do not have any content outside the <asp:content> tag?

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, November 01, 2007 10:04 PM by ian

I've tried setting this up, but the Assmebly stream in ReadResource always returns null for me when I call this from the web application. My guess is that I haven't set the three class constants in the VirtualPathProvider class correctly. Can you explain a bit more about when each of those constants represents and how to modify them for a project?

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Saturday, January 12, 2008 6:05 AM by Joe Chung

Hi, Piyush, it was nice to meet you today!  I was curious how you managed to distribute a master page in a DLL, and wouldn't you know it?  You have a blog post describing exactly how to do it.  Excellent!

I wonder if something similar could be done for Web User Controls as well.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Saturday, January 12, 2008 8:52 PM by shahpiyush

Yep. Absolutely, the same concept can be used for Usercontrols as well.

1. Embedd UserControls as Resource.

2. Read the string as a MemoryStream from the Assembly.

3. Use Page.ParseControl to add it to your page. http://msdn2.microsoft.com/en-us/library/kz3ffe28.aspx

However if this is something you are sharing amongst applications I would create a Server WebControl as above may not be that performant. With Server Control you can GAC it, have designer support, toolbar support, etc.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Tuesday, January 15, 2008 1:32 AM by Joe Chung

I couldn't get ParseControl to do the job (HttpParseException), but System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath did the trick!

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Tuesday, January 15, 2008 1:45 AM by Joe Chung

Oops, I mean LoadControl, not CreateInstanceFromVirtualPath.  CreateInstanceFromVirutalPath doesn't deal with server-side controls in the User Control Markup that well.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, February 21, 2008 2:41 PM by Jayanthi

Hi Piyush,

Thanks so much for the brilliant technique. I've extended the idea, and using HttpModule to register master page, and all works fine.

However, i'm stuck when I create a deployment project to the webapp project that uses the dll. What should the properties look like? The project has the masterpage dll in the bin (Copy to Output).I get a runtime error that it cannot find the virtual directory for the masterpage. Any help or pointers will be greatly appreciated! Thanks!

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, February 21, 2008 4:04 PM by Jayanthi

After going through the MSDN documentation for the nth time, I finally saw the 'Note:' that this will not work for Precompiled websites.

But I also found a workaround here

http://sunali.com/2008/01/09/virtualpathprovider-in-precompiled-web-sites/

Although, i'm not too happy since I have to muck with an internal method using reflection.

Could you please give an update, if at all this will be fixed? (VPP in precompiled apps)

Appreciate your time and all the great work - thanks!

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, February 21, 2008 9:41 PM by shahpiyush

Thanks for sharing the link. As it said the problem is in the HostingEnvironment class. Unfortunately I do not know why this is there and will it be fixed.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, February 22, 2008 12:03 PM by Jayanthi

I tried the workaround using reflection to call the internal method of the HostingEnvironment class - Now i'm able to register the master page, however i get another error now

<MasterPageDirectory/Master page> has not been pre-compiled, and cannot be requested.

I'm developing a framework for several webapps in my company,and not having the webapps precompiled is not an option.

Any suggestions ?

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, February 27, 2008 10:55 AM by Jayanthi

Ok - I finally have it all working.

For precompilation, apart from the workaround mentioned above, if we use a web application project as opposed to website, you have to remove the master page reference from the aspx files (I had them point to a dummy master page, for designer support, which we don't need in VS2008). However if you have a website solution, you don't need any intervention.

I have a Httpmodule instead of Global.asax to register the VPP, and a base page that adds controls dynamically to the Master page, all wrapped in a dll.

The website page will just inherit from this base page.

Thanks !

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, February 27, 2008 3:55 PM by shahpiyush

Cool Nice tip. Thanks for keeping me updated.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, March 05, 2008 4:47 PM by bharman

In reading the thread above, there is a reference to a EmbedMasterPage.zip file that I assume contains the code example described.  Where is that available?

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, March 06, 2008 5:13 PM by bharman

Similar to ian's problem mentioned earlier, I too, continue to get a null reference when I modify the constants in the MasterPageVirtualPageProvider.

My constants are:

public const string MasterPageFileLocation = "~/MasterPage.master";

       public const string VirtualPathProviderResourceLocation = "VirtualPathProvider.Resources";

       public const string VirtualMasterPagePath = "~/";

I don't have the master page stored in any folders...stored in the root of the project.

Any ideas what I'm doing wrong?

Thanks for your help.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, March 06, 2008 5:24 PM by shahpiyush

bharman,

The code shown for EmbedMasterPage in this post can be found here - http://blogs.msdn.com/shahpiyush/attachment/1847195.ashx

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, March 06, 2008 5:27 PM by shahpiyush

Regarding the contstants. Here is the description -

VirtualMasterPagePath - This is the path which should be handled by the VirtualPathProvider

VirtualPathProviderResourceLocation - In the example the Master page is stored in the resource folder so that is what this contant is there for.

MasterPageFileLocation - This is the location of the Master page which you can call from your client application.

I would advise you to have the Virtual Path as a folder rathern than at the root. Let me know if that works.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, April 18, 2008 4:00 PM by Anubhuti

Hi Piyush,

Thanks for this blog. Actually I am trying to create Global master page since a week by publishing it as DLL and then putting it in GAC but this was giving me a very Irritating Error:

An error occurred while try to load the string resources (FindResource failed with error -2147023083).

Which went away when the HTML in Global Master Page was very Small.

I am going to try this.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, June 06, 2008 5:47 AM by Anumole Mathew

Hi,

I am using a VB solution for the Master page and in that I am getting the return of this function ReadResource as nothing that is :

assembly.GetManifestResourceStream(MasterPageVirtualPathProvider.VirtualPathProviderResourceLocation + "." + resourceFileName).

How can make it available in VB.Net

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, June 11, 2008 8:17 PM by Raj

How does this work, if I need to have:

- Any ASP.NET standard server controls or custom server controls in my master mage.

- user controls in my master mage.

- nested master pages

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, June 11, 2008 11:49 PM by shahpiyush

Anumole Matthew,

For VB.Net related code on Assembly, check this support article -

http://support.microsoft.com/kb/319291

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, June 11, 2008 11:50 PM by shahpiyush

Raj,

- Any ASP.NET standard server controls or custom server controls in my master mage.

- user controls in my master mage.

- nested master pages

It should work like any other master page. All I am doing is giving ASP.Net master page from DLL instead of File system.

HTH

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, June 12, 2008 10:10 AM by Brian

Is the designer support fixed in VS2008? I see that Jayanthi mentioned "I had them point to a dummy master page, for designer support, which we don't need in VS2008".

Brian

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, June 12, 2008 12:19 PM by shahpiyush

Brian,

No. Unfortunately that will not be available with this approach.

# Share master page with designer support

Friday, July 11, 2008 11:13 AM by Santhosh

I have several projects that is supposed to share same set of master pages. Also I have some code behind functionality that is common across applications. I need share these along with the master pages.

In the above discussed methods I see that there is no way to get designer support. I would appreciate if someone give me some pointers on how to share master pages without loosing the designer support.

Please help!

Thanks in advance

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, September 05, 2008 4:29 PM by Eric

This example seems really incomplete.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, September 05, 2008 4:34 PM by shahpiyush

Eric,

What is missing for you?

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Monday, September 08, 2008 2:26 PM by Eric

What is this:  public const string VirtualMasterPagePath = "~/MasterPageDir/";

Can VirtualMasterPagePath be set to anything?

I keep getting stack overflow errors in Page_PreInit of my page that consumes the master page.  I have a feeling that it is the constants declared in 'MasterPageVirtualPathProvider.cs' not being set properly (by me).

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Monday, September 15, 2008 1:34 PM by Nate

Hi,

I tried this method of storing MasterPages in DLLs and it worked great, it does basically exactly what I want it to do, but with one restriction...  It only works if I remove the caching functionality from the MasterPageVirtualFile.Open function (its in the source you provide, but not in this post...)

The issue is that whenever it retrieves a file from the cache (it works fine the first time I open the application, but does not work subsequently), I get an error telling me the stream is not open.

Could you shed any light on this?

Thanks,

Nate

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, September 17, 2008 7:05 PM by Matt Poland

FYI: In converting this to VB, I had to remove ".Resources" from the VirtualPathProviderResourceLocation.  I also had to use Sergio Pereira's suggestion of compiling the master page class.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, September 18, 2008 9:49 AM by Matt Poland

For some further feedback (and the sake of those just diving in), the virtual path provider and virtual file provider classes could be named EmbeddedResourceVirtualFile and EmbeddedResourceVirtualPathProvider if you handle your constants differently.  Basically if you had 10 embedded master pages, those two classes could serve all of them.  The sample makes it seem that you should create different virtual provider classes for each master page whereas those two classes could serve anything embedded (images, master pages, scripts, styles, etc).

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Tuesday, October 21, 2008 3:03 PM by Jyotishka Bora

Has anyone got this error while trying to use the embedded masterpage??

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentNullException: Value cannot be null.

Parameter name: value

Source Error:

Line 33:                 if (HttpContext.Current.Cache[virPath] == null)

Line 34:                 {

Line 35:                     HttpContext.Current.Cache.Insert(virPath, ReadResource(virPath));

Line 36:                 }

Line 37:                 return (Stream)HttpContext.Current.Cache[virPath];

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Monday, November 10, 2008 12:30 PM by Steph

Hello,

I have got the same issue than you and finally found the root cause by step by step debugging:

You need to set BOTH the Master Page and its code behind as being Embedded resources. The error is poping up because the .cs code behind file is not in your resource.

Steph.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, November 14, 2008 12:21 PM by Alan

For anyone having problems loading the manifest resource stream, make sure you are correctly referencing the resouce.  An easy way to do that is to just pull up

assembly__1.GetManifestResourceNames

It will show you the name of all of the resources in the executing assembly.  In my case the ".Resources" was unnecessary, and my assembly name was different.  My call ended up looking like this:

assembly__1.GetManifestResourceStream("EmbeddedMasterPage.MasterPage.Master")

EmbeddedMasterPage being the name of my project/assembly

# Sharing Master Pages amongst Applications by Embedding it in a Dll

Tuesday, November 25, 2008 10:56 AM by DotNetKicks.com

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Wednesday, August 05, 2009 12:21 PM by Claudio

Hi! Some people complains about performance issues using VirtualPathProvider. Mostly related to app pool restarting frequently. This is related to no (or bad) implementation of GetFileHash and GetCacheDependency. I don't see anything related to those methods here :-(

Any suggestions about how to implement them and avoid performance issues? Thanks!

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, October 01, 2009 1:34 PM by Gary

Is anyone having trouble publishing their website?

Building it in Visual Studio seems to work out but publishing results to an "Index was outside the bounds of the array." and errors "Unrecognized tag prefix or device filter 'asp'.".

My original website was publishing before integrating the virtual path provider.

I appreciate any tips or suggestions... thanks!

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, October 01, 2009 1:57 PM by Gary

Found a solution / quick fix for my problem.

For some reason, deleting the "Visual Studio 2005" folder works.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Thursday, October 15, 2009 8:58 AM by Paulbi

Hi,

One question I have!

Rather interestingly I place the below directive into the 'VirtualPathProviderTest.aspx' and it worked (although I had to ignore the compile time error)...

MasterPageFile="~/MasterPageDir/VirtualPathProvider.dll/MasterPage.master"

...is there a way to get rid of the error?

For me this is a preferred method to reference the master page I want to use.

Cheers,

Paul

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, October 16, 2009 12:49 PM by Mack

In my MasterPage I added an image. I tried setting its Build Action to all possible values, but when I run the application, the image doesn't show up. Any help will be really appreciated. Following is the line I use to add image in MasterPage:

<asp:Image ID="imgBirthday" ImageUrl="~/Resources/images/happy-birthday.jpg" runat="server" />

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, October 16, 2009 12:58 PM by Mack

In my MasterPage I added a JavaScrip file and an image. I tried setting image's Build Action to Embeded Resource, but when I run the application, the image doesn't show up. Any help will be really appreciated. Following is the line I use to add image in MasterPage:

<asp:Image ID="imgBirthday" ImageUrl="~/Resources/images/happy-birthday.jpg" runat="server" />

Please also give me a hint on how to add javascript file in Master page.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Friday, October 16, 2009 4:20 PM by shahpiyush

Mack,

The image has to be in the virtual path. If you see the example project the virtual path is -

public const string VirtualMasterPagePath = "~/MasterPageDir/";

Try this -

<asp:Image ID="imgBirthday" ImageUrl="~/MasterPageDir/images/happy-birthday.jpg" runat="server" />

Embedding javascript should be the same way as images, you need to make sure the virtual path is correct.

HTH.

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Monday, October 19, 2009 5:53 AM by Paulbi

Hi shahpiyush,

Did you have a chance to look at my question yet?

It would be really cool if you could help me :)

Thanks,

Paul

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Monday, October 19, 2009 8:29 AM by Mack

@ Piyush: The trick worked, but didn't actually work too. The image shows up one time but if the page is refreshed by button click or anything, image disappears.

Then I even added a constant member in class MasterPageVirtualPathProvider as follows:

public const string VirtualBirthdayImageLocation = "~/MasterPageFolder/images/happy-birthday.jpg";

and my page's OnPreInit looks like this:

       MasterPageFile = MasterPageVirtualPathProvider.MasterPageFileLocation;

       ((Image)Page.Master.FindControl("imgBirthday")).ImageUrl = MasterPageVirtualPathProvider.VirtualBirthdayImageLocation;      

       base.OnPreInit(e);

Even that didn't help; image shows up one time, but on page refresh disappears. Thanks so much for your help...

# re: Sharing Master Pages amongst Applications by Embedding it in a Dll

Tuesday, October 20, 2009 6:38 AM by Mack

And also, I'm still unable to add Javascript file and/or css stylesheets in my master page; i tried all combinations of virtual and physical paths.

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker