Creating code-behind files for Umbraco templates

by SaschaWolter 28. January 2011 12:04

I’ve always had this idea in my head that one of the downfalls of using Umbraco when coming form standard ASP.Net web application was the missing code-behind files. You know, when you create a new web application and add an .aspx page to it it conveniently comes with a .cs and design.cs file. Most of the time I would even let the code-behind file inherit from my own custom Page/MasterPage implementation, e.g. a SecuredPage that comes with various properties and methods to handle authentication. Although Umbraco uses regular masterpages (if you haven’t turned it off in the web.config) all you get in the backoffice is the actual page template. Now, don’t get me wrong: I love the way Umbraco let’s you edit all aspects of your site via the backend and gives you the utmost flexibility and 100% control over the output, presented in a refreshingly simple manner. Yet sometimes you need a bit more, and it’s just another clear plus for Umbraco that you are able do the following without ever having to modify the core.

The 'aha' moment that it is actually quite easy to add code-behind files to Umbraco masterpages came to me when I had to port a quite big ASP.Net website to Umbraco. The website had grown organically over the years with lots of custom templates, user controls, etc. The site also had multi-language support, all of which was handled in the code-behind files of the pages. The goal was to get it over to Umbraco as quick as possible, then rework the functionality bit by bit. So I started by creating a new Umbraco site and ‘wrapped’ it in a web application project in Visual Studio.

 

1-28-2011 5-00-55 PM

[Please refer to the comments below to find more information on how to set this up in Visual Studio.]

After adding a couple of document types and templates in Umbraco the masterpages folder looks something like this:

1-28-2011 5-28-34 PM

The Root.master file is the main master page, Page1.master and Page2.master are nested master pages in Umbraco. I’ve included all three of them in the solution. Now it’s time to create the code-behind file: right-click on the masterpages folder and add three C# classes and name them Root.master.cs, Page1.master.cs and Page2.master.cs. The result should be something like this:

1-28-2011 5-29-38 PM

Visual Studio automatically groups them together, fantastic. Yet they are not really hooked up yet, VS does the grouping just based on file names. The master directive on Root.master currently looks like this:

<%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %>

To hook up the cs file we need to add the CodeBehind and Inherits attributes like so:

<%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" CodeBehind="Root.master.cs" Inherits="Umbraco_4._6._1.masterpages.Root"%>

You should get an error at this point as the compiler complains that Root is not convertible to System.Web.UI.MasterPage, so we need to fix this in the cs file as well by making the class partial (necessary if you want to later add designer files as well) and inheriting from System.Web.UI.MasterPage. An empty Page_Load message can’t hurt as well:

using System; namespace Umbraco4_6_1.masterpages { public partial class Root : System.Web.UI.MasterPage { protected void Page_Load(object sender, EventArgs e) { } } }

You should now be able to switch between both files by pressing F7 in Visual Studio. Let’s try to add a Property and reference that from the template:

public string Message { get; set; } protected void Page_Load(object sender, EventArgs e) { Message = "All the best from your code-behind file!! :)"; }

and something like this on the template:

<div> <%= Message %> </div>

Now we just need to compile the project and navigate to a content page that uses the Root template to see the message.

 

Adding designer files

[As Simon Dingley pointed out below there is an even easier way to create the designer files: right-click on the master.aspx page and select "Convert to web application", which will create the .designer file for the selected item.]

We can also add a designer file to the duo to make things even better. After adding Root.master.designer.cs, Page1.master.designer.cs and Page2.master.designer.cs the solution looks like this:

1-28-2011 5-49-22 PM

Visual Studio is now rightfully complaining that it got duplicate definitions for the classes and even suggests to add the partial keyword, which we will quickly do. After that is all working and compiling nicely we need to give Visual Studio control over the designer files. That is easily accomplished by slightly modifying each .master file (e.g. by adding a single space to an empty line) and saving it, VS will do the rest for you. The most important thing this will do for you is to reference all controls you add to the template so they are available for use in the code-behind file.

Now let’s try to modify the message value from the code-behind of Page1 by adding

protected void Page_Load(object sender, EventArgs e) { ((Root) Master).Message = "Hello from the nested master page!"; }

to it. Browsing to any Umbraco page that uses the Page1 template will now show the new message.

Categories: .Net | Umbraco

Comments

1/29/2011 3:29:23 AM #

Good Job

KVigor United States

1/29/2011 11:41:01 AM #

interesting article

eran Israel

1/29/2011 11:41:43 AM #

interesting

eran Israel

1/29/2011 2:32:59 PM #

Pingback from topsy.com

Twitter Trackbacks for
        
        FARMCode.org | Creating code-behind files for Umbraco templates
        [farmcode.org]
        on Topsy.com

