Using PerlNET Components in ASP.NET

We saw the power of ASP.NET in conjunction with PerlASPX when authoring Web Forms and providing the server code in Perl for these forms. However, the ability of using existing PerlNET components as back-end in ASP.NET makes this platform perfect for authoring robust Web applications by putting the business logic in separate, independent .NET assemblies.

Roulette Component

We demonstrate this concept using the Roulette component we presented in Chapter 12. We altered its functionality to be suitable for more general use. The full code resides in the RouletteBackend folder under this chapter's samples. Here we present the fragments with major changes.


#
# Roulette.pm - ASP.NET Back-end
#

package OI::Samples::Roulette;
use namespace "OI.Samples";
use strict;

# Define Mixed type
=for interface
    [interface: mixed]
=cut

# Implements IResettable interface
=for interface
    [implements: IResettable]
    void Reset();
=cut

# Methods
=for interface
    # Add new stake
    void AddStake(int guess, num stake);
    # Roll the roulette - generate the result
    int Roll();
    # Update prizes for all gamblers
							private void UpdatePrizes(int result);
							# Obtain all Stakes
							wantarray! str[] GetStakes();
							# Obtain all Prizes
							wantarray! num[] GetPrizes();
=cut


# Private Data Member: Last Gambler ID
=for interface
    private field int f_LastGambler;
=cut

sub Roulette
{
    my ($this, $self) = @_;
    $this->{f_LastGambler} = 0;
    $self->{Stakes} = [];
    $self->{Prizes} = [];
}
. . .

sub Roll
{
    # We do not retrieve $self since we do not need it
    my $this = shift;

    my $result = int(rand(37));
    $this->UpdatePrizes($result);

    return $result;
}

sub UpdatePrizes
							{
							my ($this, $self, $result) = @_;
							$self->{Prizes} = [];
							my ($guess, $stake, $prize);
							for (my $i = 0; $i < $this->{f_LastGambler}; $i++)
							{
							$guess = $self->{Stakes}->[$i][0];
							$stake = $self->{Stakes}->[$i][1];
							$prize = ($result == $guess ? 36*$stake : 0);
							$self->{Prizes}->[$i] = $prize;
							}
							}
							sub GetStakes
							{
							my ($this, $self) = @_;
							my @stakes;
							for (my $i = 0; $i < $this->{f_LastGambler}; $i++)
							{
							my $str = "Gambler " . int($i+1) . ": ";
							$str = $str . "Guess = " .
							$self->{Stakes}->[$i][0] . "; ";
							$str = $str . "Stake = " .
							$self->{Stakes}->[$i][1];
							$stakes[$i] = $str;
							}
							return (@stakes);
							}
							sub GetPrizes
							{
							my ($this, $self) = @_;
							my $prizes = $self->{Prizes};
							return(@$prizes);
							}
							. . .
						

The main changes are the addition of two methods—GetStakes and GetPrizes—that return arrays of gamblers' stakes and the gamblers' prizes respectively. We may then use these arrays for displaying the relevant information.

Roulette Web Application

Under this chapter's samples, you should create a new Web application for the Roulette folder. In this folder is an empty bin folder, where assemblies for the PerlNET components we are going to use in our ASP.NET application should reside. We prepared the build.bat script, which will compile and place all the required assemblies into the bin directory.

After creating a Web application in IIS and running build.bat, you may run Roulette by opening the http://localhost/NetPerl/Roulette/Stakes.aspx URL. Figure 16-13 shows the Web page you should see in your browser.

Figure 16-13. Roulette Web application.


You may add new stakes, reset them, and roll the roulette to obtain the results of the round. All the work behind the scenes is done by the Roulette component.

GLOBAL.ASAX FOR ROULETTE APPLICATION

We instantiate a new Roulette object for each user session. The most suitable place for this instantiation code is Global.asax. In this sample we created the code-behind file Global.asax.pm. Inside Global.asax we reference it with the following directive:

<%@ Application SRC="Global.asax.pm" Inherits="Global" %>

In addition, we reference two required assemblies using the following directives:

<%@ Assembly Name="roulette" %>
<%@ Assembly Name="IResettable" %>

ASP.NET looks for the referenced assemblies in the bin folder of our Web application. In the code-behind we declare the Global class, which inherits from the System.Web.HttpApplication class. We handle the Session_Start event, where we create a new Roulette instance and store it as a session variable (the bolded lines in the code below). Here is the code for Global.asax.pm.

#
# Global.asax.pm
#

