Migrating the Application

Snoops

   

 
Migrating to .NET: A Pragmatic Path to Visual Basic .NET, Visual C++ .NET, and ASP.NET
By Dhananjay  Katre, Prashant  Halari, Narayana  Rao  Surapaneni, Manu  Gupta, Meghana  Deshpande

Table of Contents
Chapter 13.   Case Study: ASP to ASP.NET


Architecture

The architecture of the migrated application appears as shown in Figure 13-12. The requests received by the Web server are processed by the ASP.NET Web application. The ASP.NET application uses all three components used by the original ASP application, (i.e., VBLoginCOM , VBAdminCOM , and VBBuySellCOM ). We have migrated VBLoginCOM to a .NET component, used the interoperability features for VBAdminCOM , and exposed VBBuySellCOM as a Web service using SOAP ToolKit. Minimal changes were made to the GUI and most of the client-side code was maintained as is. We will cover migration of the application, keeping in mind the actual flow of logic.

Figure 13-12. Architecture of migrated ASP.NET application.

graphics/13fig12.gif

A new Web application Stock_Trading_NET is created in .NET using Visual Studio .NET and all files in the ASP application are added to the new application. Before we begin with migration, we declare the two most commonly used variables across the application in the global.asax :

 Public Shared errMsg As Boolean  Public Shared strMsg As String 

The variable errMsg is initialized to False under the method Session_ Start .

Customer Module

We begin migration of the application with the Customer module. The first page in the Customer module, login_customer.asp , is renamed to login_customer.aspx . The @Page directive is at the start of the page with the Language=VB and Explicit=true attributes. Following this is the @Import directive, pointing to the namespace Stock_Trading_NET.Global formed by compiling the global.assax.vb under the project workspace. This makes the global variables accessible at the page level. All the variables are declared explicitly as required by the attribute Explicit=true :

 graphics/icon01.gif dim strLogin as String  dim k as integer  dim strLogout as String  dim strChange as String 

The functions changePassword , validateUser , fnpage , and userLogout are enclosed in the <script> ... </script > tags. These functions refer to various methods of the VBLoginCOM component.

Migrating VBLoginCOM

VBLoginCOM is migrated into a .NET component. When the original Visual Basic project containing the code is run through the upgrade wizard, the class file Login.cls is converted into Login.vb . The upgrade report for the migrated component is shown in Figure 13-13. As shown in the report, the .NET Framework does not support data type Any , which is in the function declaration for GetPrivateProfileString and hence raises a compile error:

Figure 13-13. Upgrade Report for VBLoginCOM.

graphics/13fig13.jpg

 graphics/icon01.gif Private Declare Function GetPrivateProfileString Lib "ker_  nel32" Alias "GetPrivateProfileStringA" (ByVal lpApplica_  tionName As String, ByVal lpKeyName As  Any  , ByVal lpDefault_ As  String, ByVal lpReturnedString As String, ByVal nSize As_ Long,  ByVal lpFileName As String) As Long 

This is changed to data type String :

 graphics/icon01.gif Private Declare Function GetPrivateProfileString Lib  "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplica- tionName As String, ByVal lpKeyName As  String  , ByVal lpDefault  As String, ByVal lpReturnedString As String, ByVal nSize As  Integer, ByVal lpFileName As String) As Integer 

The upgrade report shows a runtime warning for being unable to resolve the default property for a variable strMessage. The variable was declared as data type Variant in the Visual Basic 6.0 component code:

 Public Function Login(strUserID As String, strpassword As  String, ByRef strMessage As  Variant  ) As Integer 

This warning occurs because variants are no longer supported under the .NET Framework. The data type Variant is converted into the default data type for the .NET Framework, Object , during migration. The variable is declared as data type String in the upgraded version:

 Public Function Login(ByRef strUserID As String, ByRef str- password As String, ByRef strMessage As  String  ) As Short 

