Hello ASP.Net World

Webmaster or web novice?

Next we are going to create a web application with one page that displays "Hello World!". In Hello Console World, we created some common code we are going to use here. You could create a new solution, but to keep things simple we are going to just continue with the one we already have. So here is a trick question - how many files will we need just to display "Hello World!" on a web page? If you answered "one", you should go back and read Hello Console World. Otherwise, you are on your way to being a true web "master" so read on.

Web site or web application?

If you are using Visual Web Developer Express, you won't have a choice so you will be creating a web site. Both have their advantages. Web sites compile pages individually and compile on-demand so you can make changes to individual pages and test them without recompiling the whole site. Web applications allow you to edit and continue while debugging. Also, references to other projects are much easier to manage when using a web application. Since the primary focus of this project is to show how, when, where, and why to use multiple projects, we are going to use a web application. Right-click on your solution and add a new project (not a new web site). Select "Web" as the project type and then select "ASP.NET Web Application". We are going to call this application "HelloRealWorld.WebApplication" (see Projects and Namespaces to find out why).

Just like we created a common library for our console application, we are going to assume that we are going to have some reusable web components as well, so lets add a class library and call it "HelloRealWorld.Web" and add a reference to System.Web and to our HelloRealWorld.Common library. Now add a reference to HelloRealWorld.Web to our HelloRealWorld.WebApplication. We are going to create a control to display "Hello World!" so let's delete "Class1.cs" and the create a folder called "Controls" in our web library and then create "WelcomeMessageControl.cs" in that folder. Notice that the namespace of this class is HelloRealWorld.Web.Controls. As we discussed in Projects and Namespaces, not only does it help you organize your code by using folders, but it also helps organize your code at time of use by adding additional levels to your namespaces.

Get under control

An easy way to create a custom web control is to create a composite control which allows you to combine several other controls into a single control. We are going to have this class inherit from the CompositeControl so let's change our class declaration to look like this:

public class WelcomeMessageControl : CompositeControl

Note that you will get a red underline under the last letter in CompositeControl. Now hit Alt-Shift-F10 and select "using System.Web.UI.WebControls;" by pressing enter. This will put the following code at the top of your file:

using System.Web.UI.WebControls;

Now how do we go about further customizing this control to do what we need? We just need to add a control to our custom control to display our welcome message. So here is how we do that. Just go into your class and type "override", press the spacebary, start typing "CreateChildControls()", and press enter when it appears and is selected by intellisense. The following code should appear:

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
        }


Now we will add a label to our control and set the text to our welcome message from our common library. First we need a variable to hold our label so let's create a field by add the following code to the top of our class:

private Label label;

Why private? We don't want any code outside of our class or any class which inherits from our class to have direct access to this Label control. Now modify the CreateChildControls method to look like the following:

protected override void CreateChildControls()
{
this.label = new Label();
this.label.Text = Common.ContentManager.WelcomeMessage;
Controls.Add(this.label);
}

Once again, let's let code analysis and StyleCop tell us what is wrong. Just like in Hello Consle World, we need to strongly sign our assembly, and add assembly: CLSCompliant(true) to our AssemblyInfo.cs. Let's remove some unnecessary using statements, add some comments, and now our completed class should look like this:

using System.Web.UI.WebControls;

namespace HelloRealWorld.Web.Controls
{
    /// <summary>
    /// Impliments CompositeControl to display the welcome message on a label.
    /// </summary>
    public class WelcomeMessageControl : CompositeControl
    {
        /// <summary>
        /// Label to contain welcome message.
        /// </summary>
        private Label label;

        /// <summary>
        /// Creates the Label control used to display the welcome message.
        /// </summary>
        protected override void CreateChildControls()
        {
            this.label = new Label();
            this.label.Text = Common.ContentManager.WelcomeMessage;
            Controls.Add(this.label);
        }
    }
}


Believe it or not that is all we need for our control so now compile your solution and you should be able to go into Default.aspx in your web application and drag and drop WelcomeMessageControl on to your page. Now right-click on Defalut.aspx and select "View in Browser" and we are done, right? Of course not! Let's go into the source view of our Default.aspx page and see what is wrong:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HelloRealWorld.WebApplication._Default" %>

