Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Master Page Inheritance and User Controls


:P
On this page:

I'm still running into problems with trying to get 'templated' master pages to work. The page/control inheritance is still getting in the way.

 

Here's what I'm doing (recap):

 

  • I have a custom directory App_Templates
  • Sub directories for each theme
  • In each sub there are copies of all the Master Pages

 

Each of these master pages can now be templated. There's a little logic in the Page base class that picks up a 'template' master page and routes the MasterPage assignment in PreInit() to a specific master page that is theme adjusted. The idea is that you can create multiple master pages for each theme that essentially contain the same controls (well in reality they could contain different controls).

 

As described in the previous post this approach works rather well, except now I'm finding a big problem when using User Controls on the page.

 

In short here's what's happening: There's one 'master' template directory that actually hosts the code for the page class. So the there's one MASTER master page and then related inherited master pages in each of the Theme subdirectories.

 

So the first try to make this work is this:

 

<%@ Master Language="C#" AutoEventWireup="true"

           CodeFile="~/App_Templates/Standard/WebStoreMaster.master.cs"

           Inherits="Westwind.WebStore.WebStoreMaster"  %>

 

Now this appears to work, until you need to cast the MasterPage to a specific class type consistently. Something like this:

 

((WebStoreMaster) this.Master).PageTitle = ItemEntity.Descript.TrimEnd();

 

The problem is that the main class that has the code actually is WebStoreMaster. The second class is named something like:

 

ASP.app_templates_earth_webstoremaster_master'

 

and it can't be cast to WebStoreMaster despite the inherits clause above. Strike 1.

 

So in theory you should just be able to use the inherits attribute without the CodeFile, which is really what I want anyway – I want one codebehind class for all the master pages. So I  add a reference to the original page, which is what I showed in a previous post.  This is what this looks like for a satellite master page:

 

<%@ Reference VirtualPath="~/App_Templates/Standard/WebStoreMaster.master" %>

<%@ Master Language="C#" AutoEventWireup="true"

           Inherits="Westwind.WebStore.WebStoreMaster" %>

<%@ Register Src="~/CategoryList.ascx" TagName="CategoryList" TagPrefix="ww" %>

 

Note that the @Reference tag is required so that the main master page's Code class can be imported into the assembly of the second master page. Since these pages live in different directories they actually end up living in separate assemblies.

 

It works. That is as long as you don't add any User Controls to the page. <g>

 

In my example the master page contains a user control CategoryList.ascx:

 

<ww:CategoryList ID="CategoryList" runat="server"  />

 

which sits on both pages and renders a sidebar. ASP.NET is not happy with that at all though:

 

Parser Error Message: The base class includes the field 'CategoryList', but its type (ASP.categorylist_ascx) is not compatible with the type of control (ASP.categorylist_ascx).

 

Cool error message, huh? <s>

 

I'm not really sure why this is happening. The two master pages live in different assemblies, but I'm not quite sure why the CategoryList.ascx file is getting parsed as a different type. Apparently ASP.NET compiles the user control into each of the assemblies and treats them as different types with the same exact name. If this is the case – Ouch.

 

So now I'm stuck. I can't figure out how to get controls to work on both master pages.

 

I was thinking aobut using a Master base class in APP_CODE and attaching the control properties at this base class. Unfortunately that also doesn't quite work because you can't get use the CodeFileBaseClass attribute if the there's no CodeBehind file for a class/master, so the control properties don't get updated in the base. Damn it. <g>

 

The easiest solution would be to use Web Application Projects which makes this inheritance mess go away with all pages, controls and masters being able to properly reference each other. Unfortunately with WAP being an add-on and this being an application that is given out to users I don't really want to require installing anything additional beyond my tools.

 

 

The more I think about all of this the more I'm starting to REALLY dislike the ASP.NET 2.0 stock project model. I've wasted more time working around crap like this than anything else. I've said on many occasions that I think most of these issues are annoyances, but once you run into one of these they can suck a ton of time and some instances there is no workable workaround solution at all. And even if there is it's often so completely convoluted that you lose all perspective of the problem in the first place. Aggravating.

 

Maybe somebody sees something I'm overlooking here…


The Voices of Reason


 

Steve from Pleasant Hill
April 12, 2006

# re: Master Page Inheritance and User Controls

