ASP.NET Web Applications


ASP.NET makes use of IIS web applications to identify distinct application domains . Application domains are a feature of the CLR. Each application domain is separate, secure, and does not share memory with other domains. For example, each of the three web applications Wrox1, Wrox2, and Wrox3 will be treated separately, so Wrox1 will not share data such as Session or Application state with the others, and likewise for Wrox2 and Wrox3. Many application domains may be hosted within a single process “ this is completely transparent thanks to the CLR.

You can think of an application domain as a logical process. When it fails, it doesn't take down the host process, so one failure won't crash all your ASP.NET applications. This is one of many new features provided by the CLR that ASP.NET takes advantage of.

An ASP.NET web application typically consists of three types of ( user -created ) resources, in addition to standard ASP.NET pages or web services. These resource types are always found in the root of the application, and include:

  • bin :This directory lies immediately below the root of the application, and is used to hold .NET assemblies to be used by the application. (An assembly is the technical term used to describe a component built with .NET. It is compiled reusable code, an example of which is System.Data.dll. ).

  • global.asax :This file is ASP.NET's logical replacement for the ASP file global.asa . It allows us to execute code for ASP.NET application-level events, and to set application-level variables .

  • web.config :Each web application can have its own ASP.NET configuration settings. These settings, depending upon the security configuration of the system, can override settings found in ASP.NET's machine.config .

    Note

    The machine.config file applies global default settings for all ASP.NET applications. We will cover ASP.NET configuration in more detail in Chapter 13.

Let's start by briefly looking at the ASP.NET bin directory, as it relates to ASP.NET web applications.

Registering Components

Rather than relying upon the system registry, ASP.NET uses a special directory ( bin) to register components as part of an application.

The next section illustrates the differences between classic ASP/COM component registration and the new ASP.NET/Assembly registration.

Prior to .NET

To use COM (reusable compiled code) in ASP, you always had to register the components on the server. For example, if you developed a simple data access component using Visual Basic 6 and wished to use it in an ASP application, you would need to explicitly register the component before you could use it.

Registering components was done either through a command line tool, regsvr32.exe , or with COM+ Services (Start Programs Administrative Tools Component Services). In either case, an entry was made in the Windows registry describing the component, its threading model, and the location of the .dll file. You could then write code in your ASP application using the erver.CreateObject method:

  <%   Dim myObject   Set myObject = Server.CreateObject("Example.DataAccess")   %>  

Behind the scenes, the ProgID (in this case Example.DataAccess ) would find the entry for the required component in the registry. Once found, an instance of the component would be created and a reference set to the local variable myObject .

This is all well and good, and many successful applications were (and still are!) built using this model. However, there are some caveats associated with using COM in ASP:

  • Deployment and update :Deploying the component to multiple servers and replacing running components requires local server access to perform the registration/un-registration.

  • Global registration and versioning :In addition to requiring local server access to manage the components, registered components are available to all applications on the server where the component is registered. Versioning the component can be rather difficult since the components are global to the server. So, they are most often versioned by ProgID , which in turn means changes must be made to the software using those newly versioned instances.

    Note

    One of the most common problems that ASP developers ran into when using COM was the 'locking' of components by IIS when they attempted to replace an existing DLL with a new version.

You will be pleased to know that these kinds of ASP/COM issues “ deployment, updates, global registration, and versioning “ are no longer a problem in ASP.NET.

.NET Components

As mentioned earlier, in .NET the term 'assemblies' is used to describe components “ packaged units of reusable, compiled code “ built with .NET. Unlike ASP, ASP.NET does not require local server access to register a component. Instead, you can simply copy your assemblies to an ASP.NET bin directory using FTP, DAV, XCOPY, and so on, collectively referred to as XCOPY deployment. Assemblies found in the bin directory are then automatically loaded by ASP.NET, and the components made available to your application.

Important

There can only be one bin directory per ASP.NET application.

Local Server Access Not Required

Deploying components in ASP.NET is simple. Local server access is not required and all you need is the ability to copy the compiled assembly to the bin directory. Once it is there, ASP.NET and the CLR takes care of everything else, and you can start using the component in your code right away.

So how does this type of registration work? Well, unlike a COM component, whose location and internal architecture need to be explicitly logged in the registry, a .NET assembly is self-describing . That is to say, the assembly's contents include meta data that describes exactly what the compiled component can and cannot do. All information required to successfully use that component is held in one place, and no extra configuration is required.

Components Are Application-Specific

