UserControls as Include Files
The question of include files often comes up from people who are new to ASP.NET and may come from a PHP or even a Classic ASP background where script include files are often used. In this article I will explain how to use UserControls which is the closest thing we have to include files in ASP.NET and can typically be used to solve the same kinds of problems that include files are used for.
Why Don't We Have Include Files? Compiled Languages vs Scripting Languages
Include files are a common way of organizing script files into re-usable chunks of script and/or markup. The reason we don't have them in ASP.NET is that ASP.NET is not a scripting language like PHP or Clasic ASP. Scripting languages are interpreted at runtime. In ASP.NET we have several languages available such as C# (mojoPortal is written in C#) and VB.NET, neither of which is a scripting language, they are not interpeted at runtime, they are compiled and executed. Most of the C# code in mojoPortal is pre-compiled into dll files in the /bin folder. However, these dlls are compiled into what is known as MSIL (Microsoft Intermediate Language) which is then finally just in time compiled to processor specific native code. Typically the just in time compiling happens when the web site gets its first few requests and then the compiled native code is cached. The advantages of compiled code are faster execution and since we have a strongly typed variable system, mistakes in code are often found at compile time whereas it is easier for mistakes in script to be overlooked until they cause a runtime error. However the compiled code model doesn't lend itself to include files in the same way that scripts do.
Situations where you might want to use an include file
In a recent forum post, a user who was working with the slide show example from the andreasviklund-02-alt1 skin. She wanted to be able to move the slide show out of layout.master into an include file. The markup for the slideshow in the head of that skin exists in the layout.master file and is intended to illustrate how to use the slideshow in a skin. The specific markup for the slide show in layout.master of that skin is like this:
<portal:SlidePanel id="spanel1" runat="server" CssClass="rotatecontainer">
<portal:SkinFolderImage ID="imgs1" runat="server" ImageFileName="head1.jpg" CssClass="rotateitem" AlternateText=" " />
<portal:SkinFolderImage ID="imgs2" runat="server" ImageFileName="head2.jpg" CssClass="rotateitem" AlternateText=" " />
<div class="rotateitem">
<asp:Image id="img4" runat="server" CssClass="floatrightimage" AlternateText=" " Height="60" ImageUrl="~/Data/logos/mojothumb.jpg" />
<p>lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor
lorem ipsum dolor </p>
</div>
<portal:SkinFolderImage ID="imgs3" runat="server" ImageFileName="head3.jpg" CssClass="rotateitem" AlternateText=" " />
</portal:SlidePanel>
UserControl to the Rescue
An ASP.NET UserControl in it's simplest form can be a single text file with a .ascx extension. It can contain other controls, html markup, and code. The code can also be stored in a separate code behind file, but in this case we will keep it as simple as possible and use a single file to encapsulate the slide show. First create a folder beneath the root of the web to keep any custom UserControls organized in one place. For example I created a folder named MyControls, in the folder I created a new text file named HeaderSlideShow.ascx, the full contents of the file are as follows:
<%@ Control Language="C#" AutoEventWireup="true" ClassName="HeaderSlideShow.ascx" Inherits="System.Web.UI.UserControl" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
}
</script>
<portal:SlidePanel id="spanel1" runat="server" CssClass="rotatecontainer">
<portal:SkinFolderImage ID="imgs1" runat="server" ImageFileName="head1.jpg" CssClass="rotateitem" AlternateText=" " />
<portal:SkinFolderImage ID="imgs2" runat="server" ImageFileName="head2.jpg" CssClass="rotateitem" AlternateText=" " />
<div class="rotateitem">
<asp:Image id="img4" runat="server" CssClass="floatrightimage" AlternateText=" " Height="60" ImageUrl="~/Data/logos/mojothumb.jpg" />
<p>lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor
lorem ipsum dolor </p>
</div>
<portal:SkinFolderImage ID="imgs3" runat="server" ImageFileName="head3.jpg" CssClass="rotateitem" AlternateText=" " />
</portal:SlidePanel>
Note that for this example we are not running any actual custom code, so we could have left out the <script runat="server"> </script> completely, I just left it in there to show how code can be included, but to use code you need to learn C# or VB.NET.
So, now we can think of this UserControl as an include file that contains our slide show for the header of our skin, the next step is to learn how to plug it into the layout.master file. The first step is to declare our control at the top of the layout.master file so that it knows what it is and how to find it. So we add this to the top of layout.master just above the <!DocType> declaration:
<%@ Register TagPrefix="me" tagName="Slides" src="~/MyControls/HeaderSlideShow.ascx" %>
Next, we simply replace the previous slideshow markup with this:
<me:Slides id="mySlides" runat="server" />
Note that the tag prefix and tagName are arbitrary. you should probably use a consistent prefix for all your custom UserControls and use tagNames that are meaningful to you. You need to avoid using prefixes already in use, like you should not use "asp" or "portal", make soemthing up that will be unique for your TagPrefix and don't re-use TagNames.
You do need to be careful when making UserControls, if you make a typo or do something incorrectly it can cause an error and fail to load the UserControl or potentially even crash the site until you remove the UserControl. Typically any error will be logged in the mojoPortal log and may give clues about the error. You can check the log from Administration > System Log or by downloading the /Data/currentlog.config file. Newest errors are at the bottom of the file.
2010-06-27 Joe Audette