After making these changes in the upgraded code, Login.vb is compiled into its assembly VBLoginCOM.dll . This assembly is added as a reference to the .NET Web application Stock_Trading_NET . The function validateUser is then rewritten as follows :

 graphics/icon01.gif function validateUser()            dim objLogin as VBLoginCOM.cLogin            dim usrName as String            dim usrPwd as String            dim strMessage as String            dim intLogin as integer            usrName = trim(Request.Form("txtID"))            if trim(Request.Form("txtNewPWD")) <> "" then                  usrPwd = trim(Request.Form("txtNewPWD"))            else                  usrPwd = trim(Request.Form("txtPWD"))            end if            strMessage=""            objLogin = new VBLoginCOM.cLogin()            intLogin = objLogin.Login(cstr(usrName), _  cstr(usrPwd), strMessage)            objLogin = nothing            if intLogin <> 0 then                  validateUser = strMessage            else                  validateUser = ""            end if      end function 

The variables local to the function are declared explicitly within the function, and early binding is used to instantiate the new component. All the functions using the component are rewritten in a similar manner.

After successful login, the user is taken to page that was welcome.asp in the original application and is now renamed welcome.aspx . This page uses ADO.NET to fetch the user name from the database. The following code shows the use of SQLConnection , SqlCommand, and SqlDataReader objects.

 graphics/icon01.gif <%@ Import Namespace="System.Data"%>  <%@ Import Namespace="System.Data.SqlClient"%>      dim strConnect as String      dim objCommand as SQLCommand      dim con as SqlConnection      dim rsUser as SQLDataReader      dim strSQL as String      strConnect="server=pc-     p3793;uid=sa;pwd=;database=Stock_System"      strSQL = "select CustomerName from Customer where Cus_      tomerID='" & Session("userID") & "' "      con = new SqlConnection(strConnect)      objCommand  = new SQLCommand(strSQL, con)      con.open()      rsUser = objCommand.ExecuteReader()      rsUser.read() 

The menu links on the page welcome.aspx are all changed to point to .aspx files.

After clicking Buy Stocks, the user is taken to the page stockservice. aspx . In the ASP application, this page makes use of the component VBBuySellCOM . For the .NET application, we have exposed this component as a Web service using the SOAP ToolKit and used the Web service in this page.

Exposing VBBuySellCOM as Web Service

The SOAP ToolKit is run over the Visual Basic COM DLL VBBuySellCOM.dll , as explained in Chapter 11, and the corresponding WSDL and WSML files are generated. We have selected ISAPI as the listener, so no ASP listener file is generated. The generated files are named cBuySell.wsdl and cBuySell.wsml . The files are located in the root of the Web application, so the SOAP address location in the WSDL file points to its current location as follows:

 <soap:address location='http://localhost/Stock_Trading_NET/  cBuySell.WSDL' /> 

The proxy class file is generated using the command-line tool wsdl.exe with this WSDL file as its input. The following command is used to generate the proxy class:

 C:\wsdl /l:VB /namespace:VBBuySellCOM /out:BuySell.vb http://  localhost/Stock_Trading_NET/cBuySell.wsdl 