Again, unlike ASP, the .NET components you register in a specific application's bin directory are only available to that application “ by contrast, classic ASP COM components were registered for the entire server.

Note

It is possible to register an assembly to be global for all applications using the Global Assembly Cache (GAC), which is covered in more detail in Chapter 23, but this is not the default behavior.

Component Updates

In ASP, if you wanted to replace a component, you needed to restart IIS since the component was loaded in the IIS process. ASP.NET never locks the file, and thus, you can simply delete or copy over the assembly when removing or changing the application “ a procedure that does not require local server access.

This dynamic loading and unloading of the components in the bin directory works because ASP.NET specifically listens for file change notification events within the bin directory. When a change is detected (such as the addition or deletion of a component), ASP.NET will create a new application domain to begin servicing the new requests . As soon as the original application domain has completed servicing any outstanding requests, it is removed.

As far as the client is concerned , this process is completely transparent, and for the developer, it means that updates can be implemented very simply without incurring any application downtime.

An Example Use

Let's look at a simple example using the Wrox web application. You will first need to create a bin directory, for example, C:\Wrox\bin . Then, you will write a simple ASP.NET page in Visual Basic .NET:

  <%@ Import Namespace="Component" %>   <%@ Import Namespace="System.Data" %>   <%@ Import Namespace="System.Data.SqlClient" %>     <Script runat="server">   Public Sub Page_Load()   Dim simpleComponent As New Simple()     Dim dataSet As New DataSet()   dataSet = simpleComponent.LoadDataSet()     datagrid1.DataSource = dataSet   datagrid1.DataBind()   End Sub   </Script>   <font size=6>   <asp:DataGrid runat="server" id="datagrid1"/>   </font>  

Let's look at implementing the Component.Simple assembly used in the preceding code. This simple page creates a new instance, simpleComponent, of an assembly named Simple . It then uses the LoadDataSet method of the simpleComponent to populate a DataSet , which is eventually used to data bind an ASP.NET datagrid server control.

At this point, if you request the page in your browser, you will receive an error message in the detailed compiler output, telling us:

error BC30466: Namespace or type 'Component' for the Imports 'Component' cannot be found.

This is because you have identified a namespace called Component that doesn't exist yet “ you will create it now.

Using either Visual Studio .NET or the command line compiler, you can create and compile a simple Visual Basic .NET component named Component.Simple , which will be responsible for implementing the LoadDataSet method “ here, we are going to build it using Visual Studio .NET.

Open Visual Studio .NET, and select File New Project. Select the Visual Basic Projects type and Class Library for the template. Name the project Component , and implement the following code in the Class1.vb file created as part of the project:

  Imports System.Data   Imports System.Data.SqlClient     Public Class Simple   Public Function LoadDataSet() As DataSet   Dim myConnection As SqlConnection   Dim myCommand As SqlDataAdapter   Dim products As New DataSet()   Dim sql As String   Dim dsn As String     sql = "SELECT address, city, state FROM Authors"   dsn = "server=localhost;uid=sa;pwd=;database=pubs"   myConnection = New SqlConnection(dsn)   myCommand = New SqlDataAdapter(sql, myConnection)   myCommand.Fill(products, "myAuthors")     Return products   End Function   End Class  

This Visual Basic .NET class named Simple implements the LoadDataSet method required by this ASP.NET page. Compile the Visual Basic .NET project by selecting Build Build Component. Now open Windows Explorer and navigate to the location where the project was created. Within this location is a bin directory, where you should find a .dll named Component.dll .

Simply copy the Component.dll file from this location to C:\Wrox\bin . That's all there is to it! The act of copying the file into an application's bin directory registers the component. Yes, it's that easy!

If you now request your simple ASP.NET page again, rather than throwing an error, it finds and uses the component, and returns an HTML table showing the address, city, and state (the columns selected in your Simple component).

So what if you now want to change the component? Perhaps you only want to return the address and state? Well, first you need to change the component's SQL text (as shown in the following snippet), and then you must re-compile it with Visual Studio .NET.

 sql = "SELECT address, state FROM Authors" 

Once again, copy the newly compiled component to the C:\Wrox\bin directory, and immediately request the ASP.NET page again. The response you see is an HTML table that only shows address and state. Behind the scenes, ASP.NET noticed that the old component was replaced , and restarted the application using the new one.

The bin directory dramatically changes the way ASP.NET web applications are built. You no longer require local server access to register components, and ASP.NET never locks those components. You can carry out updates and changes, and ASP.NET will simply restart the application using the new version without requiring you to do anything.