use namespace "System";
use namespace "System.Collections";
use namespace "System.ComponentModel";
use namespace "System.Web";
use namespace "System.Web.SessionState";
use namespace "OI.Samples";

package Global;

=for interface
   [extends: System.Web.HttpApplication]
   protected void Session_Start(any sender, EventArgs e);
=cut

sub Session_Start
{
   my $this = shift;

   $this->{Session}->set_Item("Roulette",
								"OI.Samples.Roulette"->new());
}

STAKES.ASPX

Here is the PerlNET =for interface block definition for the code-behind of Stakes.aspx.

#
# Stakes.aspx.pm
#

package StakesPage;

use namespace "System";
use namespace "System.Collections";
use namespace "System.Web";
use namespace "System.Web.UI";
use namespace "System.Web.UI.WebControls";
use namespace "System.Data";
use namespace "OI.Samples";

use PerlNET qw(AUTOCALL int double in);
=for interface
   [extends: System.Web.UI.Page]
   protected override void OnLoad(EventArgs e);
   void btnAddStake_Click(any source, EventArgs e);
   void btnRoll_Click(any source, EventArgs e);
   void btnReset_Click(any source, EventArgs e);
   protected void BindControls();
   protected ICollection CreateDataSource(str name, 
                                          any array);
   protected field Label lblMsg;
   protected field TextBox txtGuess;
   protected field TextBox txtStake;
   protected field Label lblResult;
   protected field DataGrid dgStakes;
   protected field DataGrid dgPrizes;
=cut

In the code-behind file of the Stakes.aspx Web Form, which defines the StakesPage class, we retrieve the Roulette session variable (the reference to the Roulette class) and invoke the appropriate methods. For example, in response to the user pressing the Add Stake button, the following code will be executed:

sub btnAddStake_Click
{
   my $this = shift;

   my $roulette = $this->{Session}->get_Item("Roulette");

   my $guess = int($this->{txtGuess}->{Text});
   my $stake = double($this->{txtStake}->{Text});
   $roulette->AddStake($guess, $stake);

   . . .
}

The bolded lines show the work with our Roulette component.

BINDING LIST CONTROLS TO DATA SOURCES

In the code of Stakes.aspx we used the DataGrid controls to display the data about gamblers' stakes and their prizes (dgStakes and dgPrizes). For example, here is the ASP.NET code for the stakes DataGrid.

<asp:DataGrid id="dgStakes" RUNAT="SERVER"
      BorderColor="black"
      BorderWidth="1"
      GridLines="Both"
      CellPadding="3"
      CellSpacing="0"
      HeaderStyle-BackColor="#aaaadd"/>

These controls can be bound to certain data sources and display the data in tabular form. We should set the DataSource property for such controls and call the DataBind method to bring the data into control. The requirement of DataSource is implementing the IEnumerable interface.

We bind the controls inside our BindControls method of the StakesPage class:

sub BindControls
{
   my $this = shift;

   my $roulette = $this->{Session}->get_Item("Roulette");

   my $stakes = $roulette->GetStakes();
   my $ds = $this->CreateDataSource("Stakes", $stakes);
   $this->{dgStakes}->{DataSource} = $ds;
								$this->{dgStakes}->DataBind();
								my $prizes = $roulette->GetPrizes();
   $ds = $this->CreateDataSource("Prizes", $prizes);
   $this->{dgPrizes}->{DataSource} = $ds;
								$this->{dgPrizes}->DataBind();
}

We call the appropriate methods on the $roulette reference to obtain the Stakes and Prizes arrays. Then we create the data source with the help of the CreateDataSource method, passing to it the name string and the array with data. This method creates the DataTable and fills it in with the data from the provided array. The name for the single column of the data table is determined by the first argument of this method. Then the DataView based on the DataTable object is created and returned by CreateDataSource.

sub CreateDataSource
{
   my ($this, $name, $array) = @_;

   if (!defined $array)
   {
      return;
   }
   my $dt = "DataTable"->new();
   $dt->{Columns}->Add("DataColumn"->new($name, 
             "Type"->GetType("System.String")));
   foreach my $item(in $array)
   {
      my $dr = $dt->NewRow();
      $dr->[0] = $item;
      $dt->{Rows}->Add($dr);
   }

   return("DataView"->new($dt));
}

The data view is bound to the appropriate control and the data is displayed on Web page. Figure 16-14 shows Stakes.aspx with stakes and prizes data inside DataGrid controls, which are displayed as regular HTML tables.

Figure 16-14. Stakes.aspx with gambling and prizes data.


Note that along the way we work with the Roulette component in ASP.NET as we do in a regular PerlNET client program.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.33.107