While I offer no solutions, it is my opinion that MS owes you for processing this crap that you are going through. They missed it somewhere, amd they have missed it quite badly in certain areas.

Upgrades to VS 2005, .NET 2.0, etc. should be a good thing. And while there are many improvements, apparently not many who designed this product have to build systems with it for a living. Change like this should be progressive and also time-reducing. Not many people have the time to sort thru this stuff, air it out, and write honestly about the trials and tribulations for others to leverage, like you do.

Your readers owe you a lot and I hope the next version of VS will be better at least in part to efforts like yours (and this is as sappy as I'll ever get).


DuncanS
April 12, 2006

# re: Master Page Inheritance and User Controls

"...WAP being an add-on and this being an application that is given out to users I don't really want to require installing anything additional beyond my tools."

I'm probably misunderstanding what you mean by "users" - but people who want to install and use your app don't need any WAP stuff, only *developers* wanting to further developer your app would need WAP.

Rick Strahl
April 12, 2006

# re: Master Page Inheritance and User Controls

Duncan - 'users' of my application will be developers, so that why it's a potential issue.

Frank Kroondijk
April 13, 2006

# re: Master Page Inheritance and User Controls

Hi Rick,

Not sure I understand your problem, but wont your problems go away by setting ur masterpage at the preinit stage? Timing is critical, maybe thats the prob.

protected void Page_PreInit(object sender, EventArgs e)
{

//set masterpage
this.Page.MasterPageFile = sMasterpagesPath + myTemplate.MasterPageFile;

}

cheers,
Frank

Frank
April 13, 2006

# re: Master Page Inheritance and User Controls

After writing post above, this page just poppedup in my rssreader, you might like it:

Master Pages: Tips, Tricks, and Traps
http://odetocode.com/Articles/450.aspx

Anton
April 16, 2006

# re: Master Page Inheritance and User Controls

Do you really need to use inheritance on the masters?

I have a site with a main master working out page basics like title and direction (LTR / RTL) and then I have a master for public site and a master for client site. Each has it's own code behind, but that's optional. The public and admin masters of course run the code behind of the main master.

I'm accessing properties from the main master, but here things get a little bit tricky. I've configured the property that I need from the main master as properties in the public and admin masters. I didn't try to access the main master directly from the pages or user controls -- maybe that will work with master.parent.master or something. However it seems that what I'm doing is similar to you, but on a much smaller scale.

Let me know if what I'm doing sounds like the right direction and I'll dig a little deeper soon as possible Mr <g>. ;)

Warren Bullock
April 17, 2006

# re: Master Page Inheritance and User Controls

I empathise Rick - busy developers don't have the time to go chasing ambiguous error messages. Most people with this error message seem to have just gotten the types mixed, but that's not the case in your example. So you have two master pages at work here both using the same control - is the ID specification (ID="CategoryList") the same on both master pages? If so, then maybe the ASP.NET engine is having an issue with the two rendered controls having the same identifier when it combines the page at runtime. And it can't give a normal error message because it's caught up in the rendering phase of the master page mechanics? Seems your type specifications are correct. My money is on the naming.

I've been burnt myself using user controls on master pages just recently. We have a new version of a complex control, the natural place for which was on a master page for our ASP.NET 2.0 app - good idea, not (!). Troubleshooting non-existent error messages had us pulling our hair out until we realised that the problem disappears when the control sat on a normal page render in Page_Load. Our only conclusion is that the control makes use of information in the response header which isn't available in the Pre_Init phase - being where the master control gets rendered. We'll have to rearchitect some stuff if we're to use the new control version. So the Master Pages are pretty good up to a point but advanced requirements means tough design choices - we had to ditch some of the new stuff in ASP.NET 2.0 like the cool new membership model, because it had 90% of what we needed for our long term vision, and we couldn't afford to paint ourselves into a corner (Ouch!).

--Warren

Jacques PHILIP
April 21, 2006

# re: Master Page Inheritance and User Controls