Now that you are somewhat familiar with the bin directory, let's move on to another part of the ASP.NET web application, global.asax .

Application Code “ global.asax

Like ASP, ASP.NET supports a global file for each web application. This file is used as an implementation point for global events, objects, and variables. If you are familiar with classic ASP, you will recognize this file as global.asa . ASP.NET supports a similar file, called global.asax .

Important

The code contained in global.asax constitutes part of our application. It does not contain application configuration information “ the web.config file deals with this, and is covered in the next chapter.

Running ASP.NET and ASP Together

ASP.NET's global.asax file uses a separate extension, distinct from ASP's global.asa file. The extension .asax is used so as not to interfere with ASP's global.asa . This means that both global.asa and global.asax can reside in the same web application root.

Microsoft worked very hard to ensure that installing ASP.NET does not break any existing ASP applications. However, a caveat of this is that they cannot share any resources. This applies to all ASP.NET and ASP resources, not just the global.asax / global.asa files. ASP.NET maintains its Application , Session , global events, and so on, in complete isolation from ASP. Additionally, in a manner similar to ASP, there can only be one global.asax file per web application, and it must be called global.asax .

Let's take a look at the global.asax file format.

File Format of global.asax

The global.asax file follows a similar format to ASP.NET pages. The following snippet is a simple template of what a global.asax file looks like:

  <%@ [Directive] [attribute]=[value] %>     <Script runat="server">   [Application Event Prototypes]   </Script>  

A global.asax file typically includes directives, events, and user code.

Directives

Similar to ASP.NET pages and web services, global.asax supports directives that provide ASP.NET with special instructions used in compilation of the global.asax file. The following code snippet is the prototype for directives “ note that multiple attribute/value pairs are supported:

 <%@ [directive name] [attribute]=[value] [attribute]=[value] %> 

global.asax supports three directives, each with its own settings:

  • Application : This allows us to define the base class global.asax will use. In addition to this, it supports a simple documentation option. These features are implemented through two attributes, Inherits and Description .

    • The Inherits attribute allows us to name a .NET class that global.asax will use as the base class for all compiled instances of global.asax . This is useful if we want to add our own methods or properties to global.asax . This is quite a powerful feature and one that we will discuss in more detail in the Advanced Topics section later in this chapter.

    • The Description attribute of the Application directive provides a simple way to add some descriptive text about our global.asax :

       <%@ Application Description="A sample global.asax description" %> 

      The value of Description is discarded when global.asax is compiled.

  • Import : This directive allows us to import .NET namespaces for use in global.asax , and makes all interfaces and classes of the imported namespace available to global.asax, without needing to fully qualify their names This directive is similar in function to the Imports keyword in Visual Basic .NET or using in C#. It simply provides a reference to a namespace that contains classes we wish to make use of.

  • To use the Import directive, we must guarantee that the assembly in which the namespace exists is also available. If it is not, an ASP.NET exception will occur when we run the application. Support for adding the assembly is done either through the Assembly directive or the <compilers> section of our configuration file (configuration is covered in the next chapter). To reference assemblies that are not available, we can use the Assembly directive, outlined next.

    The Import directive requires a single attribute:

    • The Namespace attribute of Import is used to identify an assembly namespace for use in global.asax . For example, we could use the Import directive, specifying the namespace attribute for the System.Data namespace.

       <%@ Import namespace="System.Data" %> 

      If we include this directive in the global.asax file for our web application, we can use classes in System.Data without fully qualifying the class name.

      For example, to use the DataSet class, we can refer to it as System.Data.DataSet (fully qualified class name), or use the Import directive naming the System.Data namespace and refer to the class simply as DataSet .

    Using the Import directive and its Namespace attribute saves us from having to fully qualify the name of the class. However, in the event that two namespaces share a common class name (such as Math ) we can't use the Import directive. Instead, we have to fully qualify the names when we use them, for example, Simple.Math and Complex.Math .

  • Assembly : This directive is used to name assemblies that contain classes we wish to use within our ASP.NET application. An assembly is a compiled unit of code in .NET with the extension .dll and exists either in the global assembly cache (covered in Chapter 23) or the bin directory of the ASP.NET application.

    The Import and Assembly directives are very different. Import assumes that the assembly (for example, System.Data.dll ) is already available to our application, and allows us to use abbreviated class names for classes within that namespace. Assembly , on the other hand, is used to tell ASP.NET that there is an assembly that needs to be loaded.

    Important

    Assemblies located in the bin directory are automatically loaded.

    Using the Assembly directive is simple. It has one attribute, Name , which identifies the assembly we wish to reference as part of our application.