The proxy class BuySell.vb follows:

 graphics/icon01.gif Option Strict Off  Option Explicit On  Imports System  Imports System.ComponentModel  Imports System.Diagnostics  Imports System.Web.Services  Imports System.Web.Services.Protocols  Imports System.Xml.Serialization  '  'This source code was auto-generated by wsdl, Ver- sion=1.0.3705.0.  '  Namespace VBBuySellCOM      '<remarks/>      'CODEGEN: The optional WSDL extension element 'binding'  from namespace 'http://schemas.microsoft.com/soap-toolkit/  wsdl-extension' was not handled.      <System.Diagnostics.DebuggerStepThroughAttribute(),  _       System.ComponentModel.       DesignerCategoryAttribute("code"),  _       System.Web.Services.       WebServiceBindingAttribute(Name:="cBuySellSoapBinding",       [Namespace]:="http://tempuri.org/wsdl/")>  _      Public Class cBuySell          Inherits System.Web.Services.          Protocols.SoapHttpClientProtocol          '<remarks/>          Public Sub New()              MyBase.New             Me.Url =            "http://localhost/Stock_Trading_NET/cBuySell.WSDL"          End Sub          '<remarks/>          <System.Web.Services.Protocols.SoapRpcMethodAt- tribute("http://t_  empuri.org/action/cBuySell.PlaceOrder", _  RequestNamespace:="http://tempuri.org/message/", _  ResponseNamespace:="http://tempuri.org/message/")>  _          Public Function PlaceOrder(ByRef strCustomerID As _          String, ByRef StockId As String, ByRef StockPrice _          As Double, ByRef Quantity As Short, ByRef BuySell _          As String, ByRef strMessage As String) As _         <System.Xml.Serialization.          SoapElementAttribute("Result")> Short           Dim results() As Object = Me.Invoke("PlaceOrder",_           New Object() {strCustomerID, StockId, StockPrice,_           Quantity, BuySell, strMessage})              strCustomerID = CType(results(1),String)              StockId = CType(results(2),String)              StockPrice = CType(results(3),Double)              Quantity = CType(results(4),Short)              BuySell = CType(results(5),String)              strMessage = CType(results(6),String)              Return CType(results(0),Short)          End Function          '<remarks/>         Public Function BeginPlaceOrder(ByVal strCustomerID_         As String, ByVal StockId As String, ByVal StockPrice_         As Double, ByVal Quantity As Short, ByVal BuySell As_         String, ByVal strMessage As String, ByVal callback_         As System.AsyncCallback, ByVal asyncState As Object)_         As System.IAsyncResult              Return Me.BeginInvoke("PlaceOrder", New Object()              {strCustomerID, StockId, StockPrice, Quantity, _              BuySell, strMessage}, callback, asyncState)          End Function          '<remarks/>          Public Function EndPlaceOrder(ByVal asyncResult As_          System.IAsyncResult, ByRef strCustomerID As String,_          ByRef StockId As String, ByRef StockPrice As _          Double, ByRef Quantity As Short, ByRef BuySell As _          String, ByRef strMessage As String) As Short              Dim results() As Object =              Me.EndInvoke(asyncResult)              strCustomerID = CType(results(1),String)              StockId = CType(results(2),String)              StockPrice = CType(results(3),Double)              Quantity = CType(results(4),Short)              BuySell = CType(results(5),String)              strMessage = CType(results(6),String)              Return CType(results(0),Short)          End Function      End Class  End Namespace 

The proxy class shows the exposed method PlaceOrder of the component and the asynchronous methods BeginPlaceOrder and EndPlaceOrder . The proxy class is now compiled into a .NET assembly using a Visual Basic compiler provided by the command-line tool vbc.exe . The following command compiles the proxy class and creates an assembly:

 C:\vbc /t:library /r:System.dll /r:System.Web.dll  /r:System.Web.Services.dll /r:System.Xml.dll BuySell.vb 

The newly created assembly BuySell.dll is placed in the /bin directory of the .NET Web application. Before calling the Web service on the page stock_service.aspx , the function createParameters returns an array of the parameters required for the Web Service method PlaceOrder . The array is then split up and the Web service method is called as follows:

 graphics/icon01.gif dim objTrade as VBBuySellCOM.cBuySell  dim strParameters as String  dim arrParameters  dim intTrade as integer  dim strMessage as String  strParameters = createParameters()  arrParameters = split(strParameters  , ",")  strMessage = ""  'To call the COM method  objTrade = new VBBuySellCOM.cBuySell()  intTrade = objTrade.PlaceOrder(cstr(arrParameters(0)), _  cstr(arrParameters(1)), cdbl(arrParameters(2)), _  cint(arrParameters(3)), "B", strMessage) 