<%@ Register assembly="HelloRealWorld.Web" namespace="HelloRealWorld.Web.Controls" tagprefix="cc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <cc1:WelcomeMessageControl ID="WelcomeMessageControl1" runat="server" />
    
    </div>
    </form>
</body>
</html>

As a whole, this is fine. There is one small problem - "cc1". Look at the second line of code:

<%@ Register assembly="HelloRealWorld.Web" namespace="HelloRealWorld.Web.Controls" tagprefix="cc1" %>

This is where the "cc1" comes from. We can use whatever we want - "cc1", "foo", "MyControls", etc. I like to choose an abreviation since it adds to the overall length of our control's name and then have that abreviation be unique to our controls to avoid conflicts with others. Let's change "cc1" to "hrw" for "Hello Real World" both in this line that registers the control and in the line that adds the control to the page. Take note of this syntax because in the future you can add this code to your code behind on any page and add your controls in the source view instead of using the designer.

The next problem is that the default name of our control is "WelcomeMessageControl1". Some people like using pascal case (upper case first letter with upper case first letter of each word) for the name of controls to indicate the difference between controls and other fields. However, in my opinion this allows controls which are typically protected or private to be easily confused with properties which are typically public or at least internal. I tend to use what I call "reverse-Hungarian Pascal Case" notation for controls. That means that I put the type of control in the end and have a lowercase first character. If this were a Label, I would use "welcomeMessageLabel", but since we created a custom control that is only going to be used once on the page, let's change "WelcomeMessageControl1" to "welcomeMessageControl". If we had multiple welcome message controls on a page we could name them "aaaWelcomeMessageControl" and "bbbWelcomeMessageControl" where "aaa" and "bbb" are some type of description of the purpose of the control.

Finally, we are assuming that you are putting your code-behind in a separate file (which I strongly recommend). The class in the code-behind that the page inherits from is called "HelloRealWorld.WebApplication.Default". This is a very unnatural class name and code analysis asks us to remove the underscore bfrom the beginning of the class name. The underscore is added by Visual Studio because "default" is a reserved word so the class can't be called "Default". So let's go into Default.aspx.cs and change the class name to "DefaultPage". After running StyleCop and code analysis, we will find out that we need to add assembly: CLSCompliant(true) to AssemblyInfo.cs, add some comments, and remove the blank line in the PageLoad method. After we remove some unnecessary using statements, our Default.aspx.cs looks like this:

using System;

namespace HelloRealWorld.WebApplication
{
    /// <summary>
    /// Code for the Default.aspx page.
    /// </summary>
    public partial class DefaultPage : System.Web.UI.Page
    {
        /// <summary>
        /// Handles the Load event.
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event args</param>
        protected void Page_Load(object sender, EventArgs e)
        {
        }
    }
}


Our final aspx file looks like this:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HelloRealWorld.WebApplication.DefaultPage" %>

<%@ Register assembly="HelloRealWorld.Web" namespace="HelloRealWorld.Web.Controls" tagprefix="hrw" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <hrw:WelcomeMessageControl ID="welcomeMessageControl" runat="server" />
    
    </div>
    </form>
</body>
</html>

Override or use events?

Many custom control examples you will find on-line (especially Windows forms controls) will use event handlers to add custom code to an event in a custom control. While this is acceptable, it is difficult to determine when that event handler is fired and depending on where the event handler is wired up you can get some unexpected results. Event handlers are fired in the order in which they are added and perhaps more importantly they can consume events. That means that under certain conditions event handlers can cause other handlers to not fire at all.

Let's compare that to overriding the method which raises the event and we will do that by example. If you create any class that inherits from System.Web.UI.Control (or any web control that inherits from Control) and type "override", hit the spacebar, and then start typing "OnPreRender" and press enter when intellisense brings up this method. The following code should appear:

        protected override void OnPreRender()
        {
            base.OnPreRender();
        }


Now hover your mouse over "base.OnPreRender()" and you should see "Raises the System.Web.UI.Control.PreRender event". This means that any code in front of this line of code will be called before the control raises the event and vice versa.

Last edited Jul 13, 2009 at 3:42 AM by douglampe, version 7

Comments

No comments yet.