Personal C Sharp                                                         By  famsoft.org
HomeHow To StartExamples-DesktopExamples-WebPC# MethodsReference-DesktopReference-Web


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. } } ===============================================================================================


=============================================================================================== Vertical and Horizontal cross section equations: ================================================ In the chapter of "Drawing II", we have shown you how to replace an assembly or part of it with a figure which is identified with its horizontal and vertical cross section equations. Method gm("3RQ") is used for this purpose. (os) is one of the parameters which this method expects. You assign to (os) two characters, the first one is a code for the vertical cross section equation and the second character is a code for the horizontal cross section equation. Here is a list of each code and the shape equation which it represents: Vertical Cross Section: ----------------------- CODE SHAPE NAME EQUATION REQUIRED PARAMETERS ==== ========== ======== =================== r Rectangle x = hw hw = Half width of rectangle t Trapezoid x = hw + y*hw*(1-jd)/hh hw,hh=1/2 width, height. jd=bottom/center ratio c Circle x^2 + y^2 = hw^2 hw = Radius of circle = Eq Sided Obj n/a hh=Radius of enclosing circle, jd=Number of sides e Ellipse (x/hw)^2 + (y/hh)^2 = 1 hw,hh = 1/2(width,height), kd=unclipped height. h Hyperbola (x/jd)^2 - (y/kd)^2 = 1 jd,kd = Constants. p Parabola y = jd * x^2 jd = Constant s SuperEllipse (x/hw)^4 + (y/hh)^4 = 1 hw,hh = Half width, Half Height. H Heart Symbol (x^2+y^2-1)^3-x^2*y^3=0 jd=Scale factor, Default=40. m GetX() Your own equation(s) You decide. Use (jd,kd) or use local var's d Delete data x=0 None. It deletes existing data. $ Sketch n/a ims=Image file name which contains vert CS sketch. . None n/a None. Means do not modify vertical cross section. Horizontal Cross Sections: -------------------------- CODE SHAPE NAME EQUATION REQUIRED PARAMETERS ==== ========== ======== =================== r Rectangle n/a rr = Half Width, id = Depth c Circle r=rr rr = Circle's Radius = Eq Sided Obj n/a rr=Radius of enclosing circle, id=Number of sides e Ellipse (x/rr)^2+(z/id*rr)^2 = 1 rr=X-radius, id=Ratio of (Z-radius)/(X-radius) R Rose Curve r = rr * sin(id*angle) rr=Petal length, id = Number of petals. g Gear Curve r = rr * (1+0.1*tanh(t)) rr=Gear radius, id = Number of teeth. where t=10*sin(id*angle) m GetRadius() Your own equation(s) You decide. Use (id,od) or use local var's. d Delete data r=0 None. It deletes existing data. $ Sketch n/a ims=Image file name which contains horiz CS sketch . None n/a None. Means do not modify horizontal cross section The next example will allow us to practice with these codes. We'll be able to select any 2 codes for the vertical and the horizontal cross sections of a figure which will replace the entire startup assembly. We are going to be using the default density (360 sectors per unit cylinder) and rainbow coloring in order to see figure details clearly. ============================================================================================== Example 7: Write a web page in which the user can select a shape for the vertical cross section and another for the horizonal cross section to see a 3D drawing of the figure wich is represented by the two. ============================================================================================== public partial class pg7:master1 { string block=""; // Declaring a local variable public override void init() { base.init(); // No density specified since default } // will be used. public override void setup() { base.setup(); // Run setup() of master page first //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 2 cols, 3 rows cs="lb0";cis="Select the vertical and horizontal cross sections of the 3D shape you want."; j=0;k=0;i=2;ds="c";cls="r0p7";fns="trb12";wm("i"); cs="ch0";j=0;k=1;ds="c";cis="Vertical";cls="S9g7";fns="trb12"; // Vertical CS selection CIS=new string[]{"Vertical CS","Triangle","Rectangle","Hexagon","Circle","Ellipse" ,"Trapezoid","Hart Symbol","Hyperbola","Parabola"};wm("i"); cs="ch1";j=1;k=1;ds="c";cis="Horizontal";cls="S9g7";fns="trb12"; // Horizontal CS selection CIS=new string[]{"Horizontal CS","Triangle","Rectangle","Hexagon","Circle","Ellipse" ,"Rose Curve","Gear Curve"};wm("i"); cs="bt0";j=0;k=2;i=2;ds="c";cis="Draw";cls="r0g7";fns="trb12";wm("i"); // Draw button //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 1 col, 1 row cs="im1";cis="";j=0;k=0;ds="c";lf=of=250; // Image control where the drawing ims="pg7.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="rc";wm("vs"); // Save initial (default) selection } // as a session variable MakePage(table); // and Make the page PageNumber(7); // 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) vs="rTrXcetHhp".Substring(cui,1); // Get selected vert CS code. cs="ch1";wm("gu"); // Get ch1's update (cui=index) hs="cTrXceRg".Substring(cui,1); // Get selected horiz CS code. os=vs+hs; // Combine the two codes and save ks="Selections_s";wm("vs"); // as a session variable } } // ================================== draw method ==================================== void draw() { //---- Reading session variable and extracting color codes ---- ks="Selections_s";wm("vg"); // Get combined codes string back if(os.Length<2) os="rc"; // If not valid use default vs=os.Substring(0,1); // Extract vert CS code from string hs=os.Substring(1); // Extract horiz CS code from string //---- Starting up operation ---- lf=of=250;wm("bo"); // Open new bitmap operation size=250X250 cls="p7";gm("ec"); // Paint background with page's color fls="@1";o=100;gm("3cc"); // Create startup assy, load into A3D #1 //---- Additional par's required for some vert CS codes ---- if (vs=="T") {vs="=";jd=3;} // A triangle is eq sided obj with sides=3 else if (vs=="X") {vs="=";jd=6;} // A hexagon is eq sided obj with sides=6 else if (vs=="t") jd=0.8; // Trapezoid requires bottom/center ratio else if (vs=="h") {jd=25;kd=40;} // Hyprbola constants. else if (vs=="H") jd=40; // Heart symbol requires scale. else if (vs=="p") jd=0.02; // Parabola's equations requires a constant //---- Additional par's required for some horiz CS codes ---- if (hs=="T") {hs="=";id=3;} // A triangle is eq sided obj with sides=3 else if (hs=="r") id=50; // id=Depth of the rectangle else if (hs=="X") {hs="=";id=6;} // A hexagon is eq sided obj with sides=6 else if (hs=="e") id=0.66; // Ellipse requires (Z-Radius)/(X-Radius) else if (hs=="R") id=6; // Rose curve requires number of petals else if (hs=="g") id=12; // Gear curve requires number of teeth o=1;ks="0,50,80,100";ad=360;os=vs+hs;gm("3RQ"); // Call method to modify A3D //----------------------------------- Drawing 3D objects --------------------------------- fls="@1";jd=kd=1.5;cls="r";gm("3rd"); // Draw modified A3D wm("bc"); // Close bitmap operation. } } ==============================================================================================