This method is also called for selling of stocks, except that the query string value indicates that it is a sell transaction. The call to the method for selling stocks is as follows:

 graphics/icon01.gif dim objTrade as VBBuySellCOM.cBuySell  dim strParameters as String  dim arrParameters  dim intTrade as integer  dim strMessage as String  strParameters = createParameters()  arrParameters = split(strParameters  , ",")  strMessage = ""  'To call the COM method  objTrade = new VBBuySellCOM.cBuySell()  intTrade = objTrade.PlaceOrder(cstr(arrParameters(0)), _  cstr(arrParameters(1)), cdbl(arrParameters(2)), _  cint(arrParameters(3)), "S", strMessage) 

After clicking View Report, the user is taken to the page show_report.aspx to view the details of his or her portfolio. This page makes use of dataset to retrieve and display the records. The function createDataSet returns a dataset. An error flag is set if the dataset is empty and this is checked before displaying the contents of the dataset.

Admin Module

In this module we use the VBAdminCOM by adding it as a reference to the Web application. This creates the interoperability layer, which allows accessing the methods of the component as if it were a regular .NET assembly. The page login_Admin.aspx calls the COM methods for Login and ChangePassword. The function validateUser is not changed except that all the variables are declared explicitly:

 graphics/icon01.gif function validateUser()            dim objLogin as VBAdminCom.cAdmin            dim usrName as String            dim usrPwd as String            dim strMessage as String            dim intLogin as Short            usrName = trim(Request.Form("txtID"))            if trim(Request.Form("txtNewPWD")) <> "" then                  usrPwd = trim(Request.Form("txtNewPWD"))            else                  usrPwd = trim(Request.Form("txtPWD"))            end if            strMessage=""            objLogin = new VBAdminCom.cAdmin()            intLogin = objLogin.Login(cstr(usrName), _  cstr(usrPwd), strMessage)            objLogin = nothing            if intLogin <> 0 then                  validateUser = strMessage            else                  validateUser = ""            end if      end function 

Thus, the COM calls remain unchanged across the module. Under the menu Approve Orders, all unapproved orders are listed based on the selection made by the user. The page approveorder.aspx calls a stored procedure sp_Get_Unapproved_Orders directly as follows:

 graphics/icon01.gif Dim Customer  Dim buy_sell  Dim order_id  Dim strMessage  Dim status  Dim strConnect as String  Dim objCommand as SQLCommand  Dim Con as SQLConnection  Dim rsOrder as SQLDataReader  Dim strCommandText as String  Dim objParam as SQLParameter  Customer = TRIM(Request("lstCustomer"))  buy_sell = TRIM(Request("lstType"))  errMsg = false  strConnect="server=pc-p3793;uid=sa;pwd=;database=Stock_System"  strCommandText = "sp_Get_Unapproved_Orders"  Con = new SqlConnection(strConnect)  objCommand  = new SQLCommand(strCommandText, Con)  objCommand.CommandType = CommandType.StoredProcedure  objParam = objCommand.Parameters.Add("@ReturnCode", SqlDb- Type.Int)  objParam.Direction = ParameterDirection.ReturnValue  objParam = objCommand.Parameters.Add("@p_CustomerID", SqlDb- Type.VarChar, 8)  objParam.Direction = ParameterDirection.Input  objParam.Value = Customer  objParam = objCommand.Parameters.Add("@p_Buy_Sell", SqlDb- Type.Char, 1)  objParam.Direction = ParameterDirection.Input  objParam.Value = buy_sell  objParam = objCommand.Parameters.Add("@p_Status", SqlDb- Type.Int)  objParam.Direction = ParameterDirection.Output  objParam = objCommand.Parameters.Add("@p_Message", SqlDb- Type.NVarChar, 1000)  objParam.Direction = ParameterDirection.Output  Con.open()  rsOrder = objCommand.ExecuteReader()  if not rsOrder.read() then      strMsg = "There are no orders to be approved..."      errMsg=true    end if 

