Walkthrough: Developing and Using a Custom Web Server Control
This walkthrough shows you how to create and test a custom ASP.NET Web server control.
In this walkthrough you will learn how to:
Create an ASP.NET Web server control.
Specify security settings and design-time behavior by adding metadata to the control.
Specify a tag prefix in a configuration file and in the control's assembly.
Specify an icon to use for the control in the Visual Studio toolbox.
Compile the control into an assembly and add a project reference so that it can be used in another project in the same solution.
Test the control in a Web page and access its properties by using the Properties window or IntelliSense.
A Visual Studio solution with source code is available to accompany this topic: Download.
Creating the Server Control
You will create a simple control that derives from the standard Label control. The control is named WelcomeLabel. It appends the user's name to the text string that is defined in the Text property. For example, if the page developer sets "Hello" as the value of the Text property, the WelcomeLabel control renders "Hello, userName!"
The control defines a DefaultUserName property that specifies the user name value to use when the user is not logged in. For example, if the page developer sets the Text property to "Hello" and the DefaultUserName property to "Guest", the control displays "Hello Guest!" if the user is not logged in.
To create the custom server control
From the File menu select New Project.
The New Project dialog box is displayed.
Under Installed Templates, expand Visual Basic or Visual C#, and then select Web.
Select the ASP.NET Server Control template.
In the Name box enter ServerControl1.
The New Project dialog box resembles the following illustration.
Click OK.
Visual Studio creates a server control project that has a class file that is named ServerControl1.cs or ServerControl1.vb.
Rename ServerControl1.cs or ServerControl1.vb to WelcomeLabel.cs or WelcomeLabel.vb.
A dialog box asks if you want to rename all references to ServerControl1, as shown in the following illustration.
Click Yes.
Open WelcomeLabel.cs or WelcomeLabel.vb.
Change the WelcomeLabel class so that it inherits from System.Web.UI.WebControls.Label instead of from System.Web.UI.WebControls.WebControl.
In the ToolboxData attribute for the WelcomeLabel class, change the string "ServerControl1" to "WelcomeLabel" in both places where it occurs.
Delete the code that is in the WelcomeLabel class, and insert a DefaultUserName property and a RenderContents method as shown in the following example:
Imports System.Drawing Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Text Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls <DefaultProperty("Text")> _ <ToolboxData("<{0}:WelcomeLabel runat=server></{0}:WelcomeLabel>")> _ Public Class WelcomeLabel Inherits Label < _ Bindable(True), _ Category("Appearance"), _ DefaultValue(""), _ Description("The welcome message text."), _ Localizable(True) _ > _ Public Overridable Property DefaultUserName() As String Get Dim s As String = CType(ViewState("DefaultUserName"), String) Return If((s Is Nothing), [String].Empty, s) End Get Set(ByVal value As String) ViewState("DefaultUserName") = value End Set End Property Protected Overrides Sub RenderContents( _ ByVal writer As HtmlTextWriter) writer.WriteEncodedText(Text) Dim displayUserName As String = DefaultUserName If Context IsNot Nothing Then Dim userName As String = Context.User.Identity.Name If Not String.IsNullOrEmpty(userName) Then displayUserName = userName End If End If If Not String.IsNullOrEmpty(displayUserName) Then writer.Write(", ") writer.WriteEncodedText(displayUserName) End If writer.Write("!") End Sub End Class
using System.Drawing; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace ServerControl1 { [DefaultProperty("Text")] [ToolboxData("<{0}:WelcomeLabel runat=server></{0}:WelcomeLabel>")] public class WelcomeLabel : Label { [ Bindable(true), Category("Appearance"), DefaultValue(""), Description("The text to display when the user is not logged in."), Localizable(true) ] public virtual string DefaultUserName { get { string s = (string)ViewState["DefaultUserName"]; return (s == null) ? String.Empty : s; } set { ViewState["DefaultUserName"] = value; } } protected override void RenderContents(HtmlTextWriter writer) { writer.WriteEncodedText(Text); string displayUserName = DefaultUserName; if (Context != null) { string userName = Context.User.Identity.Name; if (!String.IsNullOrEmpty(userName)) { displayUserName = userName; } } if (!String.IsNullOrEmpty(displayUserName)) { writer.Write(", "); writer.WriteEncodedText(displayUserName); } writer.Write("!"); } } }
In Solution Explorer, expand Properties and open AssemblyInfo.cs or expand My Project and open AssemblyInfo.vb. (You might have to click Show All Files to be able to expand My Project.)
At the beginning of the file, add the following line:
Using System.Web.UI;
Imports System.Web.UI
This namespace is required for the TagPrefixAttribute attribute that you will add in the following step.
At the end of the file, add the following line:
[assembly: TagPrefix("ServerControl1", "aspSample")]
<Assembly: TagPrefix("ServerControl1", "aspSample")>
This TagPrefixAttribute attribute creates a mapping between the namespace ServerControl1 and the prefix aspSample.
Save the WelcomeLabel.cs or WelcomeLabel.vb file.
Code Discussion
The following sections explain the code that you created in the preceding procedure.
Inheriting from the WebControl Class
If your control renders a user interface (UI) element or any other visible element on the client, you should derive your control from System.Web.UI.WebControls.WebControl or a from class that derives from it. (In this example the custom control derives from Label, which in turn derives from System.Web.UI.WebControls.WebControl.) If your control renders an element that is not visible in the client browser, such as a hidden element or a meta element, derive your control from System.Web.UI.Control. The WebControl class derives from Control and adds style-related properties such as Font, ForeColor, and BackColor. In addition, a control that derives from WebControl participates in the themes feature of ASP.NET without any extra work on your part.
The DefaultUserName Property
The WelcomeLabel control defines one property, DefaultUserName, and the control uses view state to persist the value of this property across postbacks. On each postback, the page is re-created and values are restored from view state. If the DefaultUserName property value were not stored in view state, the value would be set to its default, Empty, on each postback. The ViewState property, which is inherited from WebControl, is a dictionary that saves data values. Values are entered and retrieved using a String key. In this case, "DefaultUserName" is used as the key. Items in the dictionary are typed as Object, and when you access them, you must cast them to the actual property type. For more information about view state, see ASP.NET State Management Overview.
The RenderContents Method
The WelcomeLabel control writes text to the response stream by overriding the inherited RenderContents method. The parameter that is passed into the RenderContents method is an object of type HtmlTextWriter, which is a class that has methods for rendering HTML.
Notice that the WelcomeLabel control makes successive calls to the HtmlTextWriter object's Write method instead of performing string concatenation and then invoking the Write method. This improves performance because the HtmlTextWriter object writes directly to the output stream. String concatenation requires time and memory to create the string, and then writes to the stream.
In general, when your control derives from WebControl and renders a single element, you should override the RenderContents method (and not the Render method). The Render method of WebControl invokes RenderContents after rendering the opening tag for the control and its style attributes. If you override the Render method to write contents, your control will lose the style-rendering logic that is built into the Render method of WebControl. For more information about rendering a control that derives from WebControl, see Web Control Rendering Example.
Attributes of the Control
The attributes that are applied to the WelcomeLabel control and to the DefaultUserName property contain metadata that is used by the common language runtime and by design-time tools. At the class level, WelcomeLabel is marked with the following attributes:
DefaultPropertyAttribute. This is a design-time attribute that specifies the default property of a control. In visual designers, the property browser typically highlights the default property when a page developer clicks the control on the design surface.
ToolboxDataAttribute. This specifies the format string for the element. The string becomes the control's markup when the control is double-clicked in the toolbox or dragged from the toolbox onto the design surface. For WelcomeLabel, the string creates the following element:
<aspSample:WelcomeLabel runat="server"> </aspSample:WelcomeLabel>
The WelcomeLabel control also inherits two attributes from the WebControl base class: ParseChildrenAttribute and PersistChildrenAttribute. These attributes are applied as ParseChildren(true) and PersistChildren(false). The attributes work together and with the ToolboxDataAttribute attribute so that child elements are interpreted as properties and properties are persisted as attributes.
Attributes of the DefaultUserName Property
The following attributes that are applied to the DefaultUserName property of WelcomeLabel are design-time attributes that you typically apply to all public properties of your controls:
BindableAttribute. This specifies for visual designers whether it is meaningful to bind the property to data. For example, in Visual Studio, if a property is marked with Bindable(true), the property is displayed in the DataBindings dialog box. If a property is not marked with this attribute, the property browser infers the value to be Bindable(false).
CategoryAttribute. This specifies how to categorize the property in the visual designer's property browser. For example, Category("Appearance") tells the property browser to display the property in the Appearance category when the page developer uses the category view of the property browser. You can specify a string argument that corresponds to an existing category in the property browser, or you can create your own category.
DescriptionAttribute. This specifies a brief description of the property. In Visual Studio, the property browser displays the description of the selected property at the bottom of the Properties window.
DefaultValueAttribute. This specifies a default value for the property. This value should be the same as the default value you return from the property accessor (getter). In Visual Studio, the DefaultValueAttribute attribute enables a page developer to reset a property value to its default by displaying the shortcut menu in the Properties window and clicking the Reset button.
LocalizableAttribute. This specifies for visual designers whether it is meaningful to localize the property. When a property is marked Localizable(true), the visual designer includes the property value when the property is serialized as a resource. The designer will persist the property value to the culture-neutral resource file or to another localization source when the control is polled for localizable properties.
Design-time attributes that are applied to a control and to its members do not affect how the control functions at run time. However, they enhance the developer experience when the control is used in a visual designer. For a complete listing of design-time and run-time attributes for server controls, see Metadata Attributes for Custom Server Controls.
The Tag Prefix
A tag prefix is the prefix (such as "asp" in <asp:Table />) that appears before a control's type name when the control is created declaratively in a page. To enable your control to be used declaratively in a page, you must map a tag prefix to your control's namespace. A page developer can provide a tag prefix/namespace mapping by adding a @ Register directive on each page that uses the custom control, as in the following example:
<%@ Register Assembly="ServerControl" TagPrefix="aspSample"
Namespace="ServerControl"%>
When you drag a custom server control from the toolbox to an .aspx page, Visual Studio automatically adds the Register directive.
As an alternative to using the @ Register directive in each .aspx page, you can specify the tag prefix/namespace mapping in the Web.config file. This is useful if the custom control will be used in multiple pages in a Web application. The following example shows a Web.config file that specifies a tag prefix for the ServerControl1 assembly.
<?xml version="1.0"?>
<configuration>
<system.web>
<pages>
<controls>
<add tagPrefix="aspSample" Assembly="ServerControl"
namespace="ServerControl">
</add>
</controls>
</pages>
</system.web>
</configuration>
Testing a Custom Server Control
In the following procedure you will complete the following tasks:
Create a Web site that you will use to test the server control that you created in the preceding procedure.
Add a reference in the Web site project to the Server Control project.
Add the WelcomeLabel control to the Toolbox.
Add an instance of the WelcomeLabel control to the Default.aspx page.
Run the Default.aspx page to see that the WelcomeLabel control works.
You begin by creating a Web site that you can use for testing.
This walkthrough uses a Web site project. You could use a Web application project instead. For information about the difference between these Web project types, see Web Application Projects versus Web Site Projects.
To create a Web site project to test the custom server control
In the File menu, click Add, and then select New Web Site.
The New Web Site dialog box is displayed.
Under Installed Templates, select Visual Basic or Visual C#, and then select the ASP.NET Web Site template.
Name the Web site TestWebSite and save it in a new folder that is under the ServerControl1 solution folder.
The New Web Site dialog box resembles the following illustration:
Click OK.
Visual Studio creates a Web site project, adds it to the ServerControl1 solution, and opens the Default.aspx page in Source view.
In Solution Explorer, right-click the Web site project and select Set as Startup Project.
In Solution Explorer, right-click the Web site project and select Add Reference.
The Add Reference dialog box is displayed.
Select the Projects tab, select the ServerControl1 project, and then click OK. The Add Reference dialog box is shown in the following illustration:
The next step is to add the server control to the toolbox so that you can use it in a Web page in the test Web site.
To add the WelcomeLabel control to the toolbox
From the Build menu, select Build Solution.
Visual Studio compiles the solution and copies the assembly that is created by the ServerControl1 project into the Bin folder of the TestWebSite project.
With the Default.aspx page still open, open the Toolbox window.
Right-click anywhere in the Toolbox window and then click Add Tab.
Name the new tab Server Control1.
Right-click the Server Control1 tab and then click Choose Items.
Select Browse and then browse to the Bin folder of the TestWebSite project.
Select ServerControl1.dll and then click Open.
The ServerControl1 assembly is added to the .NET Framework Components tab of the Choose Toolbox Items dialog box, as shown in the following illustration:
Click OK.
The WelcomeLabel control appears in the Server Control1 tab in the Toolbox.
You can now add the server control to a Web page and test the Web page.
To test the WelcomeLabel control
In the Default.aspx page, delete the text "Welcome to ASP.NET!" and in its place drag the WelcomeLabel control from the Toolbox.
Add Text and DefaultUserName attribute to the markup for the WelcomeLabel control and set it to "Welcome," as shown in the following example:
<aspSample:WelcomeLabel ID="WelcomeLabel1" runat="server" Text="Welcome" DefaultUserName="Guest"> </aspSample:WelcomeLabel>
Press CTRL-F5 to display the Web page in the browser.
The WelcomeLabel control displays "Welcome!", as shown in the following illustration:
Click the Log in hyperlink.
The Log In page is displayed.
Click the Register hyperlink.
The Create a New Account page is displayed, as shown in the following illustration.
Enter newuser as the user name, enter newuser@asp.net as the email address, enter a password, and then click the Create User button.
ASP.NET creates the new user account, logs you in as the new user, and returns to the home page. The WelcomeLabel control now displays "Welcome, newuser!", as shown in the following illustration:
Specifying an Icon for the Toolbox
Visual Studio typically uses a default icon to display a control in the toolbox, as shown in the following illustration:
As an option for your control, you can customize the appearance of your control in the toolbox by embedding a 16-by-16-pixel bitmap in your control's assembly.
To specify an icon for the Toolbox
Create or obtain a 16-by-16-pixel bitmap as the toolbox icon for your control.
Name the bitmap WelcomeLabel.bmp.
In Solution Explorer, right-click the ServerControl1 project, select Add Existing Item, and select the bitmap file.
In the Properties window, change the Build Action property for the bitmap file to Embedded Resource.
In Solution Explorer, right-click the ServerControl1 project and select Add New Item.
The Add New Item dialog box is displayed.
Select the Class template, name the file ResourceFinder.cs or ResourceFinder.vb, and then click Add.
The ResourceFinder.cs or Resourcefinder.vb file is opened.
Make the ResourceFinder class is sealed and internal (Friend and NotInheritable in Visual Basic), as shown in the following example.
Friend NotInheritable Class ResourceFinder End Class
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ServerControl1 { internal sealed class ResourceFinder { } }
Save and close the file.
Open the WelcomeLabel.cs or WelcomeLabel.vb file and add the following line to the beginning of the file:
Using System.Drawing;
Imports System.Drawing
This namespace is required for the ToolboxBitmapAttribute attribute that you will add in the following step.
In the WelcomeLabel class, add the ToolboxBitmapAttribute attribute and specify the WelcomeLabel.bmp file name with the ServerControl1 namespace prefix, as shown in the following example:
[DefaultProperty("Text")] [ToolboxData("<{0}:WelcomeLabel runat=server></{0}:WelcomeLabel>")] [ToolboxBitmap(typeof(ResourceFinder), "ServerControl1.WelcomeLabel.bmp")] public class WelcomeLabel : Label
<DefaultProperty("Text")> _ <ToolboxData("<{0}:WelcomeLabel runat=server></{0}:WelcomeLabel>")> _ <ToolboxBitmap(GetType(ResourceFinder), "ServerControl1.WelcomeLabel.bmp")> _ Public Class WelcomeLabel Inherits Label
Save and close the file.
From the Build menu, select Build Solution.
In the TestWebSite project, open the Default.aspx file.
In the Toolbox, right-click the WelcomeLabel control, and then select Delete.
Right-click the Server Control1 tab and then click Choose Items.
Select Browse and then browse to the Bin folder of the TestWebSite project.
Select ServerControl1.dll and then click Open.
The ServerControl1 assembly is added to the .NET Framework Components tab of the Choose Toolbox Items dialog box.
In the Choose Items dialog box, click OK.
The WelcomeLabel control reappears in the Server Control1 tab in the Toolbox. The icon that you selected appears to the left of the name WelcomeLabel, as shown in the following illustration.
Next Steps
This walkthrough showed you how to develop a simple custom ASP.NET server control and use it in a page. For more information, including information about rendering, defining properties, maintaining state, handling different browser or device types, and implementing composite controls, see Developing Custom ASP.NET Server Controls.
Complex controls such as the GridView control further enhance their design-time experience by using visual designer classes that provide a different user interface at design time and at run time. For more information about how to implement custom designer classes for your controls, see ASP.NET Control Designers Overview.