topsy.com

1/31/2011 4:37:23 AM #

good stuff I think I will do this as a standard mode of operation with Umraco from now on

Matt Todd Australia

1/31/2011 2:08:57 PM #

I usually do this by adding inline code into the template eg
<script runat="server">
void Page_Load(object sender, EventArgs e){
//do stuff
}
</server>

however its interesting to know there is another way.

Regards

Ismail

Ismail Mayat United Kingdom

2/1/2011 4:48:58 PM #

Sacha,

Like the article. Can you tell a bit more about the "wrapping" of the site in a web application project. How do you do it?

The way I do it now, it consits of a lot of manual steps. Would like to know if there's a better way.

Thanks,
Vincent

Vincent Baaij Netherlands

2/1/2011 7:27:27 PM #

Hi

I have been doing this on a few older umbraco sites, however when I started using 4.5+ I started getting weird "null reference" errors when trying to get data from the umbraco backend. Like for instance Node.GetCurrent().

It would return null instead of the current node object.

I suspected that it was because the order things got initialized in the umbraco beckend compared to the codebehind files of the templates. and stopped doing it.

I liked the concept though.

After reading this I will try having a go with v4.6.1 and see if I can get it working again.

Thomas Denmark

2/1/2011 7:34:09 PM #

@Vincent Baaij

1: Create a new web project in VS.
2: Remove the default content.  (Default.aspx, App_data, etc)
3: Unzip the umbraco files into the VS project folder.
4: Click the "view all files" button in solution explorer.
5: Right click and "include in project" on the following folders:
css, masterpages, scripts, usercontrols (Add other folders as needed if you have to modify other files.)
6: Set the default.aspx as start page by right clicking it.

And you should be good to go :) Now you can run the web project like normal in VS, and debug you code directly, without having to "attach to process"

Thomas Denmark

2/2/2011 4:20:54 AM #

@Thomas: thanks for the info about receiving null back from the Umbraco API, I'll watch out for that :)

@Vincent: the other alternative (or slight modification) to Thomas perfectly correct way is to create a web application instead of a web site, which means primarily that your code gets compiled before deployment. However this solution has one major downfall: as the project gets compiled you need to manually reference the Umbraco DLLs in the /bin folder from somewhere else so they get copied over to the /bin folder each time you compile. The other Umbraco files can be treated as static files (e.g. content in /umbraco and /umbraco_client) and will never change, so you don't need to worry about that. So to achieve the same as Thomas's step-by-step guide yet by using a web application project you would do this (just copied and pasted from Thomas ;):
1: Create a new web application project in VS.
2: Remove the default content.  (Default.aspx, App_data, etc)
3: Unzip the umbraco files into the VS project folder.
3.a: create a DLL folder outside your application, copy over the contents in the /bin folder form the Umbraco zip and reference the DLLs in your web application; they will then be copied over as soon as you compile the app
4: Click the "view all files" button in solution explorer.
5: Right click and "include in project" on the following folders:
css, masterpages, scripts, usercontrols (Add other folders as needed if you have to modify other files.)
6: Set the default.aspx as start page by right clicking it.

In the end it doesn't really matter which one you choose. I prefer the application approach over the site approach, but I have to admit that I don't really have any good arguments for that... ;)

SaschaWolter Australia

2/2/2011 1:14:53 PM #

@Thomas and @Sacha

Thank you both!

Vincent Baaij Netherlands

2/4/2011 12:58:54 AM #

Hi again :)

I just ran a little test on v4.6.1 with one of the scenarios I know caused problems from template codebehind files earlier.

And it looks like its working again. :)

Thomas Denmark

2/18/2011 3:02:53 PM #

A little tip on easier or automatic creation of the designer file that you may wish to add to the post. So long as you have the CodeBehind and Inherits properties defined correctly in your master file you can right-click on the aspx page and choose "Convert to Web Application" and it will automatically generate and populate the designer file for you.

Simon Dingley United Kingdom

2/23/2011 4:37:27 AM #

Cheers Simon, that's great! :) Added to the post.

SaschaWolter United States

3/7/2011 1:31:10 PM #

Be just to all, but trust not all._<a href="www.jordansclicks.com/.../">Jordan V2 Grown</a>

Jordan V2 Grown Tunisia

6/9/2011 3:41:28 AM #

@Thomas

It would return null instead of the current node object.

This seems odd to me. What access level did you have on the property? Did you make the object public or protected or leave it with no access modifier? A method, field, or property will have a default access modifier as "Private" if no modifier is specified.

In which case the *.aspx file would not be able to access the property...

Kieran Harvey Australia