DEMONSTRATIVE EXAMPLES
======================
WEB PAGE DEVELOPMENT V
=======================
For version 1.65 and later
THE MASTER PAGE FILE:
=====================
We'll copy WPDIII's master file unchanged. So, after creating the new application folder
WPDV and registering it at the Internet Information Services, copy the file "master1.cs"
from WPDIII to WPDV folder. Next step is to compile the file by executing the command
'pcwm master1' from command mode.
=========================================================================================
MEMBERSHIP AND AUTHENTICATION
=============================
Microsoft has done web developers a great favour by taking the full responsibility of creating
and maintaining databases for their clients' members. This includes controls which the members
fill in to register, to login or to change their passwords or to recover a forgotten password.
The entire process is automatically done, including sending an e-mail message with the password
to a member who has forgotten his password and correctly answered his password question.
To start you need to have Microsoft's SQL Server installed into your system. If you are not
ready to buy it yet, you can download the SQL Server 2005 Express Edition SP2 which is free.
Here is where to download it:
http://msdn2.microsoft.com/en-us/express/bb410792.aspx
Specifying the Membership Provider:
===================================
A membershipProvider is a class which contains all the logic necessary to handle authentication
and to maintain membership data. The MembershipProvider class must implement an abstract class
which sets the basic specs for all MembershipProvider classes. The "ASP.NET" gives you the option
of using one of two built-in classes, or to make your own MembershipProvider class using the
database of your choice.
Currently the (pasp) class recognizes two options. Either to use "AspNetSqlMembershipProvider"
which uses Microsoft's SQL database internally or to use no provider and do the data storage and
authentication by yourself.
To tell class (pasp) that you are using the "AspNetSqlMembershipProvider", include (mpa="a";)
into method init(). If you like to use no provider, include (mpa=""; or include nothing)
Setting the web.config file:
============================
Normally, some setup data is placed into the "web.config" file which should be available into the
application folder. The "web.config" file has a parent file which it inherits the rest of setup
data from. The parent name is "machine.config". It's located into a subfolder of the "Windows"
folder tree.
So far, we have been accepting all the default configurations in "machine.config" as is. So, we
have had no need for a "web.config" file. Now, this is going to be changed. There are two new
sets of configurations to be done:
(1) The "AspNetSqlMembershipProvider" which we'll be using is listed in the "Machine.config"
file. This means that if any of its default settings was unacceptable, we have to browse
to that file and change it there.
(2) Password recovery and Password Change require sending an e-mail message to the member. This
cannot be done unless your mail information is included into one of the two files.
So, we'are going to create a "web.config" file into the application directory and set our mailing
informations into it. Additionally, we'll look at the "machine.config" file and see if any of
the provider defaults need to be changed.
SETTING THE MAILING DATA:
-------------------------
Let us start with the mailing data. Copy this xml code to notepad, replace data with yours, then
save them into a file named "web.config" in your application directory.
IMPORTANT REMARK:
=================
We have added a space after each opening bracket to fix a display problem. You must eliminate
those spaces in your file.
< configuration>
< system.net>
< mailSettings>
< smtp from="Your e-mail address">
< network
host="Name of your SMTP (outgoing) mail server"
userName="Your user ID"
password="Your Password" />
< /smtp>
< /mailSettings>
< /system.net>
< /configuration>
THE PROVIDER's DEFAULTS:
------------------------
Let us see how to modify the "Machine.config" file. Assuming that the Windows folder is in the
root of the c: drive and the ".NET" version you have is "2.0", you can reach the "Machine.config"
containing folder from "My Computer" or the "Windows explorer" by browsing to:
c:\Windows\Microsoft.NET\Framework\v2.0\CONFIG
The first thing you need to do is to make a copy of the file which you may need in case the
original copy gets damaged. Right click on the file, select "Copy" then right click into an
empty area of the folder and select "Paste".
Read the file using NotePad. This is the section of interest to us:
IMPORTANT REMARK:
=================
We have added a space after each opening bracket to fix a display problem. You must eliminate
those spaces in your file.
< membership>
< providers>
< add name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="LocalSqlServer"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="/"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="4"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
passwordStrengthRegularExpression="" />
< /providers>
< /membership>
The items which you may need to change are as follows:
Password specs:
---------------
The length of the password and the number of Non alphanumeric Characters within it are settable.
You make the compromise between ease and security when you make this decision. You also decide
upon using question/answer to validate members when they forget their passwords.
requiresUniqueEmail:
--------------------
More than one identical e-mails can be a sign of duplicate member data, but they can also mean
two different persons from same family or same business.
maxInvalidPasswordAttempts & passwordAttemptWindow:
---------------------------------------------------
When you set the max attempts to "5" and the attempt window to "10", it means that a member can
enter upto 5 wrong passwords in 10 minutes without his account being locked out.
passwordFormat, enablePasswordRetrieval & enablePasswordReset:
--------------------------------------------------------------
The provider allows 3 choices for storing a password into the database:
(1) Clear: Store it as clear text.
(2) Hashed: Store the hash code of the password.
(3) Encrypted: Encrypting the password before storing it.
When a member forgets his password, the provider sends the password to him by email. You allow
that with (enablePasswordRetrieval="true"). A hashed password cannot be recovered, they can only
be reset, which means a new password is generated. So, in case of hashed passwords, retrieval
must be disabled and reset must be enabled. Encrypted passwords can be decrypted and retrieved.
Now, make your changes then save the file.
Creating Data Folder:
---------------------
Before you try the next example, you need to create a new folder into your application directory
named "App_Data". This is where Microsoft Database will be storing data.
The Login Control:
==================
The Login control is made of two text fields and a button. You can list it in method setup just
like you list all other controls. There are some unique settable parameters with this control
which are:
ib : If true, means turn on "Remember me" feature which causes the provider to create a
persistent cookie for the member which is stored at his computer. This eliminates the need
to login in the future.
The user can turn off the cookie by logging in again with the RememberMe CheckBox unchecked.
js : If you assign the URL of your registration page to (js), the phrase "New member? Click here
to Register." will be added to the Login control and when the user clicks on it, it will
take him to the Registration page.
ks : If you assign the URL of your password recovery page to (ks), the phrase "Forgot your
Pssword? Click here to recover it." will be added to the Login control and when the user
clicks on it, it will take him to the Password Recovery page.
ims: If you assign the URL of an icon to (ims), the icon will become the background image of
the Login button.
urs: You assign to (urs) the URL of the members page which a member should see after his login
data has been validated.
Notice that we prefer not to set size for the control in order to allow the browser to do this
job based on the control's contents.
Like with the text field and many other controls, you can assign a title to (cis) for any of
the membership controls. It can contain plain text or html and can be set above, under, right of
or left of the control by assigning "n", "s", "e" or "w" to (os) respectively. The default is "n".
What can be done in method update()?
------------------------------------
Method update is called with (cs="lo0") (assuming that "lo0" is your Login control's keyname),
after the user has enterd his data into the Login control and before the user is granted a
"login" status.
You can obtain user's data with wm("gu") You receive (ids) & (pss) containing the user ID
(also called UserName) and the user password respectively. After checking the data, you have
the power to do any of the following:
(1) You can change user ID setup before it's checked against the password. To do so, you assign
the new value to (ids) then call wm("su") Notice that you can't change the password setup.
(2) You can change the web page which the user was going to see after being logged-in. To do so,
assign the new page's URL to (urs) and call wm("sp") Notice that other users will still get
the original login page which was set into method setup()
(3) You can cancel the login process for the user by making the assignment (mpa="") Notice also
that this changes nothing to other users.
You may also neglect the call to method update() to let the login process go without interference
just like we are going to do in the next 4 examples.
==============================================================================================
Example 1: Create a Login page which contains the built-in Login control. Configure it
so that the ASP.NET Sql Provider does the entire operation. The Login control should contain
links to the registration page "register.aspx" and the password recovery page "recover.aspx"
which will be made next. It should also be able to remember members so they need not to login
during future visits. If login was successful, it should take them to the members page which
we'll consider "Members.aspx" to be it.
==============================================================================================
public partial class Login:master1 {
public override void init() {
mpa="a"; // Provider=Microsoft SqlProvider
base.init();
}
public override void setup() {
base.setup(); // Run setup() of master page first
//----------------------------------- tb2 Contents ----------------------------------
cns="tb2"; // tb2 is made of 1 col, 2 rows
cs="lb0";cis="MEMBERSHIP AND AUTHENTICATION";
j=0;k=0;ds="c";fns="trb14";cls="r0p7";wm("i");
wm("o");ds="c";cls="b0";fns="trbi12";
os="Microsoft has done web developers a great favour by taking the full responsibility";
os+=" of creating and maintaining databases for their clients' members. This includes ";
os+="controls which the members fill in to register, to login, to change their passwords or";
os+=" to recover a forgetten password. The entire process is automatically done, ";
os+="including sending an e-mail message with the password to a member who has forgotten";
os+=" his password and correctly answered his password question.";wm("dp");
wm("c");
cs="lt0";j=0;k=1;wm("i");
//----------------------------------- tb3 Contents ----------------------------------
cns="tb3"; // tb3 is made of 1 col, 1 row
cs="lo0";cis="";j=k=0;jd=5;ds="c";fns="trb10";cls="b0s9";
ib=true; // Turn "Remember Me" feature on.
js="NewAccount.aspx"; // Registration page
ks="RecoverPass.aspx"; // Password Recovery page
urs="Members.aspx"; // Members page.
wm("i");
//------------------------------------------------------------------------------------
}
public override void update() {
if(cs.Equals("pl")) { // If event is "Page_Load"
setup(); // Execute setup()
MakePage(table); // and Make the page
PageNumber(1); // Set page number
}
}
}
==============================================================================================
As usual, you generate the "aspx" file by entering: pcw Login from command mode.
We advise you to hold on checking this page until the next 4 pages are made.
==============================================================================================

===============================================================================================
The CreateUserWizard Control:
=============================
This control in its basic form, contains 6 text fields and a button. The text fields are
made to collect the following data from the user:
(1) User ID (or UserName) (2) Password (3) Confirm Password.
(4) E-Mail (5) Security Question (6) Security Answer.
The CreateUserWizard allows numerous setups. Method wm() helps with some only. If you like to
do more, request the control's object as follows:
cs="Control's keyname";wm("O");
The object reference will be returned to you assigned to (cup)
Special setups which are available:
-----------------------------------
ib : Do not require E-mail address.
ims: URL of a background image for the "CreateUser" button.
urs: URL of a web page which the user should see after his account has been created.
js : Name of a file which contains the body of the e-mail messages which will be sent to users
to inform them about the newly created account. If you do not like the e-mail messages to
be sent, keep js="".
What can be done into method update()?
--------------------------------------
Method update is called with (cs="cu0") (assuming that "cu0" is your Login control keyname),
after the user has enterd his or her data into the "CreateUserWizard" control and clicked the
"Create User" button, but before his data has been submitted to the provider or saved into the
database.
You can obtain user's data with wm("gu") You receive the array CUS[] which contains all the
supplied data in the following order:
CUS[0]=User ID CUS[1]=Password CUS[2]=ConfirmPassword
CUS[3]=Email CUS[4]=Question CUS[5]=Answer
If (ib) was set to (true) when the control was created, the number of fields will be 5 since
the E-mail field will be missing. Despite that CUS[] will still contain 6 rows with CUS[3]="".
Here is what you can do next.
(1) You can inspect the data, modify it in any way you like then call wm("su") with the new
values assigned to CUS[]. The database will contain your modified data. The only exceptions
are the "Password" and "Confirm Password" fields which cannot be changed.
(2) You can change the web page which the user was going to see after his account is created.
To do so, assign the new page's URL to (urs) and call wm("sp") Notice that other users will
still get the original page which was set into method setup()
(3) You can cancel the data saving process for the user by making the assignment (mpa="") Notice
also that this changes nothing to other users.
Just as with the Login control, you don't have to handle the event of this control. The process
is fully automatic. It can go by itself with you doing nothing.
==============================================================================================
Example 2: Create a Registration page which contains a "CreateUserWizard" control. After users
accounts have been successfully created, make them go back to the Login page.
==============================================================================================
Making the e-mail message body file:
------------------------------------
We'll name the file "NewAccount.txt" and will save it into the application folder. Here is
the file's text:
----------------------------------------------
You have just created a new account with us.
Your User ID and password are:
User ID : [ids]
Password: [pss]
Thank you for creating a new account with us.
----------------------------------------------
You must have noticed that the file contains variables which will be replacd with the unique
data of each user. The variables are made to the specs of "2 char's + type" variables which are
explained into the "Desktop referance". They must be enclosed between []. Here is a list of them:
User ID: [ids] Password: [pss] E-mail: [ems] Question: [qus] Answer: [ans]
The NewAccount class:
---------------------
public partial class NewAccount:master1 {
public override void init() {
mpa="a"; // Provider=Microsoft SqlProvider
base.init();
}
public override void setup() {
base.setup(); // Run setup() of master page first
//----------------------------------- tb2 Contents ----------------------------------
cns="tb2"; // tb2 is made of 1 col, 2 rows
cs="lb0";cis="MEMBERSHIP REGISTRATION";
j=0;k=0;ds="c";fns="trb14";cls="r0p7";wm("i");
wm("o");ds="c";cls="b0";fns="trbi12";
os="The 'CreateUserWizard' handles registration. It receives data from users, sends the";
os+=" data to the Membership provider who creates a new account for the user and saves";
os+=" the data into the database.";wm();wm();
os="After the account has been created successfully, it sends the user an e-mail message";
os+=" to inform him or her about the new account.";wm("dp");
wm("c");
cs="lt0";j=0;k=1;wm("i");
//--------------------------------------- tb3 Contents --------------------------------------
cns="tb3"; // tb2 is made of 1 col, 1 row
cs="cu0";cis="";j=k=0;ds="c";jd=5;fns="trb10";cls="b0s9";
urs="Login.aspx"; // Goto Login page after new account is done
js="NewAccount.txt"; // Send e-mail message to users using this
wm("i"); // file's text as the message body.
//-------------------------------------------------------------------------------------------
}
public override void update() {
if(cs.Equals("pl")) { // If event is "Page_Load"
setup(); // Execute setup()
MakePage(table); // and Make the page
PageNumber(2); // Set page number
}
}
}
==============================================================================================

===============================================================================================
The ChangePassword Control:
===========================
The ChangePassword control requires the user to be logged in before accessing it. It asks the
user about his Current Password and his desired new Password. After the user has been validated,
it replaces his old password with the new one into the database.
The control can send an e-mail message to the user if you supply a file name which contains the
message body just like you did with the "CreateUserWizard". The file name is assigned to (js)
If you keep (js=""), no message will be sent.
Special setups which are available:
-----------------------------------
ims: URL of a background image for the "ChangePassword" button.
urs: URL of a web page which the user should see after his password has been changed.
What can be done into method update()?
--------------------------------------
Method update is called with (cs="cp0") (assuming that "cp0" is your ChangePassword control
keyname), after the user has enterd his data, but before his new password is saved.
You can obtain user's data with wm("gu") You receive the array CUS[] which contains all the
supplied data in the following order:
CUS[0]=User ID CUS[1]=Current Password CUS[2]=New Password CUS[3]=Confirm Password
(1) You can inspect the data, but you cannot change passwords.
(2) You can change the web page which the user was going to see after his password has been
changed. To do so, assign the new page's URL to (urs) and call wm("sp") Notice that other
users will still get the original page which was set into method setup()
(3) You can cancel the password change process for the user by making the assignment (mpa="")
Notice also that this changes nothing to other users.
Just as with all previous controls, you don't have to handle the event of this control. The
process is fully automatic. It can go by itself with you doing nothing.
==============================================================================================
Example 2: Create a "Change Password" page which contains a "ChangePassword" control. After
users passwords have been changed, make them receive a cofirmation e-mail message.
==============================================================================================
Making the e-mail message body file:
------------------------------------
We'll name the file "NewPassword.txt" and will save it into the application folder. Here is
the file's text:
----------------------------------------------
Upon your request, your password has been changed.
Your old and new passwords are:
Old Password: [cps]
New Password: [nps]
Thank you.
----------------------------------------------
We have discussed how to insert variables into the message before. The variables which you can use
here are:
User ID: [ids] Current Password: [cps] New Password: [nps]
The ChangePassword class:
-------------------------
public partial class ChangePass:master1 {
public override void init() {
mpa="a"; // Provider=Microsoft SqlProvider
base.init();
}
public override void setup() {
base.setup(); // Run setup() of master page first
//----------------------------------- tb2 Contents ----------------------------------
cns="tb2"; // tb2 is made of 1 col, 2 rows
cs="lb0";cis="CHANGING PASSWORDS";
j=0;k=0;ds="c";fns="trb14";cls="r0p7";wm("i");
wm("o");ds="c";cls="b0";fns="trbi12";
os="The 'ChangePassword' control asks the user about his Current Password and his desired";
os+=" new one. After the user has been validated, it replaces his old password with the";
os+=" new one into the database. Then an e-mail message is sent to inform the user of the";
os+=" change.";wm("dp");
wm("c");
cs="lt0";j=0;k=1;wm("i");
//----------------------------------- tb3 Contents ----------------------------------
cns="tb3"; // tb3 is made of 1 col, 1 row
cs="cp0";cis="";j=k=0;ds="c";jd=5;fns="trb10";cls="b0s9";
urs="Members.aspx"; // After done, return to the members' page.
js="NewPassword.txt"; // Send message to inform user of the change
wm("i"); // and use this file as the message body.
//------------------------------------------------------------------------------------
}
public override void update() {
if(cs.Equals("pl")) { // If event is "Page_Load"
setup(); // Execute setup()
MakePage(table); // and Make the page
PageNumber(3); // Set page number
}
}
}
==============================================================================================

===============================================================================================
The PasswordRecovery Control:
=============================
The Password recovery starts by obtaining your "User ID", then it presents you with your
password question and checks your answer, if it matches the answer in the database, it sends
the password to you by e-mail.
If password was stored in an encrypted format, it decrypts it first. If it was hashed, it
generates a new password and sends it to you.
Sending the password by e-mail is mandatory. You don't have to make a mail file like you do
for the "CreateUserWizard" and the "ChangePassword" controls.
Special setups which are available:
-----------------------------------
ims: URL of a background image for the "Submit" button.
urs: URL of a web page which the user should see after the job has been done.
What can be done into method update()?
--------------------------------------
Method update is called with (cs="pr0") (assuming that "pr0" is your PasswordRecovery control
keyname), after the user has enterd his or her data, but before his data has been submitted to
the provider or saved into the database.
You can obtain user's data with wm("gu") You receive the array CUS[] which contains all the
supplied data in the following order:
CUS[0]=User ID CUS[1]=Question CUS[2]=Answer
Here is what you can do next.
(1) You can inspect the data, but you cannot modify and set any but the User ID.
(2) You can change the web page which the user was going to see after his account is created.
To do so, assign the new page's URL to (urs) and call wm("sp") Notice that other users will
still get the original page which was set into method setup()
(3) You can cancel the data saving process for the user by making the assignment (mpa="") Notice
also that this changes nothing to other users.
Just as with all other controls, you don't have to handle the event of this control. The
process is fully automatic.
==============================================================================================
Example 2: Create a Password Recovery page which contains a "PasswordRecovery" control. After
user has been validated and the recovered password is mailed to him, return him to the Login
page.
==============================================================================================
The RecoverPass class:
----------------------
public partial class RecoverPass:master1 {
public override void init() {
mpa="a"; // Provider=Microsoft SqlProvider
base.init();
}
public override void setup() {
base.setup(); // Run setup() of master page first
//----------------------------------- tb2 Contents ----------------------------------
cns="tb2"; // tb2 is made of 1 col, 2 rows
cs="lb0";cis="PASSWORD RECOVERY";
j=0;k=0;ds="c";fns="trb14";cls="r0p7";wm("i");
wm("o");ds="c";cls="b0";fns="trbi12";
os="The Password recovery starts by obtaining your 'User ID', then it presents you with";
os+=" your password question and checks your answer, if it matches the answer in the ";
os+="database, it sends the password to you by e-mail.";wm();wm();
os="If password was stored in an encrypted format, it decrypts it first. If it was hashed,";
os+=" it generates a new password and sends it to you.";wm("dp");
wm("c");
cs="lt0";j=0;k=1;wm("i");
//----------------------------------- tb3 Contents ----------------------------------
cns="tb3"; // tb3 is made of 1 col, 1 row
cs="prp";cis="";j=k=0;ds="c";jd=5;fns="trb10";cls="b0s9";
urs="Login.aspx"; // Go to Login page after done.
wm("i");
//------------------------------------------------------------------------------------
}
public override void update() {
if(cs.Equals("pl")) { // If event is "Page_Load"
setup(); // Execute setup()
MakePage(table); // and Make the page
PageNumber(4); // Set page number
}
}
}
==============================================================================================

===============================================================================================
The rest of the Membership controls:
====================================
There are three more controls which do minor jobs like letting the user knows that he is logged
in, supply you with the logged-in username or help you in making your members' page different
than the page for anonymous users.
There seem to be a problem with those three controls. Despite the fact that Microsoft checks
software very well before it is released, the operation of the three controls works fine only
when pages are simple, with no inheritance or master pages. They don't work properly with our
pages.
Fortunately, this means no problem to us. We have made our own version of supplying you with the
logged-in user name and the time which has elapsed since the user logged-in.
How to design your site:
========================
(1) The "Login" page should be the first page the user meets with when he enters your site. At
the Login page, the user can either login, go to the registration page to create a new
account if he does not have one or to go to the password recovery page if his password has
been forgotten.
After logging-in and being validated, the user should be taken to the main membership page.
This has been all done in example 1 by the setup of the Login control:
cs="lo0";cis="";j=k=0;jd=5;ds="c";fns="trb10";cls="b0s9";
ib=true; // Turn "Remember Me" feature on.
js="NewAccount.aspx"; // Registration page
ks="RecoverPass.aspx"; // Password Recovery page
urs="Members.aspx"; // Members page.
wm("i");
(2) The main membership page and all other pages which are for members only, must contain
code like this:
if(cs.Equals("pl")) { // If event is "Page_Load"
setup(); // Execute setup()
MakePage(table); // and Make the page
PageNumber(5); // Setting page number.
wm("mls"); // Get member logging status
if (ids=="") { // If no name returned:
urs="Login.aspx";wm("rr"); // Redirect user to the login page
return; // Exit.
}
}
If the member user name is returned into (ids) you can display a personal welcome phrase
like "Welcome to our site John." assuming that (ids="John")
If the (ids) returned was empty, you know that the user has found his way to the members
page without being authenticated. You can then redirect him to the Login page or to any
other page as you choose before he can see the contents of your members page.
(3) Method wm("mls") returns additional information about the user to you which is the amount
of time the user has been logged into your site. For security, some sites like to make a
user log-in again if he has been on the site for more than a specific amount of time.
If the user was not logged-in, method wm("mls") would return (ids="") and (os="") If the
user was logged-in it would return (ids="UserName") and (os="hh:mm:ss"), (os) represents
the amount of time the user has been logged into your site.
Normally, you would neglect the login time as we did in the code above but if you like to
set a maximum stay time (with one logging in) to one hour, here is how to do it:
if(cs.Equals("pl")) { // If event is "Page_Load"
setup(); // Execute setup()
MakePage(table); // and Make the page
PageNumber(5); // Setting page number.
wm("mls"); // Get member logging status
if (ids=="") { // If not logged in:
urs="Login.aspx";wm("rr"); // Redirect to login page
return; // and exit.
}
os=os.Substring(0,2);om("ti"); // Get the hours, convert to int.
if (o>0) { // If logged in for over 1 hour or more:
wm("mlo"); // Mark user as logged off.
urs="Members.aspx";wm("rr"); // Refresh page
return; // and exit
}
}
When you mark user as logged off using wm("mlo"), all you have done is that whenever your
page is refreshed or whenever any other page calls wm("mls") thereafter regarding the same
user's entry, they will get (ids="")
(4) You can easily make a logoff button which when clicked, you handle the event and mark the
user as logged off and (if necessary) redirect him to another page.
(5) You can also make a page for both anonymous and logged-in users. It could contain a "login"
button before the user logs in which turns into a logoff button after he logs in. The page
can contain many features which switch from one kind to another depending on the login state.
We will see that in a future example.
About the next example:
-----------------------
We are going to assume that the members are signing to get into a gaming site and the gaming
site main page is (pg10 of WPDI) So, you need to copy the following classes from "WPDI"
documentation:
"cards", "game1", "game2". Do not copy "pg10" class. Replace it with the class "Members" which
is listed below. Save the files into "cards.cs", "game1.cs", "game2.cs" and "Members.cs".
Compile file "cards.cs" using tool "pcwm" and compile the other 3 files with tool "pcw"
as follows:
pcwm cards [ENTER] pcw game1 [ENTER] pcw game2 [ENTER] pcw Members [ENTER]
==============================================================================================
Example 5: Modify the gaming page (pg10 of WPDI) to be the members page for this product.
Anyone who tries to accesses it without being logged in should be sent back to the "Log-in"
page. Make it log members off if they stay logged in for over one hour. Include a personalized
salutation phrase for the members. Include also a "Home", "Change Password" and a "Logoff"
buttons.
==============================================================================================
public partial class Members:master1 { // **** Class name changed to Members
//************************ No changes from here down to the astrisk line **********************
public override void init() {
base.init(); // Initialize pasp
}
public override void setup() {
base.setup(); // Execute setup() of master1 class
//----------------------------------- tb2 Contents ----------------------------------
cns="tb2"; // tb2 is made of 3 cols, 3 rows
cs="bt0";j=0;k=0;lf=0;cis="New Game";cls="r0g7";fns="trb12";ds="w";wm("i");
cs="lb1";cis="Head or Tail?";j=0;k=1;lf=0;ds="w";cls="r0p7";fns="trb12";wm("i");
cs="rb00";cis="Face Up";j=0;k=2;ds="w";cls="b0p7";fns="trb12";wm("i");
cs="rb01";cis="Face Down";j=0;k=3;ds="w";cls="b0p7";fns="trb12";wm("i");
cs="bt1";j=0;k=4;lf=0;cis="Submit Bet";cls="r0g7";fns="trb12";ds="w";wm("i");
// 2 Radio Buttons and their label
// "Click to start drawing" button
cs="im1";cis="";j=1;k=0;o=5;ds="c";lf=150;of=200; // Image control where the drawing
ims="game1.aspx";wm("i"); // will be, ims=the ".aspx file"
//----------------------------------- tb3 Contents ----------------------------------
cns="tb3"; // tb3 is made of 2 cols, 2 rows
cs="bt2";j=0;k=0;lf=0;cis="New Game";cls="r0g7";fns="trb12";ds="c";wm("i");
cs="lb2";cis="Where Is The Ace?";j=1;k=0;lf=0;ds="c";cls="r0p7";fns="trb12";wm("i");
cs="bt3";j=2;k=0;lf=0;cis="Submit Bet";cls="r0g7";fns="trb12";ds="c";wm("i");
cs="rb10";cis="";j=0;k=1;ds="c";cls="r0p7";fns="trb12";wm("i");
cs="rb11";cis="";j=1;k=1;ds="c";cls="r0p7";fns="trb12";wm("i");
cs="rb12";cis="";j=2;k=1;ds="c";cls="r0p7";fns="trb12";wm("i");
// 3 Radio Buttons and their label
// "Click to start drawing" button
cs="im2";cis="";j=0;k=2;i=3;ds="c";lf=360;of=150; // Image control where the drawing
ims="game2.aspx";wm("i"); // will be, ims=the ".aspx file"
//*******************************************************************************************
//----------------------------------- tb4 Contents ----------------------------------
cns="tb4"; // tb4 is made of 1 col, 1 row
cs="lb4";cis="";j=0;k=0;ds="w";fns="esb22";cls="o0p7";wm("i");
// Create a label. Text will be added later
//----------------------------------- tb5 Contents ----------------------------------
cns="tb5"; // tb5 is made of 3 cols, 1 row
cs="bt50";j=0;k=0;lf=0;cis="Home";cls="s9g0";fns="trb12";ds="c";wm("i");
cs="bt51";j=1;k=0;lf=0;cis="Change Password";cls="s9b0";fns="trb12";ds="c";wm("i");
cs="bt52";j=2;k=0;lf=0;cis="Logoff";cls="s9r0";fns="trb12";ds="c";wm("i");
} // Create buttons for all other functions
//-----------------------------------------------------------------------------------
public override void update() {
//------------------------------------ Page Load ------------------------------------
if(cs.Equals("pl")) { // If event is "Page_Load"
setup(); // Execute setup()
if(!IsPostBack) { // If first trip to retrieve page
ks="bet1_s";os="2";wm("vs"); // vars. Bit
ks="last1_s";os="-1";wm("vs"); // vars. Bit
ks="bet2_s";os="3";wm("vs"); // effects are default values.
ks="last2_s";os="-1";wm("vs"); // effects are default values.
} // string also as a session variable
MakePage(table); // Make the page to be sent
PageNumber(5); // Set page number.
wm("mls"); // Get member logging status
if (ids=="") { // If not logged in:
urs="Login.aspx";wm("rr"); // Redirect to login page
return; // and exit.
}
os=os.Substring(0,2);om("ti"); // Get the hours, convert to int.
if (o>0) { // If logged in for over 1 hour:
wm("mlo"); // Mark user as logged off.
urs="Members.aspx";wm("rr"); // Refresh page
return; // and exit
}
cis="Welcome to our gaming site "+ids+".";cs="lb4";wm("sl");
} // Else, display welcome message.
//--------------------------------------- Home ---------------------------------------
if(cs.Equals("bt50")) { // If button (bt50) clicked:
urs="Login.aspx";wm("rr"); // Redirect to Login page.
}
//--------------------------------- Change Password ----------------------------------
if(cs.Equals("bt51")) { // If button (bt51) clicked:
urs="ChangePass.aspx";wm("rr"); // Redirect to ChangePass page.
}
//-------------------------------------- Logoff ---------------------------------------
if(cs.Equals("bt52")) { // If button (bt52) clicked:
wm("mlo"); // Mark user as logged off.
urs="Members.aspx";wm("rr"); // Refresh page.
}
//************************ No more changes to the end of the class **************************
//------------------------------------ bt0 Click -------------------------------------
if(cs.Equals("bt0")) { // If button (bt0) clicked:
// var's used: bet1_s (user bet) can be ("0" or "1"),
// bet1_s="2" means "new game", bwt1_s=-1 means do nothing
ks="bet1_s";os="2";wm("vs");
ks="bet2_s";os="-1";wm("vs");
}
//------------------------------------ bt1 Click -------------------------------------
if(cs.Equals("bt1")) { // If button (bt1) clicked:
// var's used: bet1_s (user bet) can be ("0" or "1"), bet1_s="2" means "new game"
cs="rb0*";wm("gu"); // Get update for Radio Button grp
o=cui;om("fi");
ks="bet1_s";wm("vs");
ks="bet2_s";os="-1";wm("vs");
}
//------------------------------------ bt2 Click -------------------------------------
if(cs.Equals("bt2")) { // If button (bt0) clicked:
// var's used: bet2_s (user bet) can be ("0","1" or "2"), bet2_s="3" means "new game"
ks="bet2_s";os="3";wm("vs");
ks="bet1_s";os="-1";wm("vs");
}
//------------------------------------ bt3 Click -------------------------------------
if(cs.Equals("bt3")) { // If button (bt1) clicked:
// var's used: bet2_s (user bet) can be ("0","1" or "2"),
// bet2_s="3" means "new game", bet2_s=-1 means do nothing
cs="rb1*";wm("gu"); // Get update for Radio Button grp
o=cui;om("fi");
ks="bet2_s";wm("vs");
ks="bet1_s";os="-1";wm("vs");
//*******************************************************************************************
}
}
}
==============================================================================================

===============================================================================================
3D ASSEMBLIES
=============
(for version 4.1 and later)
It's time to put the 3D assemblies which we have discussed in the chapter of "Drawing II" into
web pages. Those 3D assemblies can be created using all versions of the .NET starting with
version 2.
We are going to start with the first example in which we have drawn a glass with orange juice
and a doughnut on a plate by its side. Since all drawings in that example have been simple, we
did not use high density drawing. We divided each unit cylinder into 40 sectors only. Also, we
wrote the data into file directly without using A3D's.
Here, on the web we don't like to use files. So we'll write data into an A3D, however We cannot
accept A3D's default density which sets number of sectors at 360. So, we're going to reduce
density by making the assignment (dna=0.112;) into method init(). At this density, the number of
sectors should be:
360*0.112=40.32
Since the number of sectors must be an integer, the number of sectors is going to be 40.
Method gm("3cc") has been used in that example 3 times to create the cup, the orange juice and
the plate. This method expects (fls) to be assigned the name of the file into which the 3D
assembly data will be written. If you like the data to be written into an A3D instead of a file,
assign to (fls) the character '@' followed with the number of the A3D which you like data to be
written into.
Also, method gm("3rd") has been used 4 times to draw all created items. This method also expects
the name of the data file which contains the assembly to be assigned to (fls). To instruct the
method to draw from an A3D, make the same assignment to (fls) as you do with method gm ("3cc")
As we always do when we send graphics to the web, we like to demonstrate how to let the user
interact with the server in order to get the drawing he wants. In this example we'll let the
user choose the kind of doughnut he wants and the kind of drink.
The rest of the example will be similar to all the drawing examples which we have seen before
starting with example 6 of WPDI. We're going to use the one file method which has been
demonstrated in that past example.
==============================================================================================
Example 6: Draw a plate with a doughnut and a glass with a drink by its side. Make the user
select from 3 kinds of doughnuts and 3 kinds of drinks.
==============================================================================================
public partial class pg6:master1 {
string block=""; // Declaring a local variable
public override void init() {
dna=0.112; // Density to be used by all A3D's
base.init();
}
public override void setup() {
IsSingleTable=true;PageLength=300;base.setup(); // Request one page setup from master page
//----------------------------------- tb2 Contents ----------------------------------
cns="tb2"; // tb2 is made of 2 cols, 3 rows
cs="ch0";j=0;k=0;ds="s";cls="S9g7";fns="trb12"; // Doughnut selection drop list
CIS=new string[]{"Select a Doughnut","Plain","Sugar Glazed","Chocolate Coated"};wm("i");
cs="ch1";j=0;k=1;ds="c";cls="S9g7";fns="trb12"; // Drink selection drop list
CIS=new string[]{"Select a Drink","Orange Juice","Chocolate Drink","Milk"};wm("i");
cs="bt0";j=0;k=2;ds="n";cis="Redraw";cls="r0g7";fns="trb12";wm("i");
// Redraw button
cs="im1";cis="";j=1;k=0;o=3;ds="c";lf=560;of=300; // Image control where the drawing
ims="pg6.aspx?block=1";wm("i"); // will be, ims=the ".aspx file"
}
public override void update() {
//------------------------------------ Page Load ------------------------------------
if(cs.Equals("pl")) { // If event is "Page_Load"
ks="block";wm("rq");block=OS[0]; // Get value of "block" in query string
if (block.Equals("1")) {draw();return;} // If block=1 call method & exit
setup(); // Else Execute setup()
if(!IsPostBack) { // If first trip to retrieve page
ks="Selections_s";os="o0O5y0o0";wm("vs"); // Save initial Doughnut-Drink colors
} // as one session variable
MakePage(table); // and Make the page
PageNumber(6); // Calling master class's method
} // to display this page's number
//------------------------------------ bt0 Click -------------------------------------
if(cs.Equals("bt0")) { // If button (bt0) clicked:
cs="ch0";wm("gu"); // Get ch0's update (cui=index)
os="o0O5 o0O5 o2O4 R4R6 ".Substring(5*cui,4); // Form color code and assign it to (os)
cs="ch1";wm("gu"); // Get ch1's update (cui=index)
os+="y0o0 y0o0 r5R5 s9s5 ".Substring(5*cui,4); // Form color code and add it to (os)
ks="Selections_s";wm("vs"); // Save selected color as a session
} // variable.
}
// ================================== draw method ====================================
void draw() {
//---- Reading session variable and extracting color codes ----
ks="Selections_s";wm("vg"); // Get color codes stored as session var
if(os.Length!=8) os="o0O5y0o0"; // If not valid use default
string cl1s=os.Substring(0,4); // Extract doughnut color code from string
string cl2s=os.Substring(4); // Extract drink color code from string
lf=500;of=300;wm("bo"); // Open new bitmap operation size=500X300
cls="p7";gm("ec"); // Paint background with page's color
//------------------------------- Creating Assembly Files --------------------------------
// The cup is a sloped hollow cylinder. First hollow u cyl=2, Side thickness=2.
fls="@1";lf=40;of=100;o=100;jd=0.82d;ib=true;i=2;id=2;gm("3cc");
// The orange juice inside the cup is a solid sloped cylinder.
fls="@2";lf=40;of=100;o=100;jd=0.85d;gm("3cc");
// The plate is a sloped hollow cylinder. First hollow u cyl=8, Side thickness=8.
fls="@3";lf=40;of=150;o=20;jd=0.5d;ib=true;i=8;id=8;gm("3cc");
//----- Creating the Doughnut assembly -----
// Doughnut constants:
int o1=40; // Number of unit cylinders
float o1f=100,l1f=40; // Diameter of encl circle at center, no of sides
o=4;j=o1;gm("3CA"); // Create the new A3D #4 with no. of ucyl's=40
//---- Outer Surface ----
for (int u=0;u<=o1;u++) { // Scanning (o+1) u cyl's and writing their data:
od=20*20-(u-o1/2)*(u-o1/2);um("ms"); // 2nd component of (x) (discussed before)
od=0.5*(double)o1f+od; // Adding 1st component to (x)
for (int s=0;s< l1f;s++) A3D[4][u][0][s]=od;
} // Data at all columns = (od)
//---- Inner Surface ----
for (int u=0;u<=o1;u++) { // Scanning (O+1) u cyl's and writing their data:
od=20*20-(u-o1/2)*(u-o1/2);um("ms"); // 2nd component of (x) (discussed before)
od=(double)(o1f/2)-od; // Adding 1st component to (x) (notice the (-) sign)
for (int s=0;s< l1f;s++) A3D[4][u][1][s]=od;
} // Data at all columns = (od)
//----------------------------------- Drawing 3D objects ---------------------------------
cls=cl2s; // Drink color
fls="@2";jf=182;kd=1.8;kf=-6;jd=1;gm("3rd"); // Drawing Drink
fls="@1";jf=182;kd=2.0;jd=1;cls="s81S01";gm("3rd"); // Drawing cup
fls="@3";jf=-63;kf=-25;kd=2.5;jd=1.4;cls="y3Y3";gm("3rd");// Draing Plate
cls=cl1s; // Doughnut color
fls="@4";jf=-63;kf=-5;kd=1.6;jd=1.2;jb=true;gm("3rd"); // Drawing doughnut
wm("bc"); // Close bitmap operation.
}
}
===============================================================================================