On the page addcustomer.aspx , the HTML controls are replaced with server-side controls. We have also used validation controls so that the server-side validation routine is eliminated. The following code shows a server-side text control for accepting Customer Name and its associated RequiredFieldValidator control.

 graphics/icon01.gif <asp:textbox id="txtCustName" Runat="server" MaxLength="20"  TextMode="SingleLine"></asp:textbox>  <asp:requiredfieldvalidator id="Requiredfieldvalidator3"  Runat="server" Display="None" ErrorMessage="You must enter a  Customer's Name." InitialValue="" ControlToValidate="txtCust- Name"></asp:requiredfieldvalidator> 

A validation summary control is used to list the validation errors:

 graphics/icon01.gif <asp:validationsummary id="ValidationSummary1" ShowSum- mary="True" DisplayMode="BulletList" HeaderText="List of  Errors in submitting the page" Runat="server"></asp:valida- tionsummary> 

We have used the code-behind in this form to call the COM method for adding customer; this is done within the Page_Load event:

 graphics/icon01.gif Private Sub Page_Load(ByVal sender As System.Object, ByVal e As  System.EventArgs) Handles MyBase.Load          errMsg = False          If Page.IsPostBack () Then              Try                  strCustID = txtCustId.Text                  strPassword = txtCustPass.Text                  strCustomerName = txtCustName.Text                  strAddress = txtCustAddress.Text                  intPhone = Integer.Parse(txtCustPhone.Text)                  strEmail = txtCustEmail.Text                  intMarginAmount =  Double.Parse(txtMargin.Text)                  intMinBal = Integer.Parse(txtBalance.Text)                  strMessage = ""                  objCustomer = New VBAdminCom.cAdmin()                  intCust = objCustomer.AddUser(strCustID,                strPassword, strCustomerName, strAddress, intPhone,                  strEmail, intMarginAmount, intMinBal, strMessage)                  If intCust = 0 Then                      Server.Transfer("welcome.aspx", False)                  Else                      errMsg = True                      strMsg = strMessage                  End If              Catch ex As Exception                  errMsg = True                  strMsg = "Failed to add customer." & _                  ex.Message & " "              End Try          End If      End Sub 

We have used structured exception handling to trap exceptions that arise if a wrong value is entered into the database. This is possible because we have used RequiredFieldValidator controls, which will only prevent blank values from being sent across.

We use the variable errMsg as an error flag across the application. In case of an error, say if a data reader is empty, we set the flag to True and assign an appropriate error message to the variable strMsg . At the start of the page, we check for the error flag and display the error message as shown:

 graphics/icon01.gif if errMsg then  Response.Write("<div class=errorMsg align=center>" & strMsg_  & "</div>")  Response.Write("<div align=center><input type=button  class=button value=Back onClick=""document.frmStockser- vice.action='welcome.aspx';document.frmStockservice.sub- mit();""></div>")  Response.End  end if 

To prevent the browser from caching, we use the following lines of code across the application:

 graphics/icon01.gif Response.Expires = 60  Response.AddHeader("pragma","no-cache")  Response.AddHeader("cache-control","private")  Response.CacheControl = "no-cache" 

In this code the following one line is missing when compared to the ASP code to prevent caching:

 Response.Expiresabsolute = Now()  1 

This code uses an arithmetic operation over a function returning the date and time. Because there is no explicit type conversion involved here, this line throws an error for invalid character detected after Now . The rest of the code, as before, uses properties of the Response object to prevent caching.


Snoops

   
Top


Migrating to. NET. A Pragmatic Path to Visual Basic. NET, Visual C++. NET, and ASP. NET
Migrating to. NET. A Pragmatic Path to Visual Basic. NET, Visual C++. NET, and ASP. NET
ISBN: 131009621
EAN: N/A
Year: 2001
Pages: 149

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