ptg 754 CHAPTER 17 Building Components Adding an Assembly to the Global Assembly Cache All the assemblies that make up the .NET Framework class library are contained in the Global Assembly Cache. For example, the Random class is located in the System.dll assem- bly, and the System.dll assembly is contained in the Global Assembly Cache. Any assem- bly located in the Global Assembly Cache can be referenced by any application running on a server. The Global Assembly Cache’s physical location is at the following path: C:\WINDOWS\assembly Before you can add an assembly to the Global Assembly Cache, you must add a strong name to the assembly. A strong name is similar to a GUID. You use a strong name to provide your assembly with a universally unique identifier. NOTE Technically, a strong name consists of th e name, ver sion number, and culture of th e assembly. The strong name also includes the public key from a public/private key pair. Finally, the strong name includes a hash of the assembly’s contents so that you know whether the assembly has been modified. You can generate a strong name by using the sn.exe command-line tool like this: sn.exe -k KeyPair.snk Executing this command creates a new file named KeyPair.snk, which includes a new random public/private key pair. WARNING Protect your key file. You should not reveal the private key to anyone. You can compile an assembly that includes a strong name by executing the Visual Basic .NET command-line compiler like this: csc /t:library /keyfile:KeyPair.snk /recurse:*.cs /out:MyLibrary.dll The resulting assembly is strongly named with the public key from the KeyPair.snk file. The /keyfile option associates the key file with the assembly. In this case, the name of the resulting assembly is MyLibrary.dll. An alternative method of associating a strong name with an assembly is to use the <Assembly: AssemblyKeyFile> attribute. You can add this attribute to any of the source From the Library of Wow! eBook ptg 755 Building Component Libraries 17 files that get compiled into the assembly. For example, you can drop the file in Listing 17.24 into the folder that you are compiling, and it associates the public key from the KeyPair.snk file with the compiled assembly. LISTING 17.24 AssemblyInfo.cs using System.Reflection; [assembly:AssemblyKeyFile(“KeyPair.snk”)] [assembly:AssemblyVersion(“0.0.0.0”)] The file in Listing 17.24 actually includes two attributes. The first attribute associates the KeyPair.snk public key with the assembly. The second attribute associates a version number with the assembly. The version number consists of four sets of numbers: major version, minor version, build number, and revision number. After you add the file in Listing 17.24 to a folder that contains the source code for your components, use the following command to compile the folder: csc /t:library /recurse:*.cs /out:MyLibrary.dll After you associate a strong name with an assembly, you can use the GacUtil.exe command-line tool to add the assembly to the Global Assembly Cache. Executing the following statement from a command prompt adds the MyLibrary.dll assembly to the Global Assembly Cache: GacUtil.exe /i MyLibrary.dll You can verify that the MyLibrary.dll assembly has been added successfully to the Global Assembly Cache by opening your Global Assembly Cache folder located at the following path: C:\WINDOWS\assembly You should see the MyLibrary.dll assembly listed in the Assembly Name column (see Figure 17.11). Note the Version and the PublicKeyToken columns. You need to know the values of these columns to use the assembly in an application. From the Library of Wow! eBook ptg 756 CHAPTER 17 Building Components After you install an assembly in the Global Assembly Cache, you can use the assembly in your ASP.NET Pages and App_Code components by adding a reference to the assembly in your web configuration file. The web configuration file in Listing 17.25 adds the MyLibrary.dll assembly to your application. LISTING 17.25 Web.Config <?xml version=”1.0”?> <configuration> <system.web> <compilation> <assemblies> <add assembly=”MyLibrary,Version=0.0.0.0,Culture=neutral, PublicKeyToken=250c66fc9dd31989”/> </assemblies> </compilation> </system.web> </configuration> The web configuration file in Listing 17.25 adds the MyLibrary assembly. You must supply the Version, Culture, and PublicKeyToken associated with the assembly. You need to substitute the correct values for these properties in Listing 17.25 before you use the file with an assembly that you have compiled. (Remember that you can get these values by opening the c:\WINDOWS\assembly folder.) FIGURE 17.11 Viewing the Global Assembly Cache. From the Library of Wow! eBook ptg 757 Architectural Considerations 17 NOTE When using Visual C# Express or Visual Studio 2010, you can create a strong name automatically and associate the strong name with an assembly. Right-click the name of your project in the Solution Explorer window and select Properties. Next, select the tab labeled Signing. In general, you should avoid adding your assemblies to the Global Assembly Cache because using the Global Assembly Cache defeats XCopy deployment. Using the Global Assembly Cache makes it more difficult to back up an application. It also makes it more difficult to move an application from one server to another. Architectural Considerations If you embark on a large ASP.NET project, you quickly discover that you spend more time writing code for components than writing code for your pages. This is not a bad thing. Placing as much of your application logic as possible in components makes it easier to maintain and extend your application. However, the process of organizing the compo- nents itself can become time consuming. In other words, you start to run into architec- tural issues concerning the best way to design your web application. The topic of architecture, like the topics of politics and religion, should not be discussed in polite company. People have passionate opinions about architecture, and discussions on this topic quickly devolve into people throwing things. Be aware that all statements about proper architecture are controversial. With these disclaimers out of the way, in this section I provide you with an overview of one of the most common architectures for ASP.NET applications. In this section, you learn how to build a three-tiered ASP.NET application. Building Multitier Applications One common architecture for an application follows an n-tier design model. When using an n-tier architecture, you encapsulate your application logic into separate layers. In particular, it is recommended that an application should be divided into the following three application layers: . User Interface . Business Logic . Data Access The idea is that the User Interface layer should contain nothing but user interface elements such as HTML and ASP.NET controls. The User Interface layer should not contain any business logic or data access code. From the Library of Wow! eBook ptg 758 CHAPTER 17 Building Components The Business Logic layer contains all your business rules and validation code. It manages all data access for the User Interface layer. Finally, the Data Access layer contains all the code for interacting with a database. For example, all the code for interacting with Microsoft SQL Server should be encapsulated in this layer. The advantage of encapsulating your application logic into different layers is that it makes it easier to modify your application without requiring you to rewrite your entire applica- tion. Changes in one layer can be completely isolated from the other layers. For example, imagine that (one fine day) your company decides to switch from using Microsoft SQL Server to using Oracle as its database server. If you have been careful to create an isolated Data Access layer, you would need to rewrite only your Data Access layer. It might be a major project, but you would not need to start from scratch. Or imagine that your company decides to create a Silverlight version of an existing ASP.NET application. Again, if you have been careful to isolate your User Interface layer from your Business Logic layer, you can extend your application to support a Silverlight interface without rewriting your entire application. The Siverlight application can use your existing Business Logic and Data Access layers. This is all abstract, so let’s examine a particular sample. We create a simple product management system that enables you to select, insert, update, and delete products. However, we do it the right way by dividing the application into distinct User Interface, Business Logic, and Data Access layers. Creating the User Interface Layer The User Interface layer is contained in Listing 17.26. The User Interface layer consists of a single ASP.NET page. This page contains no code whatsoever. LISTING 17.26 Products.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN” “http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <style type=”text/css”> html { background-color:silver; } .content { padding:10px; background-color:white; From the Library of Wow! eBook ptg 759 Architectural Considerations 17 } .products { margin-bottom:20px; } .products td,.products th { padding:5px; border-bottom:solid 1px blue; } a { color:blue; } </style> <title>Products</title> </head> <body> <form id=”form1” runat=”server”> <div class=”content”> <asp:GridView id=”grdProducts” DataSourceID=”srcProducts” DataKeyNames=”Id” AutoGenerateEditButton=”true” AutoGenerateDeleteButton=”true” AutoGenerateColumns=”false” CssClass=”products” GridLines=”none” Runat=”server”> <Columns> <asp:BoundField DataField=”Id” ReadOnly=”true” HeaderText=”Id” /> <asp:BoundField DataField=”Name” HeaderText=”Name” /> <asp:BoundField DataField=”Price” DataFormatString=”{0:c}” HeaderText=”Price” /> <asp:BoundField DataField=”Description” HeaderText=”Description” /> From the Library of Wow! eBook ptg 760 CHAPTER 17 Building Components </Columns> </asp:GridView> <fieldset> <legend>Add Product</legend> <asp:DetailsView id=”dtlProduct” DataSourceID=”srcProducts” DefaultMode=”Insert” AutoGenerateInsertButton=”true” AutoGenerateRows=”false” Runat=”server”> <Fields> <asp:BoundField DataField=”Name” HeaderText=”Name:” /> <asp:BoundField DataField=”Price” HeaderText=”Price:”/> <asp:BoundField DataField=”Description” HeaderText=”Description:” /> </Fields> </asp:DetailsView> </fieldset> <asp:ObjectDataSource id=”srcProducts” TypeName=”AcmeStore.BusinessLogicLayer.Product” SelectMethod=”SelectAll” UpdateMethod=”Update” InsertMethod=”Insert” DeleteMethod=”Delete” Runat=”server” /> </div> </form> </body> </html> The page in Listing 17.26 contains a GridView, DetailsView, and ObjectDataSource control. The GridView control enables you to view, update, and delete the products contained in the Products database table (see Figure 17.12). The DetailsView enables you to add new products to the database. Both controls use the ObjectDataSource as their data source. From the Library of Wow! eBook ptg 761 Architectural Considerations 17 NOTE The next chapter is entirely devoted to the ObjectDataSource control. The page in Listing 17.26 does not interact with a database directly. Instead, the ObjectDataSource control binds the GridView and DetailsView controls to a component named AcmeStore.BusinessLogicLayer.Product. The Product component is contained in the Business Logic layer. NOTE The page in Listing 17.26 does not contain any validation controls. I omitted adding validation controls for reasons of space. In a real application, you would want to toss some RequiredFieldValidator and CompareValidator controls into the page. Creating the Business Logic Layer The ASP.NET pages in your application should contain a minimum amount of code. All your application logic should be pushed into separate components contained in either the Business Logic or Data Access layers. Your ASP.NET pages should not communicate directly with the Data Access layer. Instead, the pages should call the methods contained in the Business Logic layer. FIGURE 17.12 The Products.aspx page. From the Library of Wow! eBook ptg 762 CHAPTER 17 Building Components The Business Logic layer consists of a single component named Product, which is contained in Listing 17.27. (A real-world application might contain dozens or even hundreds of components in its Business Logic layer.) LISTING 17.27 BLL/Product.cs using System; using System.Collections.Generic; using AcmeStore.DataAccessLayer; namespace AcmeStore.BusinessLogicLayer { /// <summary> /// Represents a store product and all the methods /// for selecting, inserting, and updating a product /// </summary> public class Product { private int _id = 0; private string _name = String.Empty; private decimal _price = 0; private string _description = String.Empty; /// <summary> /// Product Unique Identifier /// </summary> public int Id { get { return _id; } } /// <summary> /// Product Name /// </summary> public string Name { get { return _name; } } /// <summary> /// Product Price /// </summary> public decimal Price { get { return _price; } } From the Library of Wow! eBook ptg 763 Architectural Considerations 17 /// <summary> /// Product Description /// </summary> public string Description { get { return _description; } } /// <summary> /// Retrieves all products /// </summary> /// <returns></returns> public static List<Product> SelectAll() { SqlDataAccessLayer dataAccessLayer = new SqlDataAccessLayer(); return dataAccessLayer.ProductSelectAll(); } /// <summary> /// Updates a particular product /// </summary> /// <param name=”id”>Product Id</param> /// <param name=”name”>Product Name</param> /// <param name=”price”>Product Price</param> /// <param name=”description”>Product Description</param> public static void Update(int id, string name, decimal price, string ➥ description) { if (id < 1) throw new ArgumentException(“Product Id must be greater than 0”, ➥ “id”); Product productToUpdate = new Product(id, name, price, description); productToUpdate.Save(); } /// <summary> /// Inserts a new product /// </summary> /// <param name=”name”>Product Name</param> /// <param name=”price”>Product Price</param> /// <param name=”description”>Product Description</param> public static void Insert(string name, decimal price, string description) { Product newProduct = new Product(name, price, description); From the Library of Wow! eBook . for ASP. NET applications. In this section, you learn how to build a three-tiered ASP. NET application. Building Multitier Applications One common architecture for an application follows an n-tier. a single ASP. NET page. This page contains no code whatsoever. LISTING 17.26 Products.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC -/ /W3C//DTD XHTML 1.1//EN” “http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”>. name=”name”>Product Name</param> /// <param name=”price”>Product Price</param> /// <param name=”description”>Product Description</param> public static void Update(int id, string