• No se han encontrado resultados

Uso del Laboratorio de ajuste de imagen

In document Corel PHOTO PAINT X7 (página 151-154)

The Wrox Blog is designed as a three-tier application, meaning the application consists of a presentation layer, a business layer, and a data access layer. The presentation layer consists of two ASP.NET user con- trols that are discussed later in the chapter. Both the business and the data access layers contain custom classes defined in the files in the special App_Code folder in the root of the web site. You find the files related to the business layer in the subfolder called BusinessLogic, and the data access layer is placed in the DataAccess folder. This distinction isn’t really necessary, because the ASP.NET run time compiles each file it finds in the App_Code folder or any of its subfolders automatically. However, placing the files in separate folders makes it easier to see to what layer each file and class belongs. The files in the folder are named after the classes they contain, so you’ll find the class BlogManagerin the file BlogManager.vb, and so on.

The Business Layer

The business layer of the Wrox Blog is built around two important entities: the BlogEntryand the BlogManagerclasses. The BlogEntryclass represents a blog entry that is stored in the database and can be viewed on the web site, and the BlogManagerclass is responsible for getting the blog entries in and out of the database. In addition to these two important classes, you’ll also find a UserManagerclass in

the BusinessLayer folder. This class is used to allow users to log in and retrieve information about the roles they are assigned to when you’re using an Access database. ASP.NET 2.0 provides a very conve- nient platform that handles user authentication and role management for you. However, this framework works only with SQL Server and not with a Microsoft Access database. To still allow you to log in to the site when you’re using an Access database, the UserManagerclass provides the necessary methods. To see what these classes can do, each of them is discussed in the following sections.

The BlogEntry Class

The BlogEntryclass is used to represent a blog post that gets stored in the database and that can be viewed on the web site. All the interaction with a BlogEntryinstance is done by the BlogManager. Therefore, the BlogEntryclass, depicted in Figure 6-4, has only public properties and no methods (other than its two constructors).

Figure 6-4

The following table lists all of the public properties of the BlogEntryclass:

Property Data Type Description

Body String This property holds the text for the blog entry.

CategoryId Integer This indicates to which category the blog entry belongs. DatePublished DateTime This property holds the date and time the blog entry was

published.

Id Integer This is the unique ID of the blog entry and is assigned by the database automatically whenever a new item is created. Title String This is the title of the blog entry as it appears on the

BlogEntriesuser control.

In addition to these five properties, the BlogEntryclass has two constructors. The first, a parameterless default constructor, is used to create an entirely new BlogEntryinstance. The second, an overloaded

version that accepts a BlogEntryinstance’s ID as an Integer, is used when an existing BlogEntryis re-created when it’s being edited. The ID passed to the constructor is stored in the private field_Idand is made available through the public and read-only property Id. You see both constructors at work later when the code is discussed in more detail.

Because the BlogEntryclass is used only to hold data and cannot perform any operations, another class is needed that can work with instances of the BlogEntry. That class is the BlogManager.

The BlogManager Class

Quite the opposite of the BlogEntryclass, the BlogManagerclass (see Figure 6-5) has only shared methods and no properties. It also has one private constructor to prevent calling code from creating instances of the BlogManagerclass.

Figure 6-5

As you can see by the method names in Figure 6-5, the BlogManagerclass is not only responsible for working with blog entries, but is also capable of retrieving a list of categories. In larger applications it would be a wise design decision to introduce separate Categoryand CategoryManagerclasses, but in a relatively small application like the Wrox Blog it’s perfectly acceptable to designate one class for multi- ple tasks.

These methods need some explanation, so the following table describes all of them in more detail:

Method Return Type Description

Public Shared Function DataSet This method returns the latest 15 blog GetBlogEntries () As entries from the database by calling into

DataSet the BlogManagerDBclass.

Public Shared Function DataSet Returns all blog entries in the specified GetBlogEntries (ByVal category from the database by calling categoryId As Integer) into the BlogManagerDBclass. As DataSet

Public Shared Function DataSet Returns all blog entries in the specified GetBlogEntries (ByVal period from the database by calling into startDate As DateTime, the BlogManagerDBclass. If startDate ByVal endDate As DateTime) and endDateare the same, blog entries

Method Return Type Description

Public Shared Function BlogEntry This method retrieves a single BlogEntry GetBlogEntry (ByVal instance from the database based on the blogEntryId As Integer) blogEntryIdpassed to this method. It

As BlogEntry does this by calling GetBlogEntryin

the BlogManagerDBclass. Because this method is only used when editing blog entries, the code checks if the current user is a member of the Administrator group and throws an exception if this isn’t the case.

Public Shared Function DataSet Returns the available categories as a

GetCategories () As DataSet.

DataSet

Public Shared Sub n/a This method saves a blog entry in the SaveBlogEntry (ByVal database. This can be a completely new myBlogEntry As BlogEntry) or an updated blog entry. Just as with

