ASNA Visual RPG Web Tutorial

Adding code to the second form

With the interface elements in place, it's time to add code to the CustomerDetails.aspx code-behind. If it's not showing, use the Solution Explorer (View|Solution Explorer) to navigate to the CustomerDetails.aspx file. Right-click that file in the Solution Explorer and a context menu is displayed as shown below. You can use this to view either CustomerDetails.aspx or its code-behind. In this case, we want to see the Web form, so we'll select "View Designer."

With CustomerDetails.aspx showing in Visual Studio, double-click its OK button. This opens the code-behind editing window for this form, and stubs in the btnOK_Click event for you (the subroutine that's executed when the OK button is clicked).

1. Add the OK button click event code.

In that btnOK_Click event add this line of code:

Response.Redirect( "Default.aspx" ) 

this is the code that will redirect the users back to the Default.aspx page when they're done looking at customer details.

2. Add a DB declaration and an F-Spec

Now, scroll up to the top of the code, and immediately after the line that starts with "BegClass," add this code (the entire code for this code-behind is shown at the bottom of the page):

    DclDB pgmDB DBName( "DG Net Local" )

    DclDiskFile  Cust                   +
          Type( *Input  )               +
          Org( *Indexed )               +
          File( "Examples/CMastNewL1" ) +
          DB( pgmDB )                   +
          ImpOpen( *No )  

This code specifies the database platform and an F-spec. The DclDB object is named pgmDB in this program. It connects to a database named "DG Net Local". We'll review database connections later, but for now, understand that this database name looks up database connection attributes in the PC's registry. These connection attributes are used to connect your AVR program to that database. DG Net Local is the default database name given to the sample data you downloaded back at the beginning of step 3. This database name connects your program to your local ASNA PC database. We'll discuss connecting this application to your IBM i in a later step.

The DclDiskFile should be relatively obvious, if slightly syntactically mysterious. If you come from an IBM i background, think of the DclDiskFile like this: Imagine what RPG's old-fashioned column-oriented F-Spec would be like with CL's command interface applied to it (see Getting to Know AVR for .NET, which covers AVR's "command" syntax in more detail). The DclDiskFile uses keywords to specify various attributes of the file being declared. In this case:

In Web applications, files are almost always opened explicitly to give you better programmatic control when errors occur during the open. Having said that, we're skipping robust error handling in this example for the sake of brevity and clarity. A real-world application would have much more error checking than this one does.

3. Add the Page_Load event code

You page load already has a test to determine if Page.IsPostBack is occurring or not. Tweak your Page_Load slightly so that it looks like this:

        If ( NOT Page.IsPostBack )
            ExSr ReadCustomer
        EndIf

This code causes the program to read the customer information by calling the ReadCustomer subroutine. Because this program is so simple, ReadCustomer could have been called as is, conditioned by NOT Page.IsPostBack (indicating the first time the page is displayed during its event cycle) or unconditionally. While it doesn't matter in this program, it probably would in real programs, so we'll do like it we probably would in the real world and have ReadCustomer conditioned on NOT Page.IsPostBack.

4. Add the ReadCustomer subroutine

Add this subroutine after the Page_Load subroutine (like green screen RPG, you could really put this subroutine anywhere in the code, the order of subroutines don't matter.

    BegSr ReadCustomer
        // Connect to the database server.
        Connect pgmDB
        // Open the disk file.
        Open    Cust

        // Get the customer number from the cmcustno session variable.
        CMCustNo = Session[ "cmcustno" ].ToString()

        // Put the customer number in the customer number textbox.
        txtCMCustNo.Text  = CMCustNo

        // Chain into the Cust file with the customer number.
        Chain Cust Key( CMCustNo )
        // If the record was not found,
        If ( NOT %FOUND( Cust ) )
            // Show an error.
            lblErrorMsg.Visible = *True
        Else
            // Populate the user interface with data read from the record.
            txtCMName.Text     = CMName
            txtCMAddr1.Text    = CMAddr1
            txtCMCity.Text     = CMCity
            txtCMState.Text    = CMState
            txtCMPostCode.Text = CMPostCode
            txtCMPhone.Text    = CMPhone
            txtCMFax.Text      = %EDITW( CMFax, "0(   )&   -    " )

            // Set the ASPX page's title to the customer name just read.
            *This.Title = "Customer: " + CMName
        EndIf
    EndSr

The code is above is clearly commented, however a few parts of it need a little more description.

This line is fetching the customer number stored in the 'cmcustno' session variable and assigning it to the record format's CMCustNo field.

CMCustNo = Session[ "cmcustno" ].ToString()

The jarring part of this code is probably the .ToString() at the end. If you recall, in section 4, all we did to put a value in the session variable was do this:

Session[ "cmcustno" ] = txtCMCustNo.Text 

Notice that we didn't need to specify the data type of the session variable during the assignment. The downside to this convenience is that you have to specify the data type when you take the variable back out.

CMCustNo = Session[ "cmcustno" ].ToString()

So, in the line above, the .ToString() says "convert whatever value is in the session variable to a string and move it to the CMCustNo field." Hmmm. Why a string when, if you look at the file layout we're using (as shown in Section 4), CMCustNo is a packed 9,0 value? Because it's easy! AVR's equal sign (=) operator essentially translates to an RPG MOVE operation. As you learn more about .NET, you'll learn there are other ways to convert values in session variables (and other similar data storage mechanisms). One more thing, where did the .ToString() come from!? It is a method, a subroutine, associated with the session variable. Remember, AVR for .NET is an object oriented language, and you're seeing just a glimpse of the power of OO here. The session variable comes to the party with his own set of built-in subroutines. (In fact, nearly everything in AVR is an object with its own set of party-ready methods!).

If the Chain fails with the the customer number provided, we need to get the user a message to that effect. This line of code sets the visible property of the lblErrorMsg label to true when the Chain fails. (Recall that we set lblErrorMsg's visible property to false while we were setting up the UI).

lblErrorMsg.Visible = *True

The line of code below is setting the page's title to reflect the name of customer currently being viewed. *This refers to "this page."

*This.Title = "Customer: " + CMName

5. Disconnect the database connection and close the file.

Before any page goes out of scope, you need to be sure to close all of its open files and disconnect its database. This may seem wrong at first, but remember, Web pages are stateless. When a page goes out of scope, everything on that page goes away (except for data you've explicitly saved like we did with the customer number to a session variable). It's important to close files and disconnect the database so that the database job can be pooled. Pooled jobs dramatically reduce connection time (reducing the time it takes to get a job on the IBM i from several seconds to just a few milliseconds). You'll learn more about connection pooling later, but for now understand that for it to work appropriately, you must also ensure files have been closed and the database connection is disconnected before the page is displayed.

For this program, we're going to do this in the page's Unload event. This event fires just prior to your application's response leaving the server. It is usually a good place to disconnect and close. To stub this event in, you use the two drop down boxes near the top of the editor.

In the left dropdown, select "(Page Events)." In the right dropdown, select "Unload." This stubs in the page's Unload event for you. Add these two lines of code in the Unload event.

        Close Cust
        Disconnect pgmDB

That's it! You're ready to run your program. Go to the next chapter.

The entire source code for CustomerDetails.aspx.vr is shown below.

Using System
Using System.Data
Using System.Configuration
Using System.Collections
Using System.Web
Using System.Web.Security
Using System.Web.UI
Using System.Web.UI.WebControls
Using System.Web.UI.WebControls.WebParts
Using System.Web.UI.HtmlControls

BegClass CustomerDetails Partial(*Yes) Access(*Public) Extends(System.Web.UI.Page)

    DclDB pgmDB DBName( "*Public/DG Net Local" )

    DclDiskFile  Cust                   +
          Type( *Input  )               +
          Org( *Indexed )               +
          File( "Examples/CMastNewL1" ) +
          DB( pgmDB )                   +
          ImpOpen( *No )

    BegSr Page_Load Access(*Private) Event(*This.Load)
        DclSrParm sender Type(*Object)
        DclSrParm e Type(System.EventArgs)

        If ( NOT Page.IsPostBack )
            ExSr ReadCustomer
        EndIf
    EndSr

    BegSr ReadCustomer
        // Connect to the database server.
        Connect pgmDB
        // Open the disk file.
        Open    Cust

        // Get the customer number from the cmcustno session variable.
        CMCustNo = Session[ "cmcustno" ].ToString()

        // Put the customer number in the customer number textbox.
        txtCMCustNo.Text    = CMCustNo

        // Chain into the Cust file with the customer number.
        Chain Cust Key( CMCustNo )
        // If the record was not found,
        If ( NOT %FOUND( Cust ) )
            // Show an error.
            lblErrorMsg.Visible = *True
        Else
            // Populate the user interface with data read from the record.
            txtCMName.Text     = CMName
            txtCMAddr1.Text    = CMAddr1
            txtCMCity.Text     = CMCity
            txtCMState.Text    = CMState
            txtCMPostCode.Text = CMPostCode
            txtCMPhone.Text    = CMPhone
            txtCMFax.Text      = %EDITW( CMFax, "0(   )&   -    " )

            // Set the ASPX page's title to the customer name just read.
            *This.Title = "Customer: " + CMName
        EndIf
    EndSr

    BegSr Page_Unload Access(*Private) Event(*This.Unload)
        DclSrParm sender Type(*Object)
        DclSrParm e Type(System.EventArgs)

        Close Cust
        Disconnect pgmDB
    EndSr

    BegSr btnOK_Click Access(*Private) Event(*This.btnOK.Click)
        DclSrParm sender Type(*Object)
        DclSrParm e Type(System.EventArgs)

        Response.Redirect( "Default.aspx" )
    EndSr
EndClass