Hello Rick,
First thanks for all the practical info you post.
I wanted to use something similar so I worked on it a little and seem to have found a work around since I only have VWD and the WAP does not work with it.
Here is what I did different from your solution:
-Created a base class in App_Code with the User control(s) declared as public properties of UserControl type since we cannot use the derived user control class in App_Code.
-Derive each Master in App_Templates folder from that class in its code behind file, leaving the normal Master directive :
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="~/App_Templates/Summer/Blog.master.cs" Inherits="App_Templates_Summer_Blog" %>
-Initialize the user control properties in the Load event of each master:
this.Footer = ClientFooter1;
-In the page using the master, add the directive @MasterType pointing to the base master class:
<%@ MasterType TypeName="BlogMasterBase" %>
-Access the properties of the user control from the page by casting the base user control property to its real type like this:
((ClientFooter)(Master.Footer)).FooterText
(No need to cast the Master class)
The draw back I see is that you have to manually initialize the properties from the base class, but there may be other ones.

Rick Strahl
April 27, 2006

# re: Master Page Inheritance and User Controls

Anton,

Well, I would settle for not using inheritance if that would work.

But if I don't use inheritance then I run into issues with the master types not being comaptible - then I really have no choice but to create a base master page and inherit from that and making sure the base type has every control that needs to be shared defined on it.

While that's potentially workable I really hate this dependency and having to create a base class for each MasterPage that will be shared like this.

Plus I'm not even sure without trying it whether ASP.NET would assign the control refs to the base class - ASP.NET has this nasty habit of defining controls at the inherited level as New so they're not visible down the inheritance stack.

Rick Strahl
April 27, 2006

# re: Master Page Inheritance and User Controls

Jacques,

That's odd. That doesn't seem to work for me. As soon as I have a UserControl on the master - base class or not - ASP.NET complains that the UserControl is not of the original type defined in the base control.

The other problem I have with this whole base class approach is that the base class can not see the instance clas, so writing 'generic' code in the base master involves getting references to anything using FindControl() which is inefficient as hell.

While I don't plan on having lots of code in the base there will be a few references to controls and it's overall making the whole flow of the design messy (three places to look for code for a single master page).

I think I'm going to bite the bullet and go with Web Application Projects. This lame behavior is really dragging me down. I'm really tired of the stock Web Project format and all the shit that entails.




Rick Strahl's WebLog
April 28, 2006

# Converting my Web Store to Web Application Projects

So I went through the excercise of converting my Web Store project to Web Application Project from standard 2.0 projects. I've been getting increasingly pissed off by the ASP.NET stock 2.0 project model and the various inconsistencies that come from 'unique' compilation model that 2.0 projects use that make it near impossible to use Page and Control level inheritance. Anyway I converted the project today and here are a few notes and problems I ran into.

Jacques PHILIP
April 28, 2006

# re: Master Page Inheritance and User Controls

I guess the problem is that your users will have to have Visual Studio if they want to modify the project and recompile since VWD does not support WAP. There may be a way to do it with a command line tool too.
Your solution with a base class works good for me so far, maybe because I am not updating a project, but rather starting from scraps.
The base class does not have to reference the controls, it creates public objects that are consumed by the controls or the page inside the masters which are mostly shells for the layout.
The one thing I changed is that I separated the Themes and Masters because I want the users to be able to select one theme for the whole site, but a different layout for different part of the site. The theme being for colors, fonts... and the masters for Layout.

Rick Strahl's Web Log
October 11, 2006

# Themes and Templating Master Pages - Rick Strahl's Web Log

Themes in ASP.NET 2.0 are lacking in that they don't really support code type controls like pages or even more importantly Master Pages. Here is a simple outline that you can use to incorporated templates Master Pages alongside your Themes in a consistent way.

# DotNetSlackers: Master Page Inheritance and User Controls


squirrl
March 09, 2007

# A possible fix

Change the CodeFile parameter to CodeBehind up in the @ Control directive...

Rick Strahl's Web Log
May 27, 2007

# Converting my Web Store to Web Application Projects - Rick Strahl's Web Log

So I went through the excercise of converting my Web Store project to Web Application Project from standard 2.0 projects. I've been getting increasingly pissed off by the ASP.NET stock 2.0 project model and the various inconsistencies that come from 'unique' compilation model that 2.0 projects use that make it near impossible to use Page and Control level inheritance. Anyway I converted the project today and here are a few notes and problems I ran into.

asok1421
April 30, 2013

# re: Master Page Inheritance and User Controls

@squirrl, you just saved my butt. thanks!

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024