GetBlogEntry, this method checks the access rights of the current user.

In Figure 6-5 you see the method GetBlogEntrieswith (+ 2 overloads) behind its name. In the table describing the methods, you see GetBlogEntrieslisted three times. Although the name of these three methods is the same, their argument lists differ. There is a version without arguments, one that accepts the ID of the category, and one that accepts a start and end date. To avoid cluttering up the class diagram, these methods have been grouped together under one method name in Figure 6-5. To help you see the method has overloads, (+ 2 overloads) is put behind the method name.

The class diagram in Figure 6-5 also shows a Newmethod with a little lock icon in front of it. This is the constructor for the BlogManagerclass. Because this class exposes only shared methods (that operate on the class itself, rather than on an instance of the class) the constructor has been hidden by marking it as private. This makes it impossible for calling code to create new instances of the BlogManagerclass. All classes in the App_Code folder for the Wrox Blog except the BlogEntryclass follow this pattern and thus have a private constructor.

The final class in the BusinessLayer folder is the UserManagerclass, which is discussed next.

The UserManager Class

The ASP.NET 2.0 Framework provides very powerful yet easy-to-use features to manage authentication and role membership. These features are referred to as the Membership and Role providers. By simply activating these features in your application’s configuration, the application is able to allow users to log in and grant them different rights depending on the roles they are assigned to. These providers have one great shortcoming: They work only with SQL Server and not with another database such as Microsoft Access. The provider model allows developers to override the behavior of the default providers, so it is possible to write your own providers that work with an Access database instead of with SQL Server. Because of the large amount of functionality and methods these providers offer, writing your own

provider can easily be the subject of an entire chapter or book. Because the Wrox Blog doesn’t need all this functionality, it contains a simple alternative in the form of the UserManagerclass. This class has a single method called GetUserRoles(see Figure 6-6) that retrieves the roles for a user.

Figure 6-6

The GetUserRolesmethod accepts the username and a hash of the user’s password and returns a list with the roles the user has been assigned to (that is, if the user was found in the database, of course). These roles are then used by the application to determine the access rights for the user. This method is used in the Login page that is discussed later.

For the BlogManagerand the UserManagerclasses in the business layer, you’ll find a database counter- part that ends with DB inside the DataAccess folder. These classes carry out database interaction and are discussed next.

The Data Access Layer

One of the main design goals for the Wrox Blog was database independence. Because it’s likely you use this application with a remote host, you can’t know in advance whether that hosts supports SQL Server 2005 or just Microsoft Access. So, the code should work with SQL Server and with a Microsoft Access database without any modification. When you look at the three classes present in the data access layer, you won’t be able to see that these can work with multiple databases at the same time. Instead, these classes expose a single interface with methods that can work with different kinds of databases. This is made possible by a concept called factories, something you see more about when the code is discussed later. To understand how this all works, and why this is so great, you need to look a bit at the history of ASP and ADO.

When the .NET Framework version 1.0 was released, one area that caused a lot of confusion among developers was the way databases were accessed. In classic ASP — or to be more exact, with classic ADO — you had a single object model that could work with a wide variety of databases. Simply by pass- ing a proper connection string to a Connectionobject you could talk to SQL Server, Access, Oracle, and other databases. Recordsets retrieved through that connection always worked the same, and exposed the same set of methods. However, with .NET, things changed drastically. Instead of a generic Connection or Recordsetobject, developers were faced with objects bound to specific providers. For example, for the SQL Server provider, you have a SqlConnectionand a SqlDataReader; for the OleDb provider there is an OleDbConnectionand an OleDbDataReader; and so on. The only exception is the DataSet that, instead of being tied to a specific data provider, is hosted in the general System.Data namespace. Though these strongly typed objects brought great performance and a rich feature set targeted at the specific provider, developers wanting to target both SQL Server and Oracle or any other database at the same time were faced with a huge challenge. To work around this problem, a few methods are available.

First, there is the abstract base class model. In this model, a designer creates an abstract base class (a class that must be inherited and cannot be instantiated directly) or an interface that supplies the signa- ture of each of the necessary methods, like GetBlogEntryand GetCategoriesList. Then for each required database provider a child class is created that inherits from this base class or implements the appropriate interface. This concrete child class then implements each of the methods defined in the con- tract of the base class or interface. At run time, the proper child class is instantiated and the appropriate methods are called. This solution results in good performance because each of the child classes uses the most appropriate data providers, so the SQL Server implementation of the child class can benefit from the optimizations found in the SQL Server provider, for example. The downside of this solution is the amount of code required. For each new database provider, an entirely new child class needs to be cre- ated and maintained.

Another solution to write database-independent code is to write against the generic interfaces of each of the important data access objects. Each of the main ADO.NET objects, like a Connection, a DataReader, and so on, implements a specific interface. The SqlConnectionimplements IdbConnection, an OleDbDataReaderimplements IdataReader, and so on. With this solution, you have to create a method that returns the proper object type, based on the provider you want to use. This method could look similar to this:

Public Function GetConnection() As IDbConnection Select Case GetProviderFromConfiguration()

Case “System.Data.SqlClient” Return New SqlConnection() Case “System.Data.OleDb”

Return New OleDbConnection() End Select

End Function

This method looks up the requested provider from the application’s configuration file, for example, and returns the appropriate connection type. The biggest downside of this method is that you use the generic interface shared by all providers. This means you can, by default, only use the common denominator shared by all providers. It also means that you should modify this code whenever a new provider is added to the application.

Along come .NET 2.0 and ADO.NET 2.0 with a factories pattern that solves many of these problems. In a factory pattern, a class is responsible for creating instances of other classes. In the Wrox Blog, the DbProviderFactoriesclass from the System.Data.Commonnamespace is used. This class is able to create instances of other classes that are used to interact with databases. In terms of design, the ADO.NET factories pattern looks a lot like the generic interface solution you just saw. However, imple- menting it is now a lot more straightforward. You see the code to actually implement this later in the section “Writing Provider-Independent Code.”

Even though .NET 2.0 fixes many of the problems related to object instantiation, some impacting differ- ences between each data provider still exist that make it difficult to write data provider-independent code. These differences include the use of built-in functions, the capabilities of stored procedures, and the way parameters are passed to stored procedures. Not all of these problems can be fixed completely, but with some careful planning and some smart helper code it is possible to work around most of these limitations. Later in this chapter, when the inner workings of the code are discussed in the data access layer, you see the code responsible for these workarounds.

Now that you have some background on the design goals and decisions made for the data access layer of the Wrox Blog, take a look at the actual classes defined in this layer. Because the BlogEntryclass in the business layer does not have its own behavior, you’ll see no BlogEntryDBclass in the data access layer. Instead, all interaction with the database to get information about blog entries and to save them is carried out by the BlogManagerDBclass.

The BlogManagerDB Class

The BlogManagerDBclass has the exact same methods as the BlogManagerclass. However, the BlogManagerDBclass is responsible for actually getting the requested data from and into the database. The BlogManagerDBclass does not only work with blog items or lists of entries; it’s also responsible for getting a list with the available blog categories from the database.

Figure 6-7 lists the four methods and the private constructor defined in this class.

Figure 6-7

Each of these methods and their overloads, except the constructor, are discussed in the following table:

Method Return Type Description

Public Shared Function DataSet This method returns the latest 15 blog entries GetBlogEntries () As from the database, again by calling a stored

DataSet procedure or query.

Public Shared Function DataSet Returns all blog entries in the specified GetBlogEntries (ByVal category from the database.

categoryId As Integer) As DataSet

Public Shared Function DataSet Returns all blog entries in the specified period GetBlogEntries (ByVal from the database. If startDateand endDate startDate As DateTime, are the same, entries are returned for a single

ByVal endDate As day.

DateTime) As DataSet

Public Shared Function BlogEntry This method retrieves a single BlogEntry GetBlogEntry (ByVal instance from the database based on the blogEntryId As blogEntryIdpassed to this method. It does Integer) As BlogEntry this by calling a stored procedure (or query) in

the database. The procedures used in the data access layer are discussed later.

Method Return Type Description

Public Shared Function DataSet Returns the available categories as a DataSet. GetCategories () As

DataSet

Public Shared Sub n/a This method saves a blog entry in the SaveBlogEntry (ByVal database. This can be a completely new or an

myBlogEntry As updated blog item.

BlogEntry)

To simplify the data access code so it can work with multiple databases, there is also a DalHelpersclass (see Figure 6-8) that serves as a helpers class for the data access layer (DAL). This class has a single method called ReturnCommandParamName.

Figure 6-8

The ReturnCommandParamNamemethod accepts the name of a parameter that must be passed to a stored procedure (in SQL Server) or a query (in Microsoft Access) and returns the correctly formatted parameter name. For SQL Server this is the name prefixed with an at symbol (@), whereas for Access this is a single question mark symbol (?) without the initial name. You see later why and how this code is used.

The UserManagerDB Class

Just as the UserManagerclass in the business layer, the UserManagerDBclass has a single method called GetUserRoles, as shown in Figure 6-9.

Figure 6-9

To simplify the code to log in a user, the traditional LoginUserand GetRolesmethods have been com- bined into one method. The GetUserRolesmethod functions as a LoginUsermethod in that it accepts the user’s name and a hashed password. It then returns the roles for the user as an ArrayList if the user is found in the database, or Nothingotherwise.

In document Corel PHOTO PAINT X7 (página 151-154)

Documento similar