As mentioned previously, some assemblies are available by default:

  • mscorlib.dll : Base classes, such as the definition of Object , String , and so on.

  • System.dll : Additional base classes, such as the network class libraries.

  • System.Web.dll : Classes for ASP.NET.

  • System.Data.dll : Classes for ADO.NET.

  • System.Web.Services.dll : Classes for ASP.NET Web services.

  • System.Xml.dll : Classes for XML.

  • System.Drawing.dll : Classes for graphics and drawing.

  • All assemblies within an application's bin directory.

Included in this list are several System assemblies (for example, the assemblies provided as part of the .NET Framework) and those found in application bin directories. You would use the Assembly directive when an assembly is registered in the global assembly cache, or when you need System assemblies not already loaded.

For example, the assembly System.DirectoryServices.dll contains classes for working with directory services, such as Microsoft's Active Directory . This assembly is not one of the default assemblies loaded. To use the classes provided within it in global.asax , you need to use the Assembly directive:

 <%@ Assembly Name="System.DirectoryServices" %> 
Important

The extension of the assembly ( .dll ) is not included.

You can now write code in your global.asax file that uses classes (such as DirectorySearcher) found within this assembly,

The directives for global.asax are straightforward to use. Later, in the Advanced Topics section, you will take a closer look at one of these directives. For now, turn your focus to the code you can write within global.asax .

Code Declaration

Code is declared in global.asax using <Script runat="server"/> blocks. These are identical to the script blocks defined in ASP.NET pages, so we won't explain their syntax in detail again.

Later in the chapter, when we discuss global events, we will implant the created events within these script blocks.

There are two additional ways of declaring code in global.asax :

  • Server-side includes : global.asax supports the use of server-side # include statements using both File and Virtual as the path type to the filename. Server-side includes are declared using the following syntax.

     <!--#Include [File  Virtual]="Path to file" --> 

    File identifies the path as being on the file system, while Virtual identifies a virtual directory provided through the web server. The contents of the file included will be added to the global.asax file before it is compiled. Include files, especially those created using the Virtual option, can be quite useful as they allow us to define a common directory that can be shared among many applications, which may make our application more portable.

    Important

    If an include file is used within a global.asax, the application will automatically be restarted whenever the include file changes.

    While it is possible to use server side includes in your global.asax file, it is not recommended. It is supported only for the purpose of backwards compatibility with classic ASP.

  • Declarative object tags: <Object> tags enable us to declare and instantiate Application and Session objects in global.asax , using a declarative tag-based syntax. These tags can be used to create .NET assemblies, or COM objects specified by either ProgID or CLSID .

    The type of object to create is identified using one of three different tag attributes:

    • class

    • progid

    • classid

    Only one of these tag attributes can be used per <Object> tag declaration.

Using Object Tag Declarations

Here is a sample of how object tag declarations are used:

  <object id="appData" runat="server"   class="System.Data.DataSet" scope="Application"/>  

We have declared an Application scoped variable named appData that is of class type System.Data.DataSet . However, the object is not actually created until it is first used. The object then exists for the lifetime of the context in which it is created. In the preceding example, this is the lifetime of the application. Likewise, if the scope were set to Session , the object would be valid for the life of the current user session, and once that session terminated , the object would be destroyed .

Important

Object tags should be placed outside of script blocks.

The attributes used in this declaration are:

Attributes

Description

id

Unique name to use when referring to the object within the application.

runat

Must be set to server for the object to execute within ASP.NET.

scope

Determines where the object lives. The choices are Application for application state, Session for session state, or Appinstance , allowing each application to receive its own object instance.

[class , progid , classid]

Identifies either the assembly, or the COM ProgID or ClassID of which an instance is to be created.

You have three options for adding code to a global.asax file. The first and most common option will be to use the <script runat="server"> blocks to define application code. You can also define code from an include file and use the <object/> tag syntax to declaratively create an object. Now that you are familiar with how to code your global.asax file, let's take a quick diversion and discuss application state management before moving on to the supported application events.




Professional ASP. NET 1.1
Professional ASP.NET MVC 1.0 (Wrox Programmer to Programmer)
ISBN: 0470384611
EAN: 2147483647
Year: 2006
Pages: 243

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net