In this second of a two-part series, Dwight takes us through the new ASP.NET Architecture. We learn about ASP.NET's System.Web.UI namespace classes, interfaces, enumerations, and delegates. We also learn about the ASP.NET page class, including a close look at the life cycle of an ASP.NET page, applying page directives, and the code-behind feature. This piece comes from chapter six of February's Developer Shed Writing Contest prize, .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223-054-1, 2004).
Let’s create a new project in Visual Studio .Net. Begin by creating a virtual directory called MyASP.NETPages. Then open Visual Studio .NET and create the new ASP.NET web application project called IFCE. Initially, the location where the application will be stored looks like this: http://localhost/WebApplication1. Rename it to the correct project name, “IFCE.” Also, rename public class1 to Register. Notice how public class Register inherits from class System.Web.UI.Page. The next item of interest, Private Sub InitializeComponent(), calls the subroutine InitializeComponent(). Next, Private Sub Page_Init(ByVal sender as System.Object, ByVal e as System.EventArgs) Handles MyBase.Init initializes the page.
Public
Class Register Inherits System.Web.UI.Page #Region "Web Form Designer Generated Code" 'This call is required by the Web Form Designer. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() End Sub 'NOTE: The following placeholder declaration is required by the Web Form Designer. 'Do not delete or move it. Private designerPlaceholderDeclaration As System.Object Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init 'CODEGEN: This method call is required by the Web Form Designer 'Do not modify it using the code editor. InitializeComponent () End Sub #End Region End Class
WebForm1.aspx displays the code-behind feature. Inside the ASP.NET script delimiters, the page language is VB; the CodeBehind is Web Form1.aspx.vb. The code indicates that the web form inherits from the IFCE WebForm1. The form ID is Form1; the method is Post, specifying that the page must run on the server.
Next, click on the Register icon in the Solution Explorer and select View Designer. Then, click on the Toolbox icon and drag a label onto the web form. Select the label’s properties and type RegisterClient to the right of the text property. Finally, compile the application, and the label will display in Internet Explorer as follows:
Register Client
This has been part two of ASP.NET Architecture (see part 1 here), chapter six of .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223054-1, 2004).
Although this ASP.NET server page does not allow for any user interaction, it does demonstrate browser-based application functionality in its most elementary form.
The Global.aspx.vb file contains information about the sequence of events and when they fire. The file begins by importing System.Web and the System.Web.SessionState. Public Class Global inherits the System.Web.HttpApplication class. After the InitializeComponent() method performs its task and allows for any other initialization, several events fire. The first event is the Application_Start method. The next event, Session_Start, fires, followed by the Application_BeginRequest method, which fires at the beginning of each subsequent request. Then the Application_AuthenticateRequest method fires. Other methods include Application_Authentication, Application_Error, Session_End, and Application_End. Here is the Global.aspx.vb file:
Imports System
.Web Imports System.Web.SessionState Public Class Global Inherits System.Web.HttpApplication #Region " Component Designer Generated Code " Public Sub New() MyBase.New() 'This call is required by the Component Designer. InitializeComponent() 'Add any initialization after the InitializeComponent() call End Sub
'Required by the Component Designer Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Component 'Designer 'It can be modified using the Component Designer. 'Do not modify it using the code editor. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() components = New System.ComponentModel.Container() End Sub
#End Region
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) 'Fires when the application is started End Sub Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) 'Fires when the session is started End Sub Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) 'Fires at the beginning of each request End Sub Sub Application_AuthenticateRequest (ByVal sender As Object, ByVal e As EventArgs) 'Fires upon attempting to authenticate the user End Sub Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs) 'Fires when an error occurs End Sub Sub Session_End(ByVal sender As Object, ByVal e As EventArgs) 'Fires when the session ends End Sub
Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
'Fires when the application ends End Sub
End Class
The lesson learned from examining this file is that the ASP.NET execution works entirely differently from classic ASP pages. Every .aspx page is automatically converted to a class and subsequently compiled to an assembly the first time it is accessed by a client. Expect some latency (delay) from this scenario.
When the user accesses the page, the generated assembly executes and creates an instance of that page. The page object provides a method for each event and generates output that is ultimately sent to the client’s browser.
This has been part two of ASP.NET Architecture (see part 1 here), chapter six of .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223054-1, 2004).
The following ASP.NET browser-based application shows how to enter data and display it back to an ASP.NET label control.
Open Visual Studio .NET and create a new project. Select Visual Basic Projects and click on the Web Application icon. Provide a project name such as RegisterNewClient. Then, select the machine where you wish to create the web site. Click OK to begin the process of creating a new web application. Rename WebForm1 to RegisterNewClient.aspx. Next, select the Toolbox and create the form with the appropriate controls itemized in Table 2.
Control Type
Property
Value
Label
Name
Label1
TextBox
Name Text
txtFirst
Label
Name Text
Label2
TextBox
Name Text
txtLast
Label
Name Text
Label2
Button
Name Text
btnSubmit
Table 2Creating a Web Input Form
Once you verify that this form runs properly, right-click the Register.aspx page and click Set as Start Page. Run the form, and you will be able to enter data in the text fields. Then, click the Register button so the browser will render your page. However, you will not see anything you entered because the page does not contain instructions to do anything yet. Double-click the Register button and enter the following code:
Private Sub btnSubmit_Click
(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSubmit.Click lblName.Text = txtLast.Text & ", " & txtFirst.Text End Sub
Run Register.aspx again, and the result displays in the label as “Peltzer, Dwight.” You have retrieved the data you just entered in the Last Name and First Name text boxes and placed the text in the label control.
This has been part two of ASP.NET Architecture (see part 1 here), chapter six of .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223054-1, 2004).
ASP.NET divides the built-in server controls in two groups: HTML controls and web controls. Each is contained within its own namespace. HTML controls map one to one with standard HTML elements, whereas some elements do not map to a specific HTML control. You have the option of changing the functionality of a page at runtime by modifying the control’s attributes programmatically. Creating a user control is new to ASP.NET. User controls consist of HTML markup or ASP.NET code that bears the .ascx file extension. You can employ the @ Control directive to specify precisely how a control behaves on the web form. A caveat to employing user controls is that you cannot call them directly. They must reside on an already existing page. In addition, user controls should not contain <html>, <body>, or <form> elements primarily because they are already present on the page where your control is placed. You can strong type the control programmatically by adding the ClassName attribute as follows:
<%@ Control ClassName="RegisterClient" %>
Let’s create a user control and see how easy it is to do.
<%@ Control ClassName="RegisterClient" %> <script language="vb" runat="server" %> Private name As String = "" Public Property Name As String Get Return name End Get
Set name = Value End Set End Property
Public Sub GreetClient() Label1.Text = "Please register to use our services", & name End Sub </script> <asp:Label id="Label1" runat="server"></asp:Label>
The file should be saved as Register.ascx and stored in your Internet Information Services virtual directory.
The code declares a string variable called name; then a property procedure called Name sets and retrieves the value of the variable. Finally, a Sub procedure called GreetClient() sets the Text property of the Label server control.
This has been part two of ASP.NET Architecture (see part 1 here), chapter six of .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223054-1, 2004).
Two methods exist for adding the control to a web form page. The first method allows you to place the control declaratively. Create a new web form page called GreetContainer.aspx, and place it in the virtual directory where you saved Register.ascx. Write the following code:
<%@ Page Language = "vb" %> <%@ Register TagPrefix = "ASPNETsbtn" TagName=RegisterClient" Src = "Register.ascx" %> <html> <head> <script runat="server"> Sub Page_Load(Sender as Object, E As EventArgs) MyRegister.Name = "Steve" MyRegister.GreetClient End Sub </script> </head> <body> <ASPNETsbtn:RegisterClient id= "MyRegister" runat ="server"/> </body> </html>
The output is as expected:
Please register to
use our services, Steve
Adding a User Control Programmatically
Adding a user control to a web forms page programmatically is similar to the declarative method, but with a few changes. Create a new web forms page named RegisterMoreClients.aspx. Then, save it to the same directory as you did previously:
<%@ Page Language = "vb" %> <%@ Reference Control = "Register.ascx" %> <html> <head> <script runat="server"> Sub Page_Load(Sender As Object, E as EventArgs) Dim MyRegister As Control = LoadControl("Register.ascx") RegisterHolder.Controls.Add(MyRegister) CType(MyRegister.Register).Name = "Steve" CType(MyRegister.Register).GreetClient End Sub </script> </head> <body> <asp:placeholder id="Referenceholder" runat="server"/> </body> </html>
The @ Reference directive tells ASP.NET to compile and link the user control Register.ascx with the page when compiled. The Placeholder control allows you to insert a placeholder in the HTML markup so you can add a control to a specific location on the page. Reference the saved page just as you did previously from the Internet Services Manager. Right-click this page, and select Browse to render the page to the browser.
This has been part two of ASP.NET Architecture (see part 1 here), chapter six of .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223054-1, 2004).
Server controls can be placed on a web forms page. You can add an HTML control to the page by referencing the System.Web.HTMLControls namespace. Here is how you would add your HTML control to the page:
By adding the runat = “server”, you can access the control programmatically on the server side. As you will recall, the server-side <form> causes the page to post back to the server when the user clicks the Submit button.
Web Controls
The syntax for adding a web control is slightly different from syntax for an HTML control. Instead of defining your own tag prefix, use the asp prefix. Here is how you add a web control to the page:
<asp: TextBox id = "myTextBox" runat = "server" />
Let’s add a TextBox control and two web labels to a server-side form. Write the following code to the ServerSideControl.aspx page beginning with the <html> tag:
<html> <head> <script runat="Server"> Sub Page_Load(Sender As Object, E As EventArgs) If Is PostBack Then GreetingsLabel.Text = "Greetings, " & _ Server.HTMLEncode(MyNameTextBox.Text) End If End Sub </script> </head> <body> <form runat="Server"> <asp:Label id = "MyNameLabel" runat="server">Name: </asp:Label> <asp:TextBox id="MyNameTextBox" runat="Server"/> <input id="MyNameButton" type="submit" runat="server"/> </form> <asp:Label id = "GreetingLabel" runat = "server"/> </body> </html>
If you run this page, you can enter text in the TextBox control and submit the page. After the post back occurs, provide the proper URL and view the page.
NOTE:Assuming you set the AutoEventWireup to true, if you manually write your code in a text editor such as Notepad, youmust set the AutoEventWireup attribute to true. If Visual Studio .Net generates the page, by default this attribute is set to false. This indicates that all event handlers must be manually wired to the events they will handle.
Handling Events in the Server Control
An event handler was provided for the Page_Load event in the previous example. The event handler checks the IsPostBack page property to determine whether a post back occurs because the user has interacted with the Submit button. If this evaluation is true, set the Text property for the label to the appropriate text. In addition, employ the Server.HtmlEncode methodology to encode your text.
Note that when you add an event handler for the Load stage, you should check the IsPostBack page-level property. Handling Control events is slightly different. In this scenario, apply the controlname_eventname instead. Here is an example:
Sub NameTextBox_TextChanged
(Sender As Object, E As EventArgs)GreetingLabel.Text &=" your name has changed" End Sub
Next, add the following attribute to your NameTextBox server control tag:
<asp:TextBox id ="NameTextBox" onTextChanged = "NameTextBox_TextChanged" runat="server"/>
This has been part two of ASP.NET Architecture (see part 1 here), chapter six of .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223054-1, 2004).
The Page_Error handler helps manage error handling at the page level. Whenever the page encounters an error, it generates an exception. You can scrutinize the error by applying the Server.GetLastError method. This is invaluable when trying to trace the error to its source.
System.Exception is the base class for all exceptions. When an error occurs, either the system or the executing application throws the exception in a “try, catch” block. Once the exception is thrown, the application handles it by employing the default exception handler.
If you consider how the classicWindows applications handle security, the user has the option of deciding whether to let the executable run or not. For example, if you download some code from the Internet and allow the code to run, you have no control over what the executable actually does. The .NET Framework removes this option and places the application security within the assembly itself.
The assembly defines type scope as well as an assembly’s security boundary, so to speak. The CLR implements two distinct types of security:
Code access security
Role-based security
The .NET code access security has two criteria: permissions that the code requests and what permissions are based on the security policy in effect when the code executes. An assembly interacts with the CLR in numerous ways. It can request the specific permissions it requires for executing in a given environment. Here are some permissions an assembly can request:
UI Permission Permits access to a specified interface
FileIOPermission Allows access to both files and directories
EnvironmentPermission Enables access to environment variables
ReflectionPermission Provides access to metadata residing within the assembly
SecurityPermission Permits granting access to a group of permissions
WebPermission Manages Internet connections
You have two methods for embedding security permissions within an application: a declarative method and an imperative method.With the declarative method, you can write security code attributes in your code. The attributes become part of the metadata for the assembly. The imperative method lets you insert security permissions dynamically at runtime. The CLR inspects application security requests and compares them with any existing machine security roles. If the security permissions only allow read access to metadata or to specified files or directories, the assembly denies any further access.
An assembly provides several pieces of information about itself:
The assembly’s identity contains a digital signature generated by its publisher.
The assembly’s identity is represented by its strong name.
The assembly specifies the exact URL from which an assembly was downloaded.
The assembly identifies the zone defined by Internet Explorer. It reveals the exact source from which the assembly was downloaded.
When the assembly loads, the CLR examines permissions requested by the assembly. Subsequently, the assembly receives permissions specified by the security role in effect for a machine on which the assembly resides.
Role-based security allows the CLR to restrict what permissions are granted based on the assembly’s name, its origin, and who published it. Code access security makes no provisions for controlling the behavior of an assembly based on a user’s identity. Rather, the Object contains all information concerning the object’s identity and roles to which the object is assigned. If you consider the classic Windows method for assigning a role to a user or user group, you can fully understand what role-based security is.
This has been part two of ASP.NET Architecture (see part 1 here), chapter six of .NET & J2EE Interoperability, by Dwight Peltzer (McGraw-Hill/Osborne, ISBN 0-07-223054-1, 2004).