荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Jobs (温少), 信区: Visual
标  题: Migrating from ASP to ASP+
发信站: BBS 荔园晨风站 (Sun Sep 17 03:35:01 2000), 转信



Migrating from ASP to ASP+

Since Microsoft announced ASP+ at the July 2000 PDC, one question (among
many) has plagued newsgroups and discussion forums?quot;What do I need
to do to convert my existing web applications from ASP to ASP+?".
Speakers at the PDC claimed that the changes in code would be minimal,
and the transition would be not too difficult to manage. We shall
explore this claim in this article.

To run the alpha of ASP+, you need:

Windows 2000 Professional, Server, or Advanced Server
IIS 5.0
Internet Explorer 5.5
.Net Framework Runtime


(Future releases of ASP+ will be able to run on Windows NT and 9x.)

If you are a current ASP developer, the skills you currently use, such
as VBScript, will transfer easily to Visual Basic.Net to code your ASP+
pages. You may also use other languages, such as C#, Managed C++ and
even Cobol. In this article I will detail the steps we took migrating a
small web application from ASP to ASP+. The code samples use Visual
Basic.Net.

While ASP and ASP+ can coexist and interact with each other, we chose to
migrate our site entirely to ASP+. The site being migrated is a sample
site we use to teach beginning web development. We feel this site
represents a significant portion of the small to mid杝ize sites
populating the Internet today. The site,
http://www.codejunkies.net/eVille/, is a fake student enrollment site
for classes on IT topics. It is driven by an Access 2000 database,
running on Windows 2000 Server, using VBScript, client-side JavaScript,
and ASP 3.0, but doesn't use COM.


ASP and ASP+ are designed to run side by side, on the same web server
running IIS 5.0 (the final release will support other versions as well).
This enabled us to migrate the site a page at a time. The original pages
would continue working under ASP 3.0, and the new pages would be
converted to use ASP+ Server Controls and functionality.


Initial Considerations
The very first step needed was to enable IIS to recognize default.aspx
as a valid default document. This is a simple step. In Internet Services
Manager:

Open the Properties dialog for the IIS Virtual Directory
Click the Add button on the Documents tab
Type Default.aspx
Click OK twice.

The eVille site does not use COM, so all of the data access is done with
ADO in the ASP pages or include files. One of our initial goals was the
conversion from ADO to ADO+ to gain the performance benefits of the ADO+
Managed Provider. ASP+ does allow the use of traditional ADO, but there
are substantial benefits to migrating to ADO+ ?for example, retrieving
multiple tables in a single DataSet, faster performance, and binding
data to Server Controls. Data access in ASP+ pages can be done using
ADO, ADO+, or the SQL Managed Provider. Since this site does not use SQL
Server, and we want the performance boost, we are left in the capable
hands of ADO+.


Every page of this site has some data access on it, so this was to be
the largest part of the work transitioning the site. Essentially, every
page had to undergo some code modification to retrieve and display the
data needed for that page. eVille's architecture has a connect.inc file
that contains the ADO Connection code, and this file is dropped on every
page. The connection is created, and ready for use. Since the process of
connecting to the database and binding to an ASP+ Data Control was to be
done in the new Page_Load event of the ASP+ pages, a slightly different
approach had to be taken.

We used the same concept of having the connection created universally in
a separate module by creating a Pagelet. ASP+ Pagelets enable the
developer to create psuedo朿ontrols, which can expose Properties,
Methods and Events just as any object can. Our solution was to create a
Pagelet that exposed a ConnectToDB method, which returned an
ADOConnection object (slight syntax change from ADO). We created a
Pagelet with the following code, and saved it as connect.aspc (the
extension identifying Pagelets)


<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>

<script language="VB" runat="server">
Public Function ConnectToDB() As ADOConnection
   ConnectToDB = New ADOConnection("DSN=evilleDSN")
End Function
</script>

You'll notice that we imported two Namespaces, System.Data and
System.Data.ADO. These Namespaces are required to make use of the ADO+
Managed Provider. I've been asked a lot of questions on this, as most
samples at present use the SQL Managed Provider against a Microsoft SQL
Server 2000 database. For non朣QL Server databases, ASP+ can use the
ADO+ Managed Provider; much in the same way you used ADO in your current
applications. Importing the Namespaces is analogous to making References
in your VB applications.

Use of a Pagelet enabled me to maintain the current site plan, having
the connection created once in a module, and reuse that module where
needed. This meant that we needed to replace the Include File directive
with an instance of my Pagelet, and then call to the ConnectToDB method
when we needed a connection to the database. On pages where we would use
this Pagelet, we first needed to register it with the page, using an
ASP+ directive. In the directive we specify the TagPrefix, TagName, and
Source (src). The TagPrefix and TagName will be used where we place the
Pagelet, similar to an include file in ASP:


<%@ Register TagPrefix="seven" TagName="Connect"
 src="_includes/connect.aspc" %>

To place the Pagelet we just registered, we treat it similarly to an
ASP+ Server Control:

<[TagPrefix]:[TagName] id=myPagelet runat=server />

Like this:

<seven:Connect id=Connect runat=server />

In ADO+, the concept of a Recordset has been replaced with the
combination of DataSets and DataViews. We'll discuss both of these in a
moment. First lets take at how the code changes look as we migrate our
default.asp page to default.aspx (the extension for ASP+ pages). First
default.asp:

<!-- #include file="_includes/connect.inc" -->
<%
   Dim cnEville_DB, rsUpcoming, strSqlUpcoming
   Set rsUpcoming = Server.CreateObject("ADODB.Recordset")

   strSqlUpcoming = " SELECT TOP 2 " & _
      "Classes.Title, Sessions.Session_ID, " & _
      "Sessions.Special, Classes.Description " & _
      "FROM Classes INNER JOIN Sessions ON " & _
      "Classes.Class_ID = Sessions.ClassID " & _
      "WHERE (((Sessions.Date)>Date())) " & _
      "ORDER BY Sessions.Date"

   rsUpcoming.Open strSqlUpcoming,cnEville_DB
%>
In ASP+ this becomes default.aspx:

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>
<%@ Register TagPrefix="seven" TagName="Connect" &_
             src="_includes/connect.aspc" %>

<script language="vb" runat=server>
Sub Page_Load(Source As Object, E As EventArgs)
   Dim dscUpcoming   As ADODataSetCommand
   Dim dsUpcoming    As New DataSet
   Dim strSQL        As String

   strSQL = "SELECT TOP 2 Classes.Title," & _
      "Sessions.Session_ID, Classes.Description " & _
      "FROM Classes INNER JOIN Sessions ON " & _
      "Classes.Class_ID = Sessions.ClassID " & _
      "WHERE (((Sessions.Date)>Date())) " & _
      "ORDER BY Sessions.Date"

   dscUpcoming = New ADODataSetCommand(strSQL, Connect.ConnectToDB())
   dscUpcoming.FillDataSet(dsUpcoming, "Upcoming")
End Sub
</script>

The heart of my data access, the ANSI朣QL statement, is transferred over
without any changes. However, as you can see, the structure for building
my "recordset" has changed, using the ADODataSetCommand and DataSet.


Enter the DataSet
ADO+ introduces the DataSet and DataView. A DataSet is analogous to a
collection of Recordsets, in that it can hold one or more tables of data
and their relationships. The DataView is the implementation of one of
these tables, similar to an ADO Recordset. In the example above, our
DataSet is only holding one table, Upcoming, which we will use to
populate an ASP+ Server Control. We could add more tables to the DataSet
by:

Redefining our SQL statement
Setting the ADODataCommand's SelectCommand property to a new
ADODataCommand

Calling the ADODataCommand's FillDataSet method
The FillDataSet method simply puts the resulting table from our SQL
statement into the DataSet passed into the method call. Adding another
table would look like this:


dscUpcoming = New ADODataSetCommand(strSQL, Connect.ConnectToDB())
dscUpcoming.FillDataSet(dsUpcoming, "Upcoming")

'Redefine the SQL statement
strSQL = "SELECT * FROM Students"

'Set the ADODataSetCommand's SelectCommand property
dscUpcoming.SelectCommand = New ADOCommand(strSQL, Connect.ConnectToDB())

'Add the results to the DataSet as a new table with the FillDataSet method
dscUpcoming.FillDataSet(dsUpcoming,  "Students")

At this point we have created a connection to the database and returned
data into a DataSet, however; we haven't made use of this data yet.

Converting an HTML Table to an ASP+ DataList
The data we retrieved from our data store will be used to display the
next two upcoming classes offered through eVille. For design reasons, a
standard grid is not appropriate. The data needs to be displayed in a
custom format, showing the Class Title, and Description, with a link to
enroll in the class (the link passes the Session_ID in the QueryString).
Here's the original ASP page looped through the ADO Recordset, creating
a new row for each record:

<table width="100%" border="0">
<tr>
<td class="headerRow">Upcoming Events</td>
</tr>

<%Do While Not rsUpcoming.EOF%>

<tr>
<td><p><b><%=rsUpcoming("Title")%></b><br>
<%=rsUpcoming("Description")%></p>
<p><a href="enroll.asp?SessionID=<%=rsUpcoming("Session_ID")%>">
Enroll Now!</a></p><br>
</td>
</tr>

<%
rsUpcoming.MoveNext
Loop
%>

</table>

In ASP+ we make use of a new Server Control, the DataList. The ASP+
DataList is one of the new controls for creating custom layout in a
table朾ased format. DataList creates the table rows and columns based on
properties you assign it, and uses Templates to control its layout. In
the following example, we use ItemTemplate to format the layout of each
row. This template controls the layout of each cell that is rendered
(one cell per record):

<tr>
<td class="headerRow">Upcoming Events</td>
</tr>
</table>

<asp:DataList id="dlUpcoming" width="100%" runat="server">

<template name = "ItemTemplate">
<p><b><%# Container.DataItem("Title") %></b><br/>
<%# Container.DataItem("Description") %></p>
<p><a href="enroll.asp?SessionID=<%# Container.DataItem("Session_ID") %>">
Enroll Now!</a></p><br/>
</template>

</asp:DataList>

By default DataList creates a single column table. It can be set to create
multiple columns through a couple of property changes:

<asp:DataList id="dlUpcoming" width="100%"
   RepeatDirection="Horizontal"
   RepeatColumns="2"
   runat="server">

Other data display controls include DataGrid (standard table/grid
layout) and Repeater (fully custom layout).

If we were to view this page now, nothing in the table would display.
This is because, while we have designed the layout, we have not provided
any data. We must explicitly bind our data (a DataView from our DataSet)
to the ASP+ DataList control. We do this by setting the DataSource
property and calling the DataBind() method of the control we would like
the data to display in.

Because ASP+ Web applications are compiled before they are rendered, we
are no longer bound to following a linear processing flow on the page.
Even though the DataList's ID is not determined until midway down the
page (when we actually put the control on the page), we can still
reference the control in our Page_Load event, at the beginning of the
page. Doing so, we bind the data to the control when the page loads:


<script language="vb" runat=server>
Sub Page_Load(Source As Object, E As EventArgs)
   . . .
   cmdUpcoming.FillDataSet(dsUpcoming, "Upcoming")

   dlUpcoming.DataSource = dsUpcoming.Tables("Upcoming").DefaultView
   dlUpcoming.DataBind()

End Sub
</script>

Using an ASP+ Server Control, such as DataList gives us programmatic
access to the control. As a result we are able to write code against its
properties and methods. In the first line we set the DataList's
DataSource property to DataView (a single ta ble of data) in the
DataSet. Specifically, we set it to the default view of the Upcoming
table in the DataSet's Tables Collection. Having set the DataSource, we
then call the DataList control's DataBind() method, binding the results
from our SQL query to the DataList control.

Like a Horse to Water ?Converting the Other Pages
For the remainder of the pages, we followed similar steps, using the
ASP+ DataList or Repeater controls. This was necessary, as the design
called for custom layout of the data, rather than a standard grid
display. One page, classcatalog.aspx, required one field to have its
value checked and, depending on the value of the field, have one of two
possible outputs rendered. This page made use of the Repeater control,
so we explicitly create the table rows and columns, rather than letting
the control do it for us. This is done inside the templates. In ASP it
looked like this:

'Check to see if this is a special offer
If rsSessions("Special") = True Then
   'If this class is a special, then write "Special Offer!"
   Response.Write "<td valign=top align=center>" & vbCrLf
   Response.Write "<a href=""classdetail.asp?SessionID="
   Response.Write rsSessions("SessionID")
   Response.Write """name=""Click for more detail"">"
   Response.Write "Special Offer!"
   Response.Write "</td>"
Else
   'If it is not a special, write "--" to the column
   Response.Write "<td valign=top align=center>--</td>(34) & _
                     "classdetail.aspx?SessionID=" & _
                      intNumber & Chr(34) & ">Special!!</a>"
   Else
      CheckSpecial = "--"
   End If
End Function

We then simply call the function from the ASP+ Repeater:

<template name = "ItemTemplate">
<tr>
[ other data being displayed ]
<td valign=top align=center>
<%=CheckSpecial(Container.DataItem("Special"),
Container.DataItem("Session_ID"))%>
</td>
</tr>
</template>

Container is a reference to the parent object of the data being
referenced ?our ASP+ Repeater control. Calling
Container.DataItem("Special") and Container.DataItem("Session_ID")
passes to the function the values of those columns in the parent object
(the ASP+ Repeater control).

Working With Session Variables
The existing ASP version of eVille prevented access to portions of the
site unless the user logged in. Functionality such as viewing upcoming
special offers, enrolling in classes and viewing your current enrollment
are protected areas. Trying to access these d for new members to enter their
vital
information, and for existing members to update their information. In
its original state, the form data was passed (in an HTTP Post) to a page
called cookie.asp. This page would evaluate the form data, and if there
was an error, redirect back to signup.asp with an error number in the
query string. A Select Case statement would alter the output based on
the error number. Errors we checked for were:

No User Name entered
No Password entered
Password and Confirm Pidentified in the
ControlToValidate field:

<tr>
<td valign="top">
<asp:RequiredFieldValidator runat=server
   ControlToValidate = "txtUserName"
   Display = "static"
   errorMessage="<b>*</b>"
   ForeColor = "#CC3300" />
</td>
<td valign=top>User Name:</td>
<td valign=top>
<asp:TextBox id="txtUserName" size=25 runat=server /></td>
</tr>

This was such an easy solution, that we decided to add
RequiredFieldValidator to all the input fields on the form. Rather than
writing a VBScript function to check for values entered, as we would do
in ASP, we simply add the RequiredFieldValidator for each control we
want to validate.

For the Password and Confirm Password comparison we used the ASP+
CompareValidator. This control enables us to set the ControlToValidate
and ControlToCompare properties, and the Operator property ('Equal' in
this example). The two controls specified are compared to each other
using the Operator property. This was obviously a much easier and
quicker solution to building an If...Then sk for ?if the User Name being
submitted
was already being used ?required a bit of page redesign. So far, we have
done all of the ASP+ validation with Server Controls that render either
client杝ide or server杝ide validation code. For this last error, we d to access
the
database to see if the requested User Name is available or not. For this
we used the ASP+ CustomValidator control.

With the CustomValidator control, we are able to write our own
validation code, either server杝ide or client杝ide, and validate against
it. In the original version of this site, we passed the form data to the
cookie.asp page, where the validation was done, and then passed back the
error code if one occurred. For simplicity in use, we are going to post
back to the signup.aspx page, validate the user input, and then redirect
if everything is OK. This enables us to have all of the validation
centralized on one ASP+ page (in ASP it was all centralized, but on the
cookie.asp page).


Here's how we validate the User Name with the CustomValidator:

Function ValidateUserName(ByVal objSource As Object, ByVal strUserName
As String) As Boolean
   Dim dscUser   As ADODataSetCommand
   Dim dsUser    As New DataSet
   Dim dvUser    As DataView
   Dim strSQL    As String

   strSQL = is taken.  Please chose another."
   ForeColor = "#CC3300"
   display = "dynamic"
   />
This control triggers the ValidateUserName function on the form post.
Using the DataSet we query the database for User Names that match the
User Name the person is requesting. If the name has been used, one
record will be returned, otherwise no records will be returned. To check
this, we bind the results to a hidden DataGrid (visible property set to
false), and then check its Items Collection, and Count property. Iken, we
display a message; otherwise, we can continue
processing the form.


Note that this type of validation is a workaround. There is a DataReader
control that is designed for this type of function. The DataReader can
perform evaluations of this type with out ever having to bind the data
to a DataGrid. However, in the ASP+ Alpha, there is a bug in the
DataReader, and it does not work. This will be repaired in the Beta 1
release. This workaround code was provided to get the site running in
ASP+ with the current .NET Framework.

Gathering Data from the User
Once all of the input has been validated, we go to cookie.aspx where we
will insert the data into our database, and log the user in. In
signup.aspx, once the data was validated, we set all of thtrUserName") =
Request.Form("txtUserName")
      Session("strPassword") = Request.Form("txtPassword")

      Response.Redirect("cookie.aspx")
   End If
. . .
End Sub
</script>

In cookie.aspx we create an ANSI朣QL statement using the Session
Variables as the values to enter. We could just as easily used
name/value pairs in the QueryString to get the same result. To insert
the values in the database, we make use of the ADOCommand object. We
pass the SQL string and ADOConnection object into ADOCommand. Once we
have setup the ADOCommand, we open the connection, and call
ADOCommand.Execute:

<script language="VB" runat="server">
Sub Page_Load(Source As Object, E As EventArgs)
   Dim cnCon   As New ADOConnection
   Dim dcAdd   As ADOCommand
   Dim strSQL  & _
            "'" & Session("strLName") & "', " & _
            "'" & Session("strAddress") & "', " & _
            "'" & Session("strCity") & "', " & _
            "'" & Session("strState") & "', " & _
            "'" & Session("strZipcode") & "', " & _
            "'" & Session("strPhone") & "', " & _
            "'" & Session("strEmail") & "', " & _
            "'" & Session("strUserName") & "', " & _
            "'" & Session("strPassword") & "'" & _
            ")"

   cnCon = Connect.ConnectToDB()
   dcAdd = New ADOCommand(strSQL, cnCon)
   cnCon.Open()
   dcAdd.Execute()
End Sub
</script>

The new data is added to the database, and our new Student is logged in.
Similar functionality was used to insert Student_ID and Session_ID into
the Enrollmentables at a time without creating
additional objects.




--


   我想超越这平凡的生活,注定我暂时漂泊!

   我无法停止我内心的狂热,对未来的执着!

※ 来源:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.18.211]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店