by Charles Carroll
Transcription
by Charles Carroll
http://www.learnASP.com/learn/index.asp by Charles M. Carroll Page 1 /learn Table of Contents Quick Lessons - Table of Contents (/learn/index.asp) - Page 1 Credits & Instructions (/learn/credits.asp) - Page 2 Core Ideas (/learn/core.asp) - Page 3 What is ASP? (/learn/whatis.asp) - Page 4 Simple ASP Page, Server Scripting (/learn/whatisexample.asp) - Page 5 MS Online Documentation (/learn/docs.asp) - Page 6 Response: Basics (/learn/res.asp) - Page 7 Response: Buffers, Redirect (/learn/res2.asp) - Page 8 Response: Redirection (/learn/res3.asp) - Page 9 Response: Quotes & Special Characters (/learn/res4.asp) - Page 10 Response: Encoding URLs, HTML (/learn/res5.asp) - Page 11 Include: Basics (/learn/inc.asp) - Page 12 Include: Dynamic FileName (/learn/includedynamic.asp) - Page 13 Include: Sample Exercise (/learn/booksample.asp) - Page 14 Format: Numbers #1 (/learn/formatnumbers.asp) - Page 15 Format: Numbers #2 (/learn/formatnumbers2.asp) - Page 16 Format: Dates #1 (/learn/formatdates.asp) - Page 17 Date/Time on ASP Pages by Tony Arguelles (/learn/datetime.asp) - Page 18 Loops: DO WHILE/UNTIL #1 (/learn/DoLoop.asp) - Page 19 Loops: Timeouts #2 (/learn/DoLoop2.asp) - Page 20 Loops: Intercepting Timeouts #3 (/learn/DoLoop3.asp) - Page 21 Server Variables: Popular Ones (/learn/server.asp) - Page 22 Server Variables: Domain/Host Name (/learn/server2.asp) - Page 23 Server Variables: Displaying All (/learn/serverall.asp) - Page 24 Random Content/Rotating Info (/learn/randomadvice.asp) - Page 25 Browser Detection (/learn/browserdetect.asp) - Page 26 Browscap: Basics (/learn/bc.asp) - Page 27 Browscap: Intricate Details (/learn/bcdetails.asp) - Page 28 BrowserHawk: Determing Browser Type (/learn/bhbrowtype.asp) - Page 29 BrowserHawk: older AOL browsers (/learn/bhaol.asp) - Page 30 Browserhawk: MS-Wallet (/learn/bhwallet.asp) - Page 31 BrowserHawk - Reverse DNS lookups (/learn/bhresolveip.asp) - Page 32 BrowserHawk - Frame support (/learn/bhframes.asp) - Page 33 Troubleshooting, Error Trapping (/learn/troubles.asp) - Page 34 Errors: Basics (/learn/errors1.asp) - Page 35 Errors: Trapping EVERY Error (/learn/dbtablewitherrortrap.asp) - Page 36 Errors: DB Error Information Trapping (/learn/dbtroubleshoot.asp) - Page 37 DBFAQ: Operation must use Updatable Query (/learn/FAQdbUpdate.asp) - Page 38 DBFAQ: User Entered ' in field (/learn/FAQdbSinglequote.asp) - Page 39 DBFAQ: LIKE operator * not working (/learn/FAQdbLIKE.asp) - Page 40 DBFAQ: retrieving MEMO/BLOBs generates error (/learn/FAQdbMEMO.asp) - Page 41 DBFAQ: Syntax Error in SQL Statement (/learn/FAQdbSQLSyntax.asp) - Page 42 Errors: Trapping Open Connections (/learn/dbtroubleshootopen.asp) - Page 43 Troubleshoot: Getting Help from Lists! (/learn/asptroubles.asp) - Page 44 Troubleshoot: Worldwide (/learn/asptroubles2.asp) - Page 45 Troubleshoot: Specialized (/learn/asptroubles3.asp) - Page 46 Troubleshoot: Version of ASP Sofware (/learn/versioncheck.asp) - Page 47 Troubleshoot: Registered Components (/learn/componentchecker.asp) - Page 48 Troubleshoot: DB Drivers by Christophe Wille (/learn/connectioninfo.asp) - Page 49 PWS: Personal Web Server Introduction (/learn/PWS.asp) - Page 50 Forms/Decisions (/learn/Form.asp) - Page 51 Forms: Introduction (/learn/formintro.asp) - Page 52 Forms: Text Box (/learn/formtextbox.asp) - Page 53 Forms: Text Area (/learn/formtextarea.asp) - Page 54 Forms: Check Box (/learn/formcheckbox.asp) - Page 55 Forms: Radio Buttons (/learn/formradio.asp) - Page 56 Forms: List Box (/learn/formlistbox.asp) - Page 57 Forms: CASE syntax #1 (/learn/case.asp) - Page 58 Forms: CASE syntax #2 (/learn/case2.asp) - Page 59 Forms: IF syntax #1 (/learn/if.asp) - Page 60 Forms: IF syntax #2 (/learn/if2.asp) - Page 61 Forms: IF syntax #3 (/learn/if3.asp) - Page 62 Forms: IF syntax #4 (/learn/if4.asp) - Page 63 Forms: For Each Iteration (/learn/formforeach.asp) - Page 64 Forms: mailing w/ASPMail (/learn/formsendmail.asp) - Page 65 Cookies: Reading Them (/learn/cookiesform.asp) - Page 66 Cookies: Writing Them (/learn/cookiesformrespond.asp) - Page 67 Cookies: Deleting Them (/learn/cookiesforget.asp) - Page 68 Cookies: Simplified by Paul Rigor (/learn/cookiesub.asp) - Page 69 State Management (/learn/statemanagement.asp) - Page 70 State Management Introduction (/learn/stateintro.asp) - Page 71 What are ASP Sessions? (/learn/sessionswhat.asp) - Page 72 State Methods: Pros and Cons (/learn/stateproscons.asp) - Page 73 Pass Data w/Hidden Fields (/learn/hidden.asp) - Page 74 Pass Data w/Cookies (/learn/cookies.asp) - Page 75 Pass Data w/Session Vars (/learn/statesessions.asp) - Page 76 Pass Data w/ID tied to database (/learn/statedb.asp) - Page 77 State Managment Resources (/learn/statemore.asp) - Page 78 [aspStateManagement] Listserver (/learn/aspstatemanagement.asp) - Page 79 Databases (/learn/database.asp) - Page 80 DB: Troubleshooting Part 1 (/learn/dbtroubles.asp) - Page 81 DB: Troubleshooting Part 2 (/learn/dbtroubles2.asp) - Page 82 DB: Displaying Table w/Simple Code (/learn/dbsimple.asp) - Page 83 DB: Table Displayed Generically (/learn/dbtable.asp) - Page 84 DB: List Box Displayed Generically (/learn/dblist.asp) - Page 85 Database to ListBox Online Resources (/learn/dblistmore.asp) - Page 86 DB: Generic DB by Eli Robillard (/learn/genericdb.asp) - Page 87 DB: More ways To Display Tables (/learn/dbtablemore.asp) - Page 88 DB: DSNLess Connections (/learn/dbopen.asp) - Page 89 DB: DSN Setup #1 by Rob Martinson (/learn/dsn1.asp) - Page 90 DB: DSN Setup #2 by Rob Martinson (/learn/dsn2.asp) - Page 91 DB: DSN Setup #3 by Rob Martinson (/learn/dsn3.asp) - Page 92 DB: DSN Setup #4 by Rob Martinson (/learn/dsn4.asp) - Page 93 DB: DSN Setup #5 by Rob Martinson (/learn/dsn5.asp) - Page 94 DB: DSN Setup #6 by Rob Martinson (/learn/dsn6.asp) - Page 95 DB: Full Cycle #1 Show/Edit/Update (/learn/dbfull1.asp) - Page 96 DB: Full Cycle #2 Show/Edit/Update (/learn/dbfull2.asp) - Page 97 DB: Full Cycle #3 Show/Edit/Update (/learn/dbfull3.asp) - Page 98 DB: Converting a DB to a Comma-Delimited file (/learn/dbconvert.asp) - Page 99 DB: Deleting a Record w/SQL (/learn/dbSQLdelete.asp) - Page 100 DB: Access vs. SQL Server (/learn/accessSQLserver.asp) - Page 101 DB: Oracle and ASP (/learn/oracle.asp) - Page 102 ASPDB - A Component That Simplifies Databases (/learn/aspdb.asp) - Page 103 ASP DB Sample #1: Displaying Data (/learn/aspdb1.asp) - Page 104 ASP DB Sample #2: Editing, Adding Data (/learn/aspdb2.asp) - Page 105 Database: Useful ADO Features (/learn/ado.asp) - Page 106 Getstring to display database table (/learn/dbtablegetstring.asp) - Page 107 Getrows to display database table (/learn/dbtablegetrows.asp) - Page 108 Disconnected Recordsets, Display Table (/learn/dbtabledisconnected.asp) - Page 109 ADO: Limiting Number of Records (/learn/dbmaxrecs.asp) - Page 110 ADO: Paging Records (/learn/dbtablepaged.asp) - Page 111 ADO: Count Records in Query (/learn/dbcount.asp) - Page 112 ADO: Cursor Types by Phil Paxton (/learn/adocursortypes.asp) - Page 113 ADO: Input Form (/learn/dbnewrec.asp) - Page 114 ADO: Input Form, added w/SQL (/learn/dbnewSQL.asp) - Page 115 ADO: Input Form, Added w/ADO .addnew (/learn/dbnewADO.asp) - Page 116 ADO: GetString function (/learn/dbgetstring.asp) - Page 117 ADO: Tables within Databases (/learn/dbtablelists.asp) - Page 118 ADO: Schemas to access table lists (/learn/dbschemas.asp) - Page 119 ADO: Schemas to access All Data (/learn/dbschemasall.asp) - Page 120 ADO: SQL Mistakes (/learn/dbtroubleshoot2.asp) - Page 121 ADO: Show Table,1 param (/learn/db1parm.asp) - Page 122 ADO: Update/edit Record (/learn/dbupdate.asp) - Page 123 SQL Basics, Searching Databases (/learn/SQL.asp) - Page 124 SQL Troubles (/learn/SQLtroubles.asp) - Page 125 SQL: Example Tables (/learn/SQLexamples.asp) - Page 126 SQL: Where Clause Basics (/learn/SQLwhere.asp) - Page 127 SQL: Where Clause Examples (/learn/SQLwhere2.asp) - Page 128 SQL: Search Forms #1 (/learn/SQLwhereform1.asp) - Page 129 SQL: Search Forms #2 (/learn/SQLwhereform2.asp) - Page 130 SQL: Search Forms #3 (/learn/SQLwhereform3.asp) - Page 131 SQL: Search AND/OR Operators (/learn/SQLandor.asp) - Page 132 SQL: Search AND/OR Examples (/learn/SQLandor2.asp) - Page 133 SQL: COUNT, GROUPBY (/learn/SQLcount.asp) - Page 134 SQL: SUM, MIN, AVE, MAX (/learn/SQLaggregate.asp) - Page 135 SQL Joins by Aaron Alexander (/learn/dbjoin.asp) - Page 136 Authentication & Security (/learn/authenticate.asp) - Page 137 Authenticate: Overview by Kevin Flick (/learn/authenticateoverview.asp) - Page 138 Authenticate: Comparison by Kevin Flick (/learn/authenticatecomparisons.asp) - Page 139 Authenticate: NT Challenge/Response by Kevin Flick (/learn/authenticatentcr.asp) - Page 140 Authenticate: Basic Authentication by Kevin Flick (/learn/authenticatebasic.asp) - Page 141 Authenticate: Cookies by Kevin Flick (/learn/authenticatecookies.asp) - Page 142 Authenticate: Certificates by Kevin Flick (/learn/authenticatecertificate.asp) - Page 143 Authenticate: Build Your Own by Kevin Flick (/learn/authenticatebuild.asp) - Page 144 Authenticate: Protect Pages via Login #1 (/learn/security.asp) - Page 145 Authenticate: Protect Pages via Login #2 (/learn/security2.asp) - Page 146 Authenticate: 3rd Party by Kevin Flick (/learn/authenticate3rdparty.asp) - Page 147 Mastering ASP: Quality, Re-Use, More... (/learn/qualitycode.asp) - Page 148 Strings: Core Functions (/learn/strings.asp) - Page 149 Strings: SPLIT Function (/learn/stringsplit.asp) - Page 150 Strings: REPLACE Function (/learn/stringreplace.asp) - Page 151 Strings: JOIN Function (/learn/stringjoin.asp) - Page 152 Arrays: Basics (/learn/arrays.asp) - Page 153 Arrays: Variable Size (/learn/arrays2.asp) - Page 154 Arrays: Best Way To Load (/learn/arrays3.asp) - Page 155 Dictionary Objects (/learn/dictionary.asp) - Page 156 Subroutine: Working with Dates #1 (/learn/subdates.asp) - Page 157 Subroutine: Working with Dates #2 (/learn/subdates2.asp) - Page 158 Subroutine: Query2Table (/learn/subdbtable.asp) - Page 159 Subroutine: Query2List (/learn/subdblist.asp) - Page 160 Subroutine: Highly Reusable (/learn/subreusable.asp) - Page 161 Subroutine: List Box w/optional params (/learn/subDBlistbest.asp) - Page 162 Subroutine: Abstract HTML by Phil Paxton (/learn/libhtml.asp) - Page 163 Function: Working Days (/learn/functionworkingdays.asp) - Page 164 New Features in VBScript version5 (/learn/vbs5.asp) - Page 165 Editors designed for ASP (/learn/editors.asp) - Page 166 Visual Interdev + Admunsen Resources (/learn/admunsen.asp) - Page 167 ASPExpress: HOT ASP Editor (/learn/aspexpress.asp) - Page 168 Homesite: HTML editor (/learn/homesite.asp) - Page 169 Code Speed, Scalability... (/learn/speedscale.asp) - Page 170 Application Data (/learn/sessionsapps.asp) - Page 171 Application Data: Worlds Fastest ListBox (/learn/speedappdata.asp) - Page 172 Sessions: What are they? (/learn/sessionswhat.asp) - Page 173 Sessions: Global.asa Events (/learn/global.asp) - Page 174 Session Overview & Myths (/learn/sessionoverview.asp) - Page 175 Sessions: Global.asa and Scalability (/learn/globalproblems.asp) - Page 176 Global.asa Resources (/learn/globalmore.asp) - Page 177 Speed: Server Optimization (/learn/speedserver.asp) - Page 178 Speed: Research Online (/learn/speedresearch.asp) - Page 179 Time Tasks with Millisecond Accuracy (/learn/speedtimer.asp) - Page 180 Speed: Coding Tips (/learn/speedtips.asp) - Page 181 Speed: Database Percieved Speed (/learn/speedtables.asp) - Page 182 Speed: Database Retrieval Speed (/learn/speedtablesall.asp) - Page 183 Speed: OLEDB & ODBC Drivers differences (/learn/speedtablesdrivers.asp) - Page 184 Scale: IsClientConnected & Stray Tasks (/learn/isclientconnected.asp) - Page 185 Scale: Virtues of Nothing (/learn/nothing.asp) - Page 186 Scale: Connection Pooling (/learn/dbpooling.asp) - Page 187 Thread Safety Issues (/learn/threadsafe.asp) - Page 188 Round-Robin Code Execution (/learn/roundrobin.asp) - Page 189 Why Buffer? (/learn/whybuffer.asp) - Page 190 Why GetRows or Getstring to get Data (/learn/whygetrows.asp) - Page 191 ASP Scalability Listserver (/learn/aspscalability.asp) - Page 192 Related Web/Com Technologies (/learn/webcom.asp) - Page 193 Index Server via ADO (/learn/indexserver.asp) - Page 194 Commerce and ASP (/learn/commerce.asp) - Page 195 Server JavaScript: Resources (/learn/javascript.asp) - Page 196 Validation Resources (/learn/validationmore.asp) - Page 197 Listboxes: Linked Dynamically w/JavaScript (/learn/listdynamic.asp) - Page 198 Dynamic ListBox Online Examples (/learn/listdynamicmore.asp) - Page 199 Listboxes: Linked Dynamically from Database w/JavaScript (/learn/listdynamicdb.asp) - Page 200 Listboxes: Easy Choices by Bill Wilkinson (/learn/listdual.asp) - Page 201 Server Perlscript: Resources (/learn/perlscript.asp) - Page 202 Remote Scripting Simple Example (/learn/remotescripting.asp) - Page 203 Remote Scripting Microsoft Example (/learn/remotescriptingms.asp) - Page 204 RDS: Remote Data Services Intro (/learn/rds.asp) - Page 205 RDS Resources by Carl Prothman (/learn/prothman.asp) - Page 206 ADSI: Active Directory Services Interface Intro (/learn/ADSI.asp) - Page 207 MSMQ: Overview (/learn/MSMQ.asp) - Page 208 Usability: Resources (/learn/usability.asp) - Page 209 Usability: Safe Color Pallete (/learn/safecolors.asp) - Page 210 ASP Books & Online Resources (/learn/research.asp) - Page 211 Must Buy Component Building Book (/learn/bookcomponents.asp) - Page 212 ASP101.com Scripts for your site (/learn/asp101.asp) - Page 213 4GuysFromRolla.com Tons of ASP Material (/learn/4guysfromrolla.asp) - Page 214 ASPToday.com from WROX (/learn/asptoday.asp) - Page 215 Advice For Better Coding! (/learn/advice.asp) - Page 216 advice: Cache No More by Phil Paxton (/learn/cachenomore.asp) - Page 217 advice:Option Explicit (/learn/explicit.asp) - Page 218 advice: Encode with Redirects (/learn/encode.asp) - Page 219 advice: Write Your SQL (/learn/sqlwrite.asp) - Page 220 advice: Named constants for ADO are better (/learn/namedconstants.asp) - Page 221 advice: Clean Up Your Room, I mean Objects (/learn/cleanup.asp) - Page 222 advice: Server.MapPath is Good (/learn/pathmap.asp) - Page 223 advice: Just Say No to Session COM objects (/learn/nosessionobjects.asp) - Page 224 advice: Don't Read COM Properties Twice (/learn/propertyexpense.asp) - Page 225 advice: Secure Code and Data (/learn/securecode.asp) - Page 226 advice: Encaspulate Code! (/learn/encapsulate.asp) - Page 227 advice: CASE reads better than IF (/learn/caseisbetter.asp) - Page 228 advice: Error Trapping Strategies (/learn/errorstrategies.asp) - Page 229 advice: Error Trapping Secrets (/learn/errorsecrets.asp) - Page 230 advice: You Should... (/learn/shoulds.asp) - Page 231 Advanced Topics (/learn/more.asp) - Page 232 Text Files: Reading Them off Server (/learn/txtread.asp) - Page 233 Text Files: Writing Them on Server (/learn/txtwrite.asp) - Page 234 Text Files: Meyers-Briggs parsing #1 (/learn/mb1.asp) - Page 235 Text Files: Meyers-Briggs parsing #2 (/learn/mb2.asp) - Page 236 Text Files: Meyers-Briggs parsing #3 (/learn/mb3.asp) - Page 237 Content Linker: Prev/Next Page (/learn/cl.asp) - Page 238 Content Linker: Table of Contents (/learn/cl2.asp) - Page 239 Content Linker: Listbox of contents (/learn/cl3.asp) - Page 240 File Objects: Read Directory (/learn/fileobjects.asp) - Page 241 File Objects: Display Directory as Links/Graphics (/learn/fileobjects2.asp) - Page 242 File Objects: Read Disk Drive by Steven Harper (/learn/fileobjects3.asp) - Page 243 File Objects: Show Dir List by Tim Foster (/learn/fileobjects4.asp) - Page 244 Graphic Size Detector (/learn/graphicdetect.asp) - Page 245 VB ASP Components Building (/learn/buildcomponents.asp) - Page 246 VB Components: Simple Component (/learn/buildvbsimple.asp) - Page 247 VB Components: Registering Component (/learn/buildregister.asp) - Page 248 VB Components: ADO, Run It! (/learn/buildvbado.asp) - Page 249 VB Components: ADO, Build It! (/learn/buildvbado2.asp) - Page 250 VB Components: VB Warnings/Guidelines (/learn/buildvbguidelines.asp) - Page 251 VB Components: General Building Guidelines (/learn/buildvb.asp) - Page 252 VB Components: Installation Requirements (/learn/buildvb2.asp) - Page 253 VB Components: Threading Models (/learn/buildvbthreads.asp) - Page 254 Java ASP Components Building (/learn/buildjava.asp) - Page 255 C++/ATL ASP Component Building (/learn/buildc.asp) - Page 256 Microsoft Transaction Server (MTS) (/learn/buildmtx.asp) - Page 257 MTS: Overview (/learn/buildmtxoverview.asp) - Page 258 MTS: Essentials (/learn/buildmtx2.asp) - Page 259 MTS: Transactional ASP pages (/learn/buildmtxasp.asp) - Page 260 MTS: Book (/learn/booksmtx.asp) - Page 261 MTS: Book (/learn/booksmtx2.asp) - Page 262 MTS: Registering Components (/learn/buildmtxregister.asp) - Page 263 3rd Party Components (/learn/components.asp) - Page 264 ASPMail: Simple Example (/learn/serverobjectsmail.asp) - Page 265 Upload: Simple Example (/learn/uploadsimple.asp) - Page 266 Upload: Multi-part form (/learn/uploadmultipart.asp) - Page 267 Upload: Limit Size (/learn/uploadlimitsize.asp) - Page 268 Upload: Many Files (/learn/uploadmanyfiles.asp) - Page 269 Perf Counters on ASP page (/learn/perfcounters.asp) - Page 270 New Lessons (/learn/new.asp) - Page 271 Recently Modified Lessons (/learn/changed.asp) - Page 272 Beginners Lessons (/learn/newbie.asp) - Page 273 Frequently Asked Questions (/learn/faqs.asp) - Page 274 Commerce: certificates, https:// (/learn/FAQCommerceCertif.asp) - Page 275 Commerce: online charging (/learn/FAQCommerceCharge.asp) - Page 276 Commerce: components, shopping carts (/learn/FAQCommerceCarts.asp) - Page 277 Jscript: closing DB Connections (/learn/FAQJscriptCleanUp.asp) - Page 278 Jscript: online references (/learn/FAQJscriptRefs.asp) - Page 279 Jscript: display databases (/learn/FAQJscriptDB.asp) - Page 280 Oracle: I can't connect (/learn/FAQOracleconnect.asp) - Page 281 Oracle: Know any good books? (/learn/FAQOraclebooks.asp) - Page 282 Oracle: Calling Stored Procs (/learn/FAQOraclestoredproc.asp) - Page 283 VB: DLL overwrite problems (/learn/FAQvbDLLoverwrite.asp) - Page 284 VB: Recommended books (/learn/FAQvbBooks.asp) - Page 285 Overview: What the Heck is ASP? (/learn/overview.asp) - Page 286 ASP Objects: Built In (/learn/aspobjects.asp) - Page 287 ASP Objects: Created when Needed (/learn/aspobjects2.asp) - Page 288 Alphabetical Index (/learn/alphaindex.asp) - Page 289 Coming Soon/Very Rough Drafts! (/learn/comingsoon.asp) - Page 290 Data Types: VBScript (/learn/types.asp) - Page 291 Data Types: Conversion (/learn/convert.asp) - Page 292 Loops: FOR NEXT #1 (/learn/ForNext.asp) - Page 293 Loops: FOR NEXT #2 (/learn/ForNext2.asp) - Page 294 Ad Rotator (/learn/ad.asp) - Page 295 Content Rotator (/learn/cr.asp) - Page 296 DB: Command Object (/learn/command.asp) - Page 297 DB: Command Object/Queries (/learn/commandquery.asp) - Page 298 DB: Command Object/Create Tables (/learn/commandcreate.asp) - Page 299 Reporting: Simple Example (/learn/reportsimple.asp) - Page 300 Reporting: Powerful Example (/learn/reportpowerful.asp) - Page 301 Dictionaries: Different Approach #1 By Paul Rigor (/learn/dictionaryadvanced.asp) - Page 302 Dictionaries: Different Approach #2 by Paul Rigor (/learn/dictionaryadvanced2.asp) - Page 303 Validate data (/learn/validate.asp) - Page 304 3rd Party: WebJam (/learn/webjam.asp) - Page 305 Time Tasks: VB Component by Sunny Yu #1 (/learn/asptime.asp) - Page 306 Time Tasks: VB Component by Sunny Yu #2 (/learn/asptimer.asp) - Page 307 http://www.learnASP.com/learn/credits.asp by Charles M. Carroll Page 2 ASP Quick Lessons is a on-line book published @ http://www.learnasp.com All material not specifically noted otherwise is ©1998,1999 by Charles Carroll. All rights reserved. May be used and printed for any single individual with no restriction. Cannot be reprinted, resold, or commercially made available without the written consent of Charles Carroll. Primary Writer: Charles M. Carroll Inspiration, Assistance, Production: Naoko Yoshitsugu, Hitoshi Carroll Additional Writers: Aaron Alexander, Kevin Flick, Steve Genusa, Steven Harper, John Kauffman. Andrew Laken, Juan Llibre, Rob Martinson, Phil Paxton, Paul Rigor, Christophe Wille, David Wihl and Sunny Yu. Instructions, Hints, Tips ● A complete printout suitable for printing off-line is available @ http://www.learnasp.com/learn/printout.asp ● All the ASP programs used in this tutorial can be obtained @ http://www.learnasp.com/learn/download.asp http://www.learnASP.com/learn/core.asp by Charles M. Carroll Page 3 What is ASP? (whatis.asp) - Page 4 Simple ASP Page, Server Scripting (whatisexample.asp) - Page 5 MS Online Documentation (docs.asp) - Page 6 Response: Basics (res.asp) - Page 7 Response: Buffers, Redirect (res2.asp) - Page 8 Response: Redirection (res3.asp) - Page 9 Response: Quotes & Special Characters (res4.asp) - Page 10 Response: Encoding URLs, HTML (res5.asp) - Page 11 Include: Basics (inc.asp) - Page 12 Include: Dynamic FileName (includedynamic.asp) - Page 13 Include: Sample Exercise (booksample.asp) - Page 14 Format: Numbers #1 (formatnumbers.asp) - Page 15 Format: Numbers #2 (formatnumbers2.asp) - Page 16 Format: Dates #1 (formatdates.asp) - Page 17 Date/Time on ASP Pages by Tony Arguelles (datetime.asp) - Page 18 Loops: DO WHILE/UNTIL #1 (DoLoop.asp) - Page 19 Loops: Timeouts #2 (DoLoop2.asp) - Page 20 Loops: Intercepting Timeouts #3 (DoLoop3.asp) - Page 21 Server Variables: Popular Ones (server.asp) - Page 22 Server Variables: Domain/Host Name (server2.asp) - Page 23 Server Variables: Displaying All (serverall.asp) - Page 24 Random Content/Rotating Info (randomadvice.asp) - Page 25 http://www.learnASP.com/learn/whatis.asp by Charles M. Carroll Page 4 (surprisingly even though ASP was shipped in Feb 1996, most explanations are still HUGE in books and use quite scary technical terms) We will try to present this all in clear, concise terms and be complete as well. Hang on. Here we go. ASP is: 1. an abbreviation for Active Server Pages 2. FREE and already built into Win2000. 3. FREE for NT4 if one installs the NT4 Option Pack. Can be downloaded from http://www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/default.asp 4. ASP can be installed on Win 95/98 computers to test ASP scripts; thus we can conclude the NT Option Pack4 has a very misleading name since it installs on Win 9x as well. 5. The code inside ASP is mixed in with standard HTML and is NEVER seen by the browser. ASP pages run in ALL browsers UNLESS the person making the page uses HTML or browser commands outside of the ASP portions. More ASP facts: 1. See www.learnasp.com/hosts for links to FREE hosts if you want to develop a site on the WWW web without spending money; Commercial hosts are also listed to serve busy corporate sites you build. 2. It is part of IIS (Internet Information Server) which takes care of all the non-asp chores (FTP, serving plain HTML, serving video). IIS is also FREE with NT4 or Win2000. 3. It can be purchased for Unix, Notes/Domino, Novell servers and other platforms. Two vendors currently offer this: Chilisoft and Halcyonsoft (see www.learnasp.com/hosts for links to them) Are you one of those unlucky folks who gets cryptic errors or has trouble Installing Asp? Just join http://www.asplists.com/asplists/aspinstall.asp and submit your problem by email. Others will help you! http://www.learnASP.com/learn/whatisexample.asp by Charles M. Carroll Page 5 Now let us go over the essential mechanisms that are ASP: 1. A user asks for a page say: http://www.coyoteindustries.com/hi.asp 2. The Web Server find the file and then processes all the ASP code between <% ... %> before handing back the page. Code between <% ... %> never arrives at the browser. <html><head> <TITLE>hi.asp</TITLE> </head> <body bgcolor="#FFFFFF"> Today is <%=now%> and all is well<br> <%if hour(now())>13 THEN%> Good Morning <%ELSE%> Good Day! <%END IF%> </body></html> The webserver file <<<<<<< ASP compiler grabs page Interprets all the <% %> markers before browser sees page! <html><head> <TITLE>hi.asp</TITLE> </head> <body bgcolor="#FFFFFF"> Today is Tue 10:30am and all is well<br> Good Morning </body></html> <html><head> <TITLE>hi.asp</TITLE> </head> <body bgcolor="#FFFFFF"> Today is Tue 02:00pm and all is well<br> Good Day! </body></html> Before 12pm the user at the browser receives <<<<<<< After 12pm the user at the browser receives <<<<<<< http://www.learnASP.com/learn/docs.asp by Charles M. Carroll Page 6 Microsoft Documentation There is quite a bit of online documentation that comes with Microsoft Active Server Pages. Our tutorial was written with the express purpose of being a friendlier, easier to understand set of lessons than the free documentation Microsoft gives you below: IIS4 Docs /iishelp /iishelp/iis/htm/asp/intr1orp.htm /IISSamples/ExAir/default.asp /iishelp/iis/htm/asp/comp275c.htm /iishelp/JScript/htm/JStoc.htm /iishelp/VBScript/htm/VBStoc.htm /iishelp/iis/htm/asp/iissiref.htm /iishelp/iis/htm/asp/iiwaref.htm click here NT4 Option Pak ASP objects reference Ex Air Installable Components for ASP JScript Language Reference VBScript Language Reference Server Side Include Reference ASP Quick reference card ASP Tutorial* IIS3 Docs /iasdocs/aspdocs/roadmap.asp /aspsamp/samples/samples.htm /AdvWorks/default.asp Roadmap / Official IIS3 Docs IIS3 Code Samples AdventureWorks * ASP Tutorial resides at this ridiculously long URL: /iishelp/iis/htm/asp/iiselect.asp?LessonFile=%2Fiishelp%2Fiis%2Fhtm%2Fasp%2Fiiatmd1% http://www.learnASP.com/learn/res.asp by Charles M. Carroll Page 7 Response Object The response object is useful, feature rich, and subtle. We are going to focus on it's most fundamental capabilities -- the 20% you will use 80% of the time. The capabilities we think are vital include: ● response.write ● response.write alternate syntax <%= %> which allows ASP simply placed in HTML ● response.end which effectively halts a script in it's tracks. ● response.redirect which transfers control to another page Here is a script utilizing response.write to send some information to the browser. It also uses dateadd, a built-in function documented at http://help.activeserverpages.com/iishelp/VBScript/htm/vbs90.htm. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <html><head> <title>response.asp</title>& <body color="#FFFFFF"> <% when=now() tommorow=dateadd("d",1,when) twoweekslater=dateadd("ww",2,when) fourteenweekdayslater=dateadd("w",14,when) monthlater=dateadd("m",1,when) sixminuteslater=dateadd("n",6,when) sixhourslater=dateadd("h",6,when) fortysecslater=dateadd("s",40,when) response.write response.write response.write response.write response.write "Now <b>" & when & "</b><br>" "tommorow <b>" & tommorow & "</b><br>" "2 weeks from Now <b>" & twoweekslater & "</b><br>" "fourteen working days from Now <b>" & fourteenweekdayslater & "</b><br>" "1 month from Now <b>" & monthlater & "</b><br>" 20 21 22 23 24 %> six minutes from now <b> <%=sixminuteslater%> </b><br> six hours from now <b> <%=sixhourslater%> </b><br> fourty seconds later <b> <%=fortysecslater%> </b><br> </body></html> Here is a script utilizing response.end to prematurely end a page: 1 <html><head> 2 <title>end.asp</title>& 3 <body color="#FFFFFF"> 4 <% 5 when=now() 6 tommorow=dateadd("d",1,when) 7 twoweekslater=dateadd("w",2,when) 8 monthlater=dateadd("m",1,when) 9 sixminuteslater=dateadd("n",6,when) 10 sixhourslater=dateadd("h",6,when) 11 12 response.write "Now <b>" & when & "</b><br>" 13 response.write "1 month from Now <b>" & monthlater & "</b><br>" 14 response.end 15 response.write "2 weeks from Now <b>" & twoweekslater & "</b><br>" 16 %> 17 six minutes from now <b> <%=sixminuteslater%> </b><br> 18 six hours from now <b> <%=sixhourslater%> </b><br> 19 </body></html> . http://www.learnASP.com/learn/res2.asp by Charles M. Carroll Page 8 Response Object Part2 - Buffer Explanation Response object error 'ASP 0156 : 80004005' Header Error whatever.asp, line # The HTTP headers are already written to the client browser. Any HTTP header modifications must be made before writing page content. Does this error message plague you? <%response.buffer=true%> needs to be added as the very first line to any pages made by any HTML document that mixes redirects and content. That line will do away with all browser complaints that "headers are already sent". Normally a page has a header --or-- text not both. If the browser writes any text, you can never response.redirect because once the browser writes text it can't change "horses in midstream" -- it either writes content OR redirects. <%response.buffer=true%> which essentially tells the browser don't write anything at all until a) response.end executes thus stopping the page dead in tracks and sending to browser b) response.flush executes c) 100% of the page is executed and it finishes all the ASP and HTML. d) response.redirect is sent, that and no content or text has been sent with response.flush. The only drawback to: <%response.buffer=true%> is if a page takes a while to compose (i.e. a couple thousand records from a database) people see nothing until the page is completely rendered. In that situation to avoid appearing as the page is dead, an occassional response.flush lets readers see portions of the page being built. We explain why BUFFER=true and flushing is the ideal way to achieve overall speed @ /advice/whybuffer.asp Here is a non-working page that will display the error: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <%response.buffer=false%> <html><head> <title>dailystuff.asp</title> </head> <body> <% whatweekday=Weekday(now()) select case whatweekday case vbSunday response.redirect "http://www.cnn.com" case vbMonday response.redirect "http://www.activeserverpages.com" case vbTuesday response.redirect "http://www.aspalliance.com" case vbWednesday response.redirect "http://www.aspconvention.com" case vbThursday response.redirect "http://www.aspmagazine.com" case vbFriday response.redirect "http://www.dilbert.com" case vbSaturday response.redirect "http://www.movielink.com" end select %> </body> </html> Here is the fixed page that will NOT display the error: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <%response.buffer=true%> <html><head> <title>dailystuff.asp</title> </head> <body> <% whatweekday=Weekday(now()) select case whatweekday case vbSunday response.redirect "http://www.cnn.com" case vbMonday response.redirect "http://www.activeserverpages.com" case vbTuesday response.redirect "http://www.aspalliance.com" case vbWednesday response.redirect "http://www.aspconvention.com" case vbThursday response.redirect "http://www.aspmagazine.com" case vbFriday response.redirect "http://www.dilbert.com" case vbSaturday response.redirect "http://www.movielink.com" end select %> </body> </html> . http://www.learnASP.com/learn/res3.asp by Charles M. Carroll Page 9 Response Object Part3 - Page Redirection Code The response object can be used to decide what page to send a user to next. Specifically the response.redirect method will work in that capacity. We have made a script formjump.asp that takes advantage of this. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html><head> <TITLE>FormJump.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="FormJumpRespond.asp" method="get"> <SELECT NAME="wheretogo"> <OPTION SELECTED VALUE="fun">Fun</OPTION> <OPTION value="news">Daily News</OPTION> <OPTION value="docs">ASP IIS3 Roadmap/Docs</OPTION> <OPTION value="main">MainPage of ActiveServerPages.com</OPTION> <OPTION value="sample">IIS 3 Sample ASP scripts</OPTION> </SELECT> <input type=submit value="Choose Destination"> </form> </body></html> The responder that reacts to this form is: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <%response.buffer=true%> <html><head> <title>formjumprespond.asp</title>& <body bgcolor="#FFFFFF"> <% ' My ASP program that redirects to URL thisURL="http://www.activeserverpages.com" where=Request.QueryString("Wheretogo") Select Case where case "main" response.redirect thisURL & "/" case "samples" response.redirect thisURL & "/aspsamp/samples/samples.htm" case "docs" response.redirect thisURL & "/iasdocs/aspdocs/roadmap.asp" case "news" response.redirect "http://www.cnn.com" case "fun" response.redirect "http://www.dilbert.com" End Select response.write "All dressed up and I don't know where to go<br>" response.write "I recommend --> " & "<br>" response.write server.htmlencode(thisURL & "/learn/test/res2.asp?where=fun") & "<br>" response.write "for a good laugh!" & "<P>" %> </body></html> http://www.learnASP.com/learn/res4.asp by Charles M. Carroll Page 10 Response Object #4 by Charles Carroll The response object is often used with a variety of syntax variations which we will detail here. 1 2 3 4 5 6 <html><head> <title>res4.asp</title> </head><body bgcolor="#FFFFFF"> <% ' The response object can be used to write text a variety of ways ' depending on what style you personally prefer 7 8 ' Various permutations of writing to the browser 9 response.write "<form>" 10 response.write "Hello, Joe<br>" 11 12 who="Joe" 13 response.write "Hello, " & who & "<br>" 14 %> 15 16 Hello, <%=who%><br> 17 18 Which Book? <input type="TEXT" name="book" value="The Stand"><br> 19 20 <% 21 response.write "Which Book? <input type=""TEXT"" name=""book"" value=""The Stand""><br>" 22 %> 23 24 <% 25 response.write "Which Book? <input type='TEXT' name='book' value='The Stand'><br>" 26 %> 27 28 <% 29 quote=chr(34) 30 response.write "Which Book? <input type=" & quote & "TEXT" & quote & " name=" & quote & "book" & quote & " value=" & quote & "The Stand" & quote & "><br>" 31 %> 32 33 34 <%bookname="The Stand"%> 35 Which Book? <input type="TEXT" name="book" value="<%=bookname%>"><br> 36 37 <% 38 response.write "Which Book? <input type=""TEXT"" name=""book"" value=""" & bookname & """><br>" 39 %> 40 </form> 41 </body></html> http://www.learnASP.com/learn/res5.asp by Charles M. Carroll Page 11 Response Object #5 by Charles Carroll The response object is often used in conjunction with various kinds of codi9ng schemes. No discussion of response would be complete without a discussion of how to "handle" or "escape" special characters. This sample script demonstrates common conversion and transformation commands that make sense to use with the response.write command: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html><head> <title>res5.asp</title> </head><body bgcolor="#FFFFFF"> <% ' The response object can be used to write text ' but sometimes some functions must be used to transform ' the text instead of sending as is to the browser response.write response.write response.write response.write "<B>Hyperion</b> by <I>Dan Simmons</i> is a great novel" "<p>" server.htmlencode("<B>Hyperion</b> by <I>Dan Simmons</i> is a great novel") "<p>" response.write "Joe Smith & Hilda = a team" response.write "<p>" 17 18 19 20 response.write server.URLencode("Joe Smith & Hilda = a team") %> </body></html> http://www.learnASP.com/learn/inc.asp by Charles M. Carroll Page 12 Include Files The include option is the heart of making efficient ASP files and re-usable chunks. It basically has two forms and now we will present the forms and their differences: <!--#include virtual="/whatever.asp"--> would include any file on your site (in this example, whatever.asp is in the web server's root directory) but you must fully qualify the filename with a path. <!--#include file="whatever.asp"--> can include the whatever.asp file in the directory of the script that contains the statement. It ASSUMES the current directory! Example #1 <!--#include virtual="/sally/filename.asp"--> could include a file from sally's directory, even if the page with this statement is (for example) in the /fred/finance folder. Example #2: <!--#include file="/sally/filename.asp"--> will fail from fred's directory. Example #3: <!--#include file="../sally/filename.asp"--> will succed from fred's directory but if the script that contains it is moved to a different level in the tree structure it will fail to locate the file. INCLUDE VIRTUAL is better if a script may be moved and is immune to relative path issues. IMPORTANT: Include files are always processed and inserted before ASP scripts on the page are calculated. Thus a page with many IFs and SELECT CASEs that selectively include files in fact always include the file before the script begins executing. http://www.learnASP.com/learn/includedynamic.asp by Charles M. Carroll Page 13 Include Files Dynamically by Charles Carroll The include files are gathered and processed BEFORE any ASP code. Soif your code looks like this: <%SELECT CASE CASE 1 %> <!--#include virtual="whatever1.asp"--> CASE 2 %> <!--#include virtual="whatever2.asp"--> CASE 3 %> <!--#include virtual="whatever3.asp"--> <%END SELECT%> Three includes are performed before any ASP code is executed. YOU CANNOT DO: <% whichfile="1"%> <!--#include virtual="whatever<%=whichfil%>.asp"--> Though this is a reasonable idea. <!--#include virtual="whatever.asp"--> The alternative is: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <html><head> <TITLE>includedynamic.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% whichfile="bookscifi.asp" Call ReadDisplayFile(whichfile) response.write "<hr>" whichfile="bookhorror.asp" Call ReadDisplayFile(whichfile) response.write "<hr>" whichfile="/learn/test/bookmarketing.asp" Call ReadDisplayFile(whichfile) response.write "<hr>" %> </body></html> <% SUB ReadDisplayFile(FileToRead) whichfile=server.mappath(FileToRead) Set fs = CreateObject("Scripting.FileSystemObject") Set thisfile = fs.OpenTextFile(whichfile, 1, False) tempSTR=thisfile.readall response.write tempSTR thisfile.Close set thisfile=nothing set fs=nothing END SUB %> The only downside to this method is no ASP Code ( i.e. anything in <% %> ) will be parsed or executed in the included file. http://www.learnASP.com/learn/booksample.asp by Charles M. Carroll Page 14 Book Sample by Charles Carroll The Recommend Book Sample Files provides you with several files that when created, prepare you for applying several unrelated but powerful content management tools in the following pages. The features detailed will include: ● Include files that implement pages headers, footers ● sessions and application variables to track users accessing these pages ● the content linker component all come together in this example. Here is the code for bookheader.asp: 1 Recommended Books for <%=session("fname")%> <%=session("lname")%><br><hr> Here is the code for bookfooter.asp: 1 <hr><br> 2 Recommended Books has <%=application("howmany")%> people reading it now! Here is the code for bookfuture.asp: 1 2 3 4 5 6 7 8 9 10 11 <html><head> <title>bookfuture.asp</title>& <!--#include file="bookheader.asp"--> <body> <h1>Future Books</h1> <ul> <li><b><i>Visions</b></i><br>Michio Kaku</li> <li><b><i>Future Magic</b></i><br>Robert Forward</li> </ul> <!--#include file="bookfooter.asp"--> </body></html> Here is the code for bookhorror.asp: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html><head> <title>bookhorror.asp</title>& <!--#include file="bookheader.asp"--> <body> <h1>Horror Books</h1> <ul> <li><b><i>Carrion Comfort</b></i><br>Dan Simmons</li> <li><b><i>The Stand</b></i><br>Steven King</li> <li><b><i>Children of Darkness</b></i><br>Dan Simmons</li> <li><b><i>Thinner</b></i><br>Steven King</li> <li><b>Fires of Eden<i></b></i><br>Dan Simmons</li> </ul> <!--#include file="bookfooter.asp"--> </body></html> Here is the code for bookmarketing.asp: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html><head> <title>bookMarketing.asp</title>& <!--#include file="bookheader.asp"--> <body> <h1>Marketing Books</h1> <ul> <li><b><i>22 Immutable Laws of Branding</b></i><br>Reiss and Reiss</li> <li><b><i>22 Immutable Laws of Marketing</b></i><br>Reiss and Trout</li> <li><b><i>Marketing Warfare</b></i><br>Reiss and Trout</li> <li><b><i>Horse Sense</b></i><br>Reiss and Trout</li> <li><b><i>Words That Sell</b></i><br>by ??</li> </ul> <!--#include file="bookfooter.asp"--> </body></html> Here is the code for booknovels.asp: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html><head> <title>booknovels.asp</title>& <!--#include file="bookheader.asp"--> <body> <h1>Recommended Novels</h1> <ul> <li><b><i>A Prayer for Owen Meaney</b></i><br>John Irving</li> <li><b><i>Cider House Rules</b></i><br>John Irving</li> <li><b><i>Heart of the Country</b></i><br>Greg Mathhews</li> <li><b><i>All That Remains</b></i><br>Patricia Cornwell</li> <li><b><i>Presumed Innocent</b></i><br>Scott Turrow</li> <li><b><i>Time to Kill</b></i><br>John Grisham</li> <li><b><i>Disclosure</b></i><br>Michael Chrichton</li> <li><b><i>Mount Dragon</b></i><br>Lincoln and Childs</li> </ul> <!--#include file="bookfooter.asp"--> 17 </body></html> Here is the code for bookscifi.asp: 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <title>bookscifi.asp</title>& <!--#include file="bookheader.asp"--> <body> <h1>Science Fiction Recommended Books</h1> <ul> <li><b><i>Ender's Game</b></i><br>Orson Scott Card</li> <li><b><i>Hyperion</b></i><br>Dan Simmons</li> <li><b><i>Childhood's End</b></i><br>Arthur Clarke</li> <li><b><i>TommyKnockers</b></i><br>Steven King</li> </ul> <!--#include file="bookfooter.asp"--> </body></html> Here is the code for bookselfhelp.asp: 1 2 3 4 5 6 7 8 9 10 11 12 <html><head> <title>bookselfhelp.asp</title>& <!--#include file="bookheader.asp"--> <body> <h1>Self Help Books</h1> <ul> <li><b><i>Road Less Travelled</b></i><br>Scott Peck</li> <li><b><i>The Seven Habits of Highly Effective People</b></i><br>Steven Covey</li> <li><b><i>First Things First</b></i><br>Steven Covey</li> </ul> <!--#include file="bookfooter.asp"--> </body></html> http://www.learnASP.com/learn/formatnumbers.asp by Charles M. Carroll Page 15 Format Numbers - Reference Frequently you want a number to appear in a certain format. The most commands requests are for a set total number of digits and a set number of digits to the right of the decimal place. Less frequently there is a call for negative amounts displayed in parenthesis or that there should be leading zeros. The FormatNumber function takes the contents of a number type variable and returns the contents in the specified format. Syntax: FormatNumber(expression, iDigits, bleadingDigit, bParen, bGroupDigits) argument expression iDigits meaning the variable holding the raw number number of digits to right of decimal point 1 for leading zeros bleadingDigit 0 for no leading zeros 1 for parenthesis around negative numbers bParen 0 for no parenthesis around negative numbers 1 to display numbers as per regional settings in the Control Panel bGroupDigits 0 to over-ride settings in the Control Panel http://www.learnASP.com/learn/formatnumbers2.asp by Charles M. Carroll Page 16 Format Numbers Part2 (by Charles Carroll) The easiest way to demonstrate format numbers is just have some sample code that tries evry permutation of the command. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <html><head> <TITLE>formatnumbers2.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% ' My ASP formatting number sample mynumber=123.4567 response.write "<hr>" & mynumber & "<br>" response.write "formatnumber(mynumber,0)" response.write formatnumber(mynumber,0) & response.write "formatnumber(mynumber,2)" response.write formatnumber(mynumber,2) & response.write "formatnumber(mynumber,6)" response.write formatnumber(mynumber,6) & & "<br>" "<hr>" & "<br>" "<hr>" & "<br>" "<hr>" mynumber=.4567 response.write mynumber & "<br>" '0 means means no leading zeroes response.write "formatnumber(mynumber,2,0)" & "<br>" response.write formatnumber(mynumber,2,0) & "<hr>" '1 means means pad with leading zeroes 'response.write "formatnumber(mynumber,2,1)" & "<br>" 'response.write formatnumber(mynumber,2,1) & "<hr>" 'mynumber=-123.4567 'response.write mynumber & "<br>" '0 means means no parentheses for negative numbers 'response.write "formatnumber(mynumber,2,0,0)" & "<br>" 'response.write formatnumber(mynumber,2,0,0) & "<hr>" '1 means means yes parentheses for negative numbers 'response.write "formatnumber(mynumber,2,0,1)" & "<br>" 'response.write formatnumber(mynumber,2,0,1) & "<hr>" %> </body></html> http://www.learnASP.com/learn/formatdates.asp by Charles M. Carroll Page 17 Format Dates (by Charles Carroll) The easiest way to demonstrate formatting dates is just have some sample code that tries evry permutation of the command. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <html><head> <title>formatdates.asp</title> </head><body bgcolor="#FFFFFF"><html> <%'My ASP program that formats dates response.write "<hr>" for counter=0 to 4 currentdate=now() response.write "today is..." & "<br>" response.write currentdate & "<P>" select case counter case 0 whichformat="vbgeneraldate" case 1 whichformat="vblongdate" case 2 whichformat="vbshortdate" case 3 18 19 20 21 22 23 24 25 whichformat="vblongtime" case 4 whichformat="vbshorttime" end select response.write "FormatDate(now()," & whichformat & ")=" response.write Formatdatetime(currentdate,counter) & "<P><HR>" next%> </body></html> http://www.learnASP.com/learn/datetime.asp by Charles M. Carroll Page 18 Adding the date and time to your ASP pages By Tony Arguelles tony@southbaywebdesigns.com Summary Including the date and/or time on a web page can be a subtle yet valuable addition when designing a web site. The addition of the date to the home page can create the impression that a site is constantly being updated with new content since each time a visitor loads the page, the current date will be displayed. In this tutorial I'll teach you how to add the date and time to your ASP pages using the VBScript FormatDateTime() function. I'll explain how the function works, teach you how to integrate it into your ASP pages and illustrate the output you'll get depending on the arguments you pass. I'll round out the tutorial of the FormatDateTime() function by covering a few limitations that it has, which might or might not be a big deal depending on your specific needs. Just FYI, this article assumes you know basic HTML and how to add ASP scripts to your web pages. The FormatDateTime() Function Microsoft provides a ton of predefined VBScript functions designed to reduce coding time. The FormatDateTime() function is one of those powerful functions and is really easy to use, too. This function uses the following format: FormatDateTime(date, format) There are two arguments the function accepts: date and format. Table 1-1 below describes these arguments in greater detail: Table 1-1: The FormatDateTime() function and its arguments Argument date Argument Description This argument is required and can be any valid date expression such as Date or Now format This format constant or format value specifies how the date and/or time will be displayed on your ASP page. When specifying the format argument, you can either type the Visual Basic constant name (name in left column), or the constant's corresponding value (0 - 4, from the middle column). They do the same thing, it's just less typing if you use the value. Constant Format Value Format Description vbGeneralDate 0 This is the default. Not specifying a value or specifying 0 will produce a date in the format of mm/dd/yy. If the date expression is Now, it will also return the time, after the date, in hh:mm:ss PM/AM format. vbLongDate 1 This is my personal favorite :-) Passing this value will produce a date in the format of weekday, month day, year* * The year is Y2K compliant :-). vbShortDate 2 vbLongTime 3 vbShortTime 4 Passing this value returns a date formatted just like the default of 0 (mm/dd/yy). Passing this value returns the time in hh:mm:ss PM/AM format. Passing this value returns military time in this format hh:mm Table 1-1 is a good reference once you've got a feel for how the FormatDateTime() function works or if you're an experienced programmer. For those of you that aren't clear on how all the information in table 1-1 relates to "real world" implementations, let's take a look at some examples: Returning the Current Date If you would like to display the current date, here are a few different ways to do it along with the results they produce: <%= FormatDateTime(Date) %> returns: 1/25/00 (You would get the same result by coding this: <%= FormatDateTime(Date, 0) %>) <%= FormatDateTime(Date, 1) %> returns: Tuesday, January 25, 2000 <%= FormatDateTime(Date, 2)%> returns: 1/25/00 Returning the Current Time If you would like to return the current time, here are a couple of ways to do that: <%= FormatDateTime(Now, 3)%> returns: 9:55:29 PM <%= FormatDateTime(Now, 4)%> returns: 21:55 Returning the Current Date and Time If you would like to return the current date and time together, here's how to do just that: <%= FormatDateTime(Now) %> returns: 1/25/00 9:55:29 PM If you're like me, you probably don't like the way the date and time displays above; it's not very cool looking, is it? In cases like this, you can actually include two FormatDateTime() functions next to each other, in order to get the date and time in a more desriptive format, like this: <%= FormatDateTime(Date, 1) %> <%= FormatDateTime(Now, 3)%> returns: Tuesday, January 25, 2000 9:55:29 PM Adding the code to your page Integrating the code into your ASP pages is really easy; here is how the code would look on a page with basic HTML to display the date: <html> <head> <title>Here's the date</title> </head> <body> Thank you for coming to this page. The current date is: <%= FormatDateTime(Date, 1) %> </body> </html> Limitations of the FormatDateTime() function The FormatDateTime() function is an extremely handy bit of code that can help you add a touch of flair almost instantly. I would like to mention four limitations that stick out in my mind, which may be an issue to you (or your clients) depending on the project at hand: Limitation 1: The unneeded zero On the first through ninth days of a month the day shows up in the format of "Month 01, Year". I know it seems like a small thing but trust me, it's can be a big deal to some. Limitation 2: Only basic formatting allowed You are limited to basic formatting of the string that's returned by the FormatDateTime() function. Since the date and/or time function returns is a single string, you can bold, italicize and change the whole date/time by adding HTML or style sheet tags around it, but you can't change the display properties for a single part (e.g., the month). With the FormatDateTime() function, you can do this: <b><%= FormatDateTime(Date, 1) %></b> which would return this: Tuesday, January 25, 2000 But you can't do this: Wednesday, January 1, 1999 If limitations 1 or 2 are a major hang up for you, you'll need to use different ASP/VBScript techniques to add the date to your page. I'll cover those in my next article! Limitation 3: The time isn't necessarily "their" time. Limitation 3 is more of a by-product than a limitation, but I figured I would keep the naming conventions the same for this section. If you use the the FormatDateTime() function (or any other date related function) on the server side, the date/time returned will be whatever the server's date and time is, not your client's time from their system. If you want to ensure that the date and/or time a visitor sees on your page is the date in their part of the coutry or world, then consider using client side VBScript as an Internet Explorer only solution, or switch to client side JavaScript for a universal browser solution. Limitation 4: It's static. Think of the displayed date or time as a "snap shot" of when the page was requested by the visitor. You cant use this function to display a "clock" that updates every second, or automatically update the date on the page when one day turns to the next. If you wanted to display a dynamic clock on your page, you would need to use client side JavaScript, or VBScript (IE only) to handle that task. I hope you've enjoyed this article on the FormatDateTime() function. I'll be back soon with more date and time related ASP fun! If you have any questions or comments, send me an Email at: tony@southbaywebdesigns.com http://www.learnASP.com/learn/DoLoop.asp by Charles M. Carroll Page 19 Do Loop Part #1 by Charles Carroll To execute a code sequence more than once ASP provides: ● DO, LOOP ● WHILE, WEND Either of these statements can be followed by UNTIL or WHILE. DO UNTIL .....code to be repeated... LOOP DO .....code to be repeated... LOOP UNTIL http://www.learnASP.com/learn/DoLoop2.asp by Charles M. Carroll Page 20 Do Loop and Timeouts by Charles Carroll A loop that is infinite will not run forever. IIS will timeout the script (default is 90 seconds). Here is an infinite loop that IIS will timeout: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <%response.buffer=true%> <TITLE>doloop1.asp</TITLE> <body bgcolor="#FFFFFF"> <HTML> <% DO counter=counter+1 response.write counter & "<br>" response.flush LOOP %> </BODY> </HTML> Here is an infinite loop that we explicitly set a timeout for: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <% response.buffer=true server.scripttimeout=20 %> <TITLE>loop2.asp</TITLE> <body bgcolor="#FFFFFF"> <HTML> <% DO counter=counter+1 response.write counter & "<br>" response.flush LOOP %> </BODY> 16 17 18 </HTML> It has been assumed that a timed out script was impossible to intercept, but the next lesson shows how to use the transactional aspect of an ASP script to capture this elusive condition. http://www.learnASP.com/learn/DoLoop3.asp by Charles M. Carroll Page 21 Do Loop Intercept Timeouts by Charles Carroll The transactional nature of ASP pages can be used to intercept a script timeout. loop3.asp traps a timeout: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <%@ TRANSACTION=Required%> <% response.buffer=true server.scripttimeout=20 %> <HTML> <TITLE>loop3.asp</TITLE> <body bgcolor="#FFFFFF"> </BODY> <% DO counter=counter+1 response.write counter & "<br>" LOOP response.flush response.write "Script executed without incident" %> </HTML> <% Sub OnTransactionAbort() response.clear Response.Write "The Script Timed Out" end sub %> loop4.asp succeeds and does not trigger the trap: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <%@ TRANSACTION=Required%> <% response.buffer=true server.scripttimeout=40 %> <HTML> <TITLE>loop4.asp</TITLE> <body bgcolor="#FFFFFF"> </BODY> <% DO UNTIL counter=400 counter=counter+1 response.write counter & "<br>" LOOP response.flush response.write "Script Exexuted without incident!" %> </HTML> <% Sub OnTransactionAbort() response.clear Response.Write "The Script Timed Out" 23 24 end sub %> http://www.learnASP.com/learn/server.asp by Charles M. Carroll Page 22 Server Variables by Charles Carroll Available Server Variables are the result of a combination of the browser software and the server software. They are not always exactly the same on your server and with specific browsers as we document here. Server Variables are retrieved with request.servervariables("variablename"), for example: sn=request.servervariables("script_name") ref=request.servervariables("http_referer") br=request.servervariables("http_user_agent") lan=request.servervariables("http_accept_language") user=request.servervariables("logon_user") name of script, i.e./learn/server.asp in this case name of site page (unless they just typed the URL) they clicked on to get here. Identification string emitted by browser. en for english. Basically indicates language the browser is targetted to. IE passes back NT logon in this variable! This script below demonstrates accessing a couple of these variables: 1 <html><head> 2 <title>server.asp</title>& 3 <body> 4 <% 5 sn=request.servervariables("script_name") 6 response.write "Script Name=" & sn & "<br>" 7 8 ref=request.servervariables("http_referer") 9 response.write "Page thats links to this=" & ref & "<br>" 10 11 ua=request.servervariables("http_user_agent") 12 response.write "Browser String=" & ua & "<br>" 13 14 lan=request.servervariables("http_accept_language") 15 response.write "Browser Language=" & lan & "<br>" 16 17 user=request.servervariables("logon_user") 18 response.write "NT Logon Name=" & user & "<br>" 19 %> 20 </body></html> http://www.learnASP.com/learn/server2.asp by Charles M. Carroll Page 23 Server Variables #2 by Charles Carroll Server Variables have many uses. We will show you a popular one here. Web sites are typically attached to an IP address, but sometimes several domain names may point to the same IP. A clever ASP script could display the same page different ways depending on which domain name was typed utilizing the HTTP_HOST. Our site, for example has three domain names tied to the same IP ( activeserverpages.com, asptraining.com, learnasp.com, help.activeserverpages.com ) and the following script will provide different results depending on what domain name it is called from: 1 <html><head> 2 <title>server2.asp</title>& 3 <body> 4 <% 5 host=lcase(request.servervariables("HTTP_HOST")) 6 SELECT CASE host 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 CASE "www.asptraining.com" response.write "Welcome Training Customer!" CASE "www.activeserverpages.com" response.write "Welcome To Our Reference Site!" CASE "www.learnasp.com" response.write "Welcome To Our Tutorial!" CASE "www.aspeuro.com" response.write "Welcome To Our European Site!" CASE "www.asplists.com","www.asplist.com" response.write "Welcome To Our ASP listservers!" CASE "www.aspconventions.com","www.aspconvention.com" response.write "Welcome To Our ASP convention site!" CASE ELSE response.write "Welcome!" END SELECT %> </body></html> http://www.learnASP.com/learn/serverall.asp by Charles M. Carroll Page 24 Listing All Server Variables by Charles Carroll The available Server Variables vary based on the result of a combination of the browser software and the server software. They are not always exactly the same on your server and with specific browsers as we document here. There is an easy way to obtain a list. If the script is executed on a given browser, the Server Variables displayed will reflect that browser plus your server. 1 2 3 4 5 6 <% for each thing in request.servervariables tempvalue=request.servervariables(thing) response.write thing & "=" & tempvalue & "<br>" next %> Since the above script appears in dozens of books and websites, we wanted to provide you with a better version. This script may prove useful as it will ● list all the available server variables 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ● skipping the variables ALL_HTTP and ALL-RAW since they are just a "glob" of all the other vars ● place blank variables at the end ● display code to retrieve that variable so you can cut and paste into script <html><head> <TITLE>serverall.asp</TITLE>& <body bgcolor="#FFFFFF"> <% Response.Write("<P><B>Server Variables</b><br>") BlankVars="<P><B>Blank Server Variables</b><br>" & vbcrlf quote=chr(34) For Each Key in Request.ServerVariables If instr(Key,"_ALL")+instr(key,"ALL_")=0 then tempvalue=trim(request.servervariables(Key)) If len(tempvalue)=0 then BlankVars=BlankVars & Key & ", " Else response.write "request.servervariables(" & quote response.write Key & quote & ") " response.write " =<br><B>" & tempvalue & "</b><p>" & vbcrlf End If end if Next response.write mid(BlankVars,1,len(BlankVars)-2) %> 22 </body></html> If the server has been secured with https:// then the following script will display some additional variables: https://secure.activeserverpages.com/learn/test/serverall.asp http://www.learnASP.com/learn/randomadvice.asp by Charles M. Carroll Page 25 Random Advice / Rotating Information by Charles Carroll This page demonstrates how to use several commands together to serve varying content based on a random number: ● RND function ● INT function ● SELECT CASE The script randomadvice.asp shows different advice every time the pge is refreshed: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <html><head> <TITLE>randomadvice.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% ' generate a random number 1-6 randomize randomnum=int(rnd*6)+1 SELECT CASE randomnum CASE 1,2,3%> Plant your crops early this year<br> No frost expected<br> <%CASE 4%> Never play cards<br>with a man named after a city<br> <%CASE 5%> You can never be too rich, too thin or backup too often<br> <%CASE 6%> A swallow keeps away the stork<br> <%END SELECT%> </body></html> http://www.learnASP.com/learn/browserdetect.asp by Charles M. Carroll Page 26 Browscap: Basics (bc.asp) - Page 27 Browscap: Intricate Details (bcdetails.asp) - Page 28 BrowserHawk: Determing Browser Type (bhbrowtype.asp) - Page 29 BrowserHawk: older AOL browsers (bhaol.asp) - Page 30 Browserhawk: MS-Wallet (bhwallet.asp) - Page 31 BrowserHawk - Reverse DNS lookups (bhresolveip.asp) - Page 32 BrowserHawk - Frame support (bhframes.asp) - Page 33 http://www.learnASP.com/learn/bc.asp by Charles M. Carroll Page 27 Browser Capabilites The script below demonstrates the most commonly used property of the Browser Capabilites component. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <html><head> <TITLE>bc.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% Set bc = Server.CreateObject("MSWC.BrowserType") %> Browser Name: <%=bc.browser %><p> Browser Version: <%=bc.version%><p> <% if (bc.frames = TRUE) then %> I noticed you do frames<p> <% else %> I noticed you are frame challenged<p> <% end if %> <% if (bc.tables = TRUE) then %> I noticed you do tables<p> <% else %> I noticed you can't do tables<p> <% end if %> <% if (bc.BackgroundSounds = TRUE)then %> I noticed you allow me to play music<p> <% else %> I noticed you aren't a music listener<p> <% end if %> <% I <% I <% if (bc.vbscript = TRUE) then %> noticed you are VBscript capable<p> else %> noticed you can't understand VB Script<p> end if %> <% if (bc.javascript = TRUE) then %> I noticed you understand JScript<p> <% else %> I noticed you don't understand JScript<p> <% end if set bc=nothing %> </body></html> http://www.learnASP.com/learn/bcdetails.asp by Charles M. Carroll Page 28 Browser Capability Details (by Charles Carroll) Any ASP script attempting to detect a browser needs to realize the following: ● Currently any new version of a browser is reported as unknown, unless you get an updated browscap.ini file. Even a minor release of a browser may be reported as unknown. The technology this DLL uses cannot "guess" that a new browser with slightly different characteristics is just like the previous one. ● There are two ways to get a known, reliable browscap.ini. which are explained below. Cyscape offer a downloadable latest, greatest BROWSCAP.INI and even offers e-mail subscriptions so you get the latest one sent to you. Visit http://www.cyscape.com/browscap to pick it up and/or subscribe. You can test in advance whether your browser is recognized by this file at http://www.cyscape.com/browtest.asp. The latest, greatest BROWSCAP.ZIP from Juan Llibre is available at http://www.asptracker.com. Juan Libre's Detect Your Screen Res articles is another sample making use of BROWSCAP.INI. These two sources give you the means to correctly identify the latest browser. The BrowserHawk Component at http://www.cyscape.com/browserhawk offers accuracy far better than what any browscap file can provide. It also provides information on more than twice as many properties, including FileUpload, MouseOver, SSL, DHTML, StyleSheets, Authenticode, OSDetails, Language, and many more! It will even download and install updated browser definition files for you automatically! Evaluation download available at: http://www.cyscape.com/browserhawk/download.asp http://www.learnASP.com/learn/bhbrowtype.asp by Charles M. Carroll Page 29 How to Determine the Browser Type and Version Often you will want to send content to the client only if you know their browser can support it. You may already have created pages that are designed to work only in IE and Netscape, version 4 or greater. Or for example you may have situations where a specific browser type and or version creates a page layout problem. In this lesson we present the technique used to detect specific browsers that you want to handle things differently for. For starters, assume you receive complaints that your favorite shade of blue used for some font text on your page is extremely difficult to read when viewed on WebTV (colors are typically an issue with WebTV due to contrast and other problems). What are you do to - remove the blue color all together? Change it for a boring share of grey? Of course not! The trick here is first finding a alternative color suitable for viewing on WebTV, and only using that color when the visitor is using a WebTV browser. Otherwise you use your blue font as originally planned. Here's how you would implement that: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <% set bh = server.createobject("cyScape.browserObj") if (bh.browser = "WebTV") then fontColor = "003366" 'a suitable alternate color for WebTV folks only else fontColor = "000066" 'your favorite shade of blue for all folks end if %> <html> <head> <title></title> </head> <body> <p>Welcome to my page. The <font color="<%=fontColor%>important" text</font>is highlighted for your convenience. </p> </font> </body> </html> This technique of testing for a specific browser type is also useful if you have specific tags and scripts that only work with certain browsers. For example, say you had certain pages that required Netscape or IE versions 4 or higher. Instead of going through and conditionally including all the v4-only tags, scripts and objects, this example will show how to use this technique to detect when a browser is not Netscape or IE v4 or higher, and redirect the user to an alternate page suitable for the other browsers. 1 2 3 4 5 6 7 8 9 10 <% set bh = server.createobject("cyScape.browserObj") if (bh.majorver >=4 ) and (bh.Browser ="IE" or bh.Browser ="Netscape") then else response.redirect("PageForNonIEorNNv4.asp") end if set bh = nothing %> <html><body> </body></html> Remember that the response.redirect code should go before any of the HTML content on the page. You can keep this check script in a separate file, and include it at the top of all pages within an application. Another example is the title attribute for HTML elements which, currently, is only supported by IE 4 or greater. While the title attribute degrades fine in other browsers, it is sometimes desirable to limit the amount of superfluous code being sent to the browser... regardless of how insignificant it may seem. This example will show you a quick and easy way to let BrowserHawk decide for you whether or not to use that title attribute. Here is an example of the title attribute. Since you are using IE4 or greater, if you hold your mouse over the following link for a few seconds, you will see a tooltip, similar to the kind you see when you hold your mouse over a button on an application's toolbar. This allows you to include a lot more information in a small space, such as a navigation frame or a slim table cell. Hover here Using two methods of BrowserHawk, we can quickly and easily check if the visitor is using a browser which supports the title element (namely, that it is Internet Explorer AND that it is version 4 or greater). Here is what the code looks like: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <% set bh = server.createobject("cyScape.browserObj") if bh.version>=4 and bh.browser="IE" then %> <a href='x.asp' title=' This is the alternate text. '> <% else %> </a> <a href='x.asp'> <% end if set bh = nothing %> <p> Hover here</a> This logic could be used for any feature that you know is only supported by certain browser versions. Sometimes it is worth it to prevent the waste of bandwidth caused by adding elements and features to a page when they can't be viewed anyway. But more likely then not, you'll use this approach to avoid inconsistencies with layout and scripting across browsers. Need a copy of BrowserHawk? See our section on Getting Started. Copyright (c) 1999 cyScape, Inc. All rights reserved. This material may not be published, distributed, or reprinted without written consent from cyScape. http://www.learnASP.com/learn/bhaol.asp by Charles M. Carroll Page 30 Detecting older AOL browsers Many people ask about how to detect older versions of AOL browsers, particularly AOL version 3.0 and earlier. This is because they find that certain form submissions may not work properly, or specific functionality, such as Macromedia Flash, will not work properly for their audience. Regardless of the reason, should you find it necessary to detect older versions of AOL browsers, you can easily use the following script to do so. Note also that you can easily modify this script to detect other browser types and versions as well. This example is based on the same concept presented in the previous lesson for detecting a browser type and version, but is targeted here specifically to AOL browsers. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <% set bh = Server.CreateObject("cyScape.browserObj") if bh.browser = "AOL" and bh.majorver <= 3 then response.redirect "noaol3.asp" end if %> <html> <head> <title>AOL check script</title> </head> <body> <p>You are not using AOL v3 or lower</p> </body> </html> Need a copy of BrowserHawk? See our section on Getting Started. Copyright (c) 1999 cyScape, Inc. All rights reserved. This material may not be published, distributed, or reprinted without written consent from cyScape. http://www.learnASP.com/learn/bhwallet.asp by Charles M. Carroll Page 31 Detecting if the MS Wallet is supported Many developers are chosing to use the Microsoft Wallet for securely taking customer credit card / payment information for their e-commerce site. The MS Wallet is implemented as a client-side ActiveX control. This means that in order for your customers to purchase using the MS Wallet, their browser needs to support ActiveX controls. Unfortunately not all browsers have this ability, including several popular browsers such those from Netscape and Opera (not even in the latest versions). Therefore if you are implementing the MS Wallet in your site, you'll want to make sure to provide an alternative form of secure payment for those visitors without support for this component. Microsoft provides useful scripts for implementing the Wallet in your ASP code. Unfortunately their scripts rely on the MS browser capability component, which frequently misidentifies browsers and ActiveX support in particular. Therefore relying on the MS component for this information will result in situations where you send the Wallet to those who can not handle it, and several cases where you do not send it to users when you should have.. To work around this problem, simply search through the MS scripts related to the Wallet and change all occurances of the class string "MSWC.BrowserType" in the CreateObject statements in the scripts to "cyScape.browserObj". This will ensure that you accurately identify which users can support the Wallet and provide alternatives for those who can not. For simple demonstration purposes, the following code snippet is provided. For real-world uses of this technique start with the scripts available for MS Wallet and change the class string as instructed above. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html> <head> <title>Purchase</title> </head> <body> <p>Payment info:<br> <% set bh = Server.CreateObject("cyScape.browserObj") if bh.ActiveXControls then response.write "... send MS Wallet control" else response.write "... send alternative code for collecting payment info" end if %></p> <p>%></p> </body> </html> Need a copy of BrowserHawk? See our section on Getting Started. Copyright (c) 1999 cyScape, Inc. All rights reserved. This material may not be published, distributed, or reprinted without written consent from cyScape. http://www.learnASP.com/learn/bhresolveip.asp by Charles M. Carroll Page 32 How to resolve IP address to host names Have you ever looked at an IP address and wondered where the user came from? Take 198.137.240.91 for example. Certainly "www.whitehouse.gov" has quite a lot more meaning. At one time or another you'll likely find yourself wanting to resolve IP addresses to host names. This is known in the biz as "reverse DNS lookups". So why would someone want to resolve an IP address? Well there are several possible uses for this information, but for this example we'll talk about using this information to help reduce fraud on your web site. For example, consider for a moment the issue of credit card fraud. Certainly providing fraudulent credit card information (or using someone elses card) over the Internet seems much easier than doing the same in person. This is because it seems easy to hide behind the anonymous nature of an HTTP connection. What the user may not realize, however, is that based on their IP address you can likely determine who their their employer or ISP is - and can use that information to track down someone providing fradulent credit card information or abusing your site in other ways. The host name, therefore, can serve as a decent deterrent by showing the host name to the visitor. This way they realize it is possibly that their identify could be determined based on this information. For example, showing someone with dishonest intentions that you know they are connected through "pop5.erols.net" may make them think twice before entering fraudulent credit card information. Afterall, it may not prove all that difficult for the authorities to obtain records from their ISP to determine their identity. As was mentioned earlier, there are several possible uses for this information. Whatever your reasons may be, BrowserHawk makes it easy to to obtain the host name for the current visitor or for any other IP address you'd like to look up. To determine the host name for the current site visitor, simply call the BrowserHawk ResolveIP method as demonstrated in the example below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html> <head> <title>Resolve IP</title> </head> <body> <p>Hello user connected from <% set bh = Server.CreateObject("cyScape.browserObj") hostname = bh.ResolveIP if hostname <> "" then response.write hostname else response.write "Unknown" end if %> </p> <p>%></p> </body> </html> Similarly, you can also obtain the host name for any given IP address as well. You simply call the ResolveIP method and pass in the IP address to be resolved as a parameter to the method. This is demonstrated in the example below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <html> <head> <title>Resolve IP</title> </head> <body> <% ipToLookup = "198.137.240.91" %> <p>The host name for <%=ipToLookup%> is <% set bh = Server.CreateObject("cyScape.browserObj") hostname = bh.ResolveIP(ipToLookup) if hostname <> "" then response.write hostname else response.write "Unknown" end if %> </p> <p>%></p> </body> </html> Copyright (c) 1999 cyScape, Inc. All rights reserved. This material may not be published, distributed, or reprinted without written consent from cyScape. http://www.learnASP.com/learn/bhframes.asp by Charles M. Carroll Page 33 Handling browsers that do not support frames Just about all "modern" browsers today support frames. Unfortunately though there are still several browsers in use today that do not. Just which ones do and which ones don't? Well, that's a tricky questions - but fortunately we don't need to concern ourselves with that. Instead, we simply ask BrowserHawk to determine this for us at run-time, based on the particular browser that a user visits with. If the browser supports frames, we load the frames set as expected and all is peachy. If the browser does not support frames, you have a couple of choices on how to handle this. The easiest thing to do of course is just display a page that tells the user that their browser does not support frames and ask them to upgrade their browser. Unfortunately this is the least elegant and can leave your visitor soured. As a result, many developers have two versions of their web site - one that is frames enabled and one that is not. In this case you use BrowserHawk to determine whether the visitor can support frames. If they can, you simply load the frameset and off they go. If they do not support frames, however, then we redirect them to the no frames version of the site. The following code demonstrates this approach. For simplicity sake we will display text that says to "load the frameset here" rather than actually load a frameset. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <% set bh = Server.CreateObject("cyScape.browserObj") if not bh.frames then 'note: this could also be written as "if bh.frames = false" response.redirect "noframes.asp" end if %> <html> <head> <title></title> </head> <body> <p>HTML code to load your frameset goes here </p> </body> </html> Need a copy of BrowserHawk? See our section on Getting Started. Copyright (c) 1999 cyScape, Inc. All rights reserved. This material may not be published, distributed, or reprinted without written consent from cyScape. http://www.learnASP.com/learn/troubles.asp by Charles M. Carroll Page 34 Errors: Basics (errors1.asp) - Page 35 Errors: Trapping EVERY Error (dbtablewitherrortrap.asp) - Page 36 Errors: DB Error Information Trapping (dbtroubleshoot.asp) - Page 37 DBFAQ: Operation must use Updatable Query (FAQdbUpdate.asp) - Page 38 DBFAQ: User Entered ' in field (FAQdbSinglequote.asp) - Page 39 DBFAQ: LIKE operator * not working (FAQdbLIKE.asp) - Page 40 DBFAQ: retrieving MEMO/BLOBs generates error (FAQdbMEMO.asp) - Page 41 DBFAQ: Syntax Error in SQL Statement (FAQdbSQLSyntax.asp) - Page 42 Errors: Trapping Open Connections (dbtroubleshootopen.asp) - Page 43 Troubleshoot: Getting Help from Lists! (asptroubles.asp) - Page 44 Troubleshoot: Worldwide (asptroubles2.asp) - Page 45 Troubleshoot: Specialized (asptroubles3.asp) - Page 46 Troubleshoot: Version of ASP Sofware (versioncheck.asp) - Page 47 Troubleshoot: Registered Components (componentchecker.asp) - Page 48 Troubleshoot: DB Drivers by Christophe Wille (connectioninfo.asp) - Page 49 PWS: Personal Web Server Introduction (PWS.asp) - Page 50 http://www.learnASP.com/learn/errors1.asp by Charles M. Carroll Page 35 Error Trapping #1 by Charles Carroll Now we will demonstrate how to trap VBScript errors that occur in your scripts with code. The script below runs without incident. All the syntax in the script is correct. 1 2 3 4 5 6 7 8 9 10 <TITLE>errordivide1.asp</TITLE> <body bgcolor="#FFFFFF"> <% ' ASP program that works if numbers are legit x=7 y=2 z=x/y response.write z & "<br>" %> </body></html> Now even though all the syntax in the script is correct, since one of the numbers has the effect of creating a "division by zero" error the script fails. 1 2 3 4 5 6 7 8 9 10 <TITLE>errordivide2.asp</TITLE> <body bgcolor="#FFFFFF"> <% ' ASP program that works if numbers are legit x=7 y=2 ' if changed to 0 this will crash z=x/y response.write z & "<br>" %> </body></html> Now we use the VBScript error trapping to present a message instead of a catastrophic script error. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <TITLE>errordivide3.asp</TITLE> <body bgcolor="#FFFFFF"> <% ' ASP program that works if numbers are legit on error resume next x=7 y=0 z=x/y response.write z & "<br>" If err.number=0 then response.end end if pad=" " response.write "<b>VBScript Errors Occured!<br>" response.write parm_msg & "</b><br>" response.write pad & "Error Number= #<b>" & err.number & "</b><br>" response.write pad & "Error Desc.= <b>" & err.description & "</b><br>" response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>" response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>" response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>" %> </body></html> http://www.learnASP.com/learn/dbtablewitherrortrap.asp by Charles M. Carroll Page 36 Displaying A Table from Query w/Bells & Whistles Displaying a table take very little code. A veteran will expand the basic code to deal with many errors that a novice will not have encountered until testing their web on a large scale. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 <TITLE>dbtablewitherrortrap.asp</TITLE> <body bgcolor="#FFFFFF"> <!--#include file="lib_errors.asp"--> <% on error resume next attempt="create connection object" set conntemp=server.createobject("adodb.connection") Call ErrorVBScriptReport(attempt) attempt="opening DSN" conntemp.open "DSN=Student;uid=student;pwd=magic" Call ErrorVBScriptReport(attempt) Call ErrorADOReport(attempt,conntemp) attempt="select * from authors where AU_ID<16" set rstemp=conntemp.execute(attempt) Call ErrorVBScriptReport(attempt) Call ErrorADOReport(attempt,conntemp) If rstemp.eof then response.write "No records matched your query" & "<P>" response.write attempt response.end end if attempt="counting fields" howmanyfields=rstemp.fields.count -1 Call ErrorVBScriptReport(attempt) Call ErrorADOReport(attempt,conntemp) %> <table border=1> <tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name %></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields%> <td valign=top><%=rstemp.fields(i)%></td> <% next %> </tr> <% rstemp.movenext loop rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </table> </BODY> </HTML> The error trapping library looks like this: 1 2 3 4 <% SUB ErrorVBScriptReport(parm_msg) If err.number=0 then exit sub 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 end if pad=" " response.write "<b>VBScript Errors Occured!<br>" response.write parm_msg & "</b><br>" response.write pad & "Error Number= #<b>" & err.number & "</b><br>" response.write pad & "Error Desc.= <b>" & err.description & "</b><br>" response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>" response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>" response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>" END SUB SUB ErrorADOReport(parm_msg,parm_conn) HowManyErrs=parm_conn.errors.count IF HowManyErrs=0 then exit sub END IF pad=" " response.write "<b>ADO Reports these Database Error(s) executing:<br>" response.write SQLstmt & "</b><br>" for counter= 0 to HowManyErrs-1 errornum=parm_conn.errors(counter).number errordesc=parm_conn.errors(counter).description response.write pad & "Error#=<b>" & errornum & "</b><br>" response.write pad & "Error description=<b>" response.write errordesc & "</b><p>" next END SUB %> http://www.learnASP.com/learn/dbtroubleshoot.asp by Charles M. Carroll Page 37 Error Trapping Database Code (by Charles Carroll) Before you use http://www.asplists.com and send a mail to get your question answered let us take a couple of minutes and try the following and see if it identifies your problem. There are tons of frightening messages that come up like: Microsoft OLE DB Provider for ODBC Drivers error '80040e07' [Microsoft][ODBC Microsoft Access 97 Driver] Data type mismatch in criteria expression. /somewhere/something.asp, line 12 Error #-2147217900 Error desc. -> [Microsoft][ODBC SQL Server Driver][SQL Server]Line 1: Incorrect syntax near ','. Error #-2147217900 Error desc. -> [Microsoft][ODBC Microsoft Access 97 Driver] Syntax error in UPDATE statement. Here are our guidelines for getting to the heart of the matter. First add some error code to the script to display the messages and bad SQL that causes the problem, for example: 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <title>dbtroubleshoot.asp</title>& <body> <!--#include file="lib_errors.asp"--> <% on error resume next Set Conn = Server.CreateObject("ADODB.Connection") conn.open "DSN=student;uid=student;password=magic" SQLstmt = "INSERT INTO junk (city,state,zip) VALUES ('Rockville','MD','20849')" Set RS = Conn.Execute(SQLStmt) Call ErrorVBScriptReport("Insert Statement") 14 15 16 17 18 19 20 21 Call ErrorADOReport(SQLstmt,conn) rs.close set rs=nothing Conn.Close set conn=nothing%> </body></html> Here is the include file that displays appropriate errors: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <% SUB ErrorVBScriptReport(parm_msg) If err.number=0 then exit sub end if pad=" " response.write "<b>VBScript Errors Occured!<br>" response.write parm_msg & "</b><br>" response.write pad & "Error Number= #<b>" & err.number & "</b><br>" response.write pad & "Error Desc.= <b>" & err.description & "</b><br>" response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>" response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>" response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>" END SUB SUB ErrorADOReport(parm_msg,parm_conn) HowManyErrs=parm_conn.errors.count IF HowManyErrs=0 then exit sub END IF pad=" " response.write "<b>ADO Reports these Database Error(s) executing:<br>" response.write SQLstmt & "</b><br>" for counter= 0 to HowManyErrs-1 errornum=parm_conn.errors(counter).number errordesc=parm_conn.errors(counter).description response.write pad & "Error#=<b>" & errornum & "</b><br>" response.write pad & "Error description=<b>" response.write errordesc & "</b><p>" next END SUB %> There is a set of links to Microsoft ADO knowledge base articles @ http://www.asptracker.com/demo/adokb1.asp which may prove invaluable. http://www.learnASP.com/learn/FAQdbUpdate.asp by Charles M. Carroll Page 38 Database listserve for help! FAQ #1:Operation must use an updateable query. I get this error message when adding or modifying data Microsoft OLE DB Provider for ODBC Drivers error '80004005' Database Error: [Microsoft][ODBC Microsoft Access Driver] Operation must use an updateable query. is a very common error message when updating Access databases. Since Access is file based any attempt to update the database by an ASP script can only modify the Access databases if permissions are established correctly. Go to the parent directory where the database is stored. Click on the folder permissions and set IUSER_xxxxx to 'change' where xxxxx is the machine name. Make sure the file is also set so the ISUSER_xxxx can change the file. http://www.learnASP.com/learn/FAQdbSinglequote.asp by Charles M. Carroll Page 39 Database listserve for help! FAQ #2: A user attempted to edit or add data to the database that had a single quote in the name (for example Bill's Fish Shop or O'Reilly). Now the form gives an error when adding or updating. This is a very common error message when updating or adding to databases. Let us look at 3 SQL statements: UPDATE customer FIELDS (Name,City,State,Zip) _ VALUES ('Acme Inc.','Rockville','MD','20849') _ WHERE custid=20 works fine! UPDATE customer FIELDS (Name,City,State,Zip) _ VALUES ('Acme's Store','Rockville','MD','20849') _ WHERE custid=20 will fail because it the single ' confuses the SQL parser. UPDATE customer FIELDS (Name,City,State,Zip) _ VALUES ('Acme''s Store','Rockville','MD','20849') _ WHERE custid=20 will succeed because it the single ' was entered as '' which satisfies the SQL parser. UPDATE customer FIELDS (Name,City,State,Zip) _ VALUES ('Ledos','Pike's Peak','CO','000000') _ WHERE custid=20 will fail because it the single ' confuses the SQL parser. UPDATE customer FIELDS (Name,City,State,Zip) _ VALUES ('Ledos','Pike''s Peak','CO','000000') _ WHERE custid=20 will succeed because it the single ' was entered as '' which satisfies the SQL parser. In your code you may be building your SQL statement from variables, i.e. co=request("company") cy=request("city") st=request("state") id=request("keycust") mySQL = "UPDATE customer FIELDS (" mySQL = MySQL & "Name,City,State,Zip) " mySQL = MySQL & "VALUES ('" & co & "'," mySQL = MySQL & "'" & cy & "'," mySQL = MySQL & "'" & st & "'," mySQL = MySQL & "'" & zip & "'" mySQL = MySQL & "WHERE keycust=" & id and this will work fine as long as the user never enter an ' in the data. But to be robust, you should use a built-in function called replace that can find characters in a string and replace them with alternate characters. For example the code above could be replaced with: co=request("company") cy=request("city") st=request("state") id=request("keycust") co=replace(co,"'","''") cy=replace(cy,"'","''") mySQL = "UPDATE customer FIELDS (" mySQL = MySQL & "Name,City,State,Zip) " mySQL = MySQL & "VALUES ('" & co & "'," mySQL = MySQL & "'" & cy & "'," mySQL = MySQL & "'" & st & "'," mySQL = MySQL & "'" & zip & "'" mySQL = MySQL & "WHERE keycust=" & id and it would work even if the user input ' in the company or city field because they would be doubled up and acceptable to the SQL parser. Additional Information: Check MS knowledgebase article Q178070 (HOWTO : Handle Quotes and Pipes in Concatenated SQL Literals) which suggests all pipe characters be replaced with chr(124) The article can be found at http://support.microsoft.com/support/kb/articles/q178/0/70.asp http://www.learnASP.com/learn/FAQdbLIKE.asp by Charles M. Carroll Page 40 Database listserve for help! FAQ #3: I have a query utilizing LIKE that works great in Access but produces an error in ASP. This is a very common error message when querying databases and the person learned to query in Access. Access uses * for multiple character wildcards and ? for individual character wildcards. Access ASP/ADO * ? % _ Let us look at 2 typical Access Query statements: SELECT * from customer where city LIKE "N*" works fine in Access! produces an error in ASP. SELECT * from customer where city LIKE "N%" works fine in ASP. SELECT * from customer where phrase LIKE "N?w" works fine in Access! produces an error in ASP. SELECT * from customer where phrase LIKE "N_w" works fine in ASP. http://www.learnASP.com/learn/FAQdbMEMO.asp by Charles M. Carroll Page 41 Database listserve for help! FAQ #4: My memo fields are not working. I get the error message: Microsoft OLE DB Provider for ODBC Drivers error '80020009' Let us look at a typical problem Query and the solution: SELECT * from cargo where city LIKE "New York" produces errors if the memo fields are retrieved. (for the sake of this example the memo fields are marked in red CargoID, CargoName, Comments, Street, City, State,Zip, ShippingNotes and DueDate) MEMO/BLOBS must be listed last explictly. SELECT CargoID,CargoName, Street,City, State,Zip,DueDate,ShippingNotes,Comments from cargo where city LIKE "New York" produces no errors since the memo fields are listed last. Check out http://support.microsoft.com/support/kb/articles/q175/2/39.asp as well for more details. http://www.learnASP.com/learn/FAQdbSQLSyntax.asp by Charles M. Carroll Page 42 Database listserve for help! FAQ #5: Syntax Error in Database Statement 90% of the problems submitted to the listserves could be solved by systematically checking your code against these guidelines. If you complete all of these steps, then submit it to the list, but most people will solve their problem without the list! Step 1: did you write the SQL statement to the browser? ....code... conn.execute(SQLstuff) ....code... needs to be converted to: ....code... response.write SQLstuff conn.execute(SQLstuff) ....code... The SQLstatement written to the browser will allow Step 2 and Step 3 to be checked. The code tells you little about the syntax error until you write what the code assembles. Step 2: Are the field names a problem? a. Forbidden/cantankerous field names Do not name a field date. It will create problems. A query like select * from employees where date=#1/17/98# will fail even though it is syntactically correct because date is a forbidden name. Rename the field, so the query could look like "select * from employees where hiredate=#1/17/98# and you are "out of the woods" b. Field names with spaces A field name that has embedded spaces will create problems if you don't surround it with square brackets when referencing it in the query. A query like select * from employees where state of residence='MD' will fail even though it is syntactically correct because state of residence is a field with spaces in the name. A query like select * from employees where [state of residence]='MD' will succeed because the fieldname is delimited properly. Step 3: Check for these common Syntax Errors? a. Text Fields get surrounded by ' ' and numeric fields do not! A query like: select * from employees where city=Rockville and State=MD and yearsresiding>9 will fail because the text fields were not delimited properly. A query like: select * from employees where city='Rockville' and State='MD' and yearsresiding>9 succeeds. b. Date fields get surrounded by # # A query like: select * from employees where birthdate>1/1/1966 will fail because the date fields were not delimited properly. A query like: select * from employees where birthdate>#1/1/1966# succeeds. http://www.learnASP.com/learn/dbtroubleshootopen.asp by Charles M. Carroll Page 43 Database Error Trapping: Opening Database by Charles Carroll Many people want to intercept specific errors and replace them with friendly messages. Here is some sample code that catches mispelled DSNs and bad login/user ids: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <html><head> <title>dbtroubleshoot.asp</title>& <body> <% on error resume next Set Conn = Server.CreateObject("ADODB.Connection") my_DSN="DSN=student;uid=student;password=magic2" conn.open my_DSN Call CheckOpen Conn.Close set conn=nothing SUB CheckOpen If err.number>0 then%> <b>VBScript Errors Occured:</b><br> Error Number=<%=err.number%><br> Error Descr.=<%=err.description%><br> Help Context=<%=err.helpcontext%><br> Help Path=<%=err.helppath%><br> Native Error=<%=err.nativeerror%><br> Source=<%=err.source%><br> SQLState=<%=err.sqlstate%><P> <%else%> No VBScript problems occured!<p> <%end if IF conn.errors.count> 0 then%> <b>ADO Reports these Database Error(s):</b><br> 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <% maxerrors=conn.errors.count-1 for counter= 0 to maxerrors DBErrorNum=conn.errors(counter).number DBErrorDesc=conn.errors(counter).description SELECT CASE DBErrorNum CASE -2147467259 response.write "Problem => <b>Bad DSN</b><br>" response.write "DSN => <b>" & my_DSN & "</b><br>" CASE -2147217843 response.write "Problem => <b>Bad Login Info</b><br>" response.write "DSN => <b>" & my_DSN & "</b><br>" exit sub CASE ELSE%> Error # = <b><%=DBErrorNum%></b><br> Error description = <b><%=DBerrorDesc%></b><p> <%END SELECT next else%> Everything Went Fine <% end if END SUB%> </body></html> http://www.learnASP.com/learn/asptroubles.asp by Charles M. Carroll Page 44 ASP Troubleshooting Resources Part1 When your Active Server Page code does not work, we actually manage a listserv you can write to send in your code and have your colleagues from around the world on the listserv help you fix it. Warning: One of listservers -- [aspfreeforall] -- is quite noisy (40-50 messages a day) with many people helping each other. People having trouble with ASP code communicating with a specific database should try their questions on one of these lists: Access DB2 AS400 Dbase Fox/Visual FoxPro Informix SQLserver 6.5 SQLserver 7.x Oracle Setup/Can't Connect! Oracle Paradox Reports/Printing (Crystal, PDF, etc.) RDS (Remote Data Services) SQL: Joins, complex queries, shaping Sybase People having trouble with ASP and does not have code communicating with a specific database can sign up for one of our general listservers Beginning - Any ASP questions [aspfreeforall] Intermediate - NO beginner questions [aspnotnewbie] Advanced - tough ASP questions only! [aspadvanced] [aspadvanced] Strict Rules Installing,Upgrading ASP [aspinstall] ASP Database Beginners [aspdatabasefreeforall] ASP Databases Advanced Users [aspdatabases] http://www.learnASP.com/learn/asptroubles2.asp by Charles M. Carroll Page 45 ASP Troubleshooting Resources (Worldwide) When your Active Server Page code does not work, we actually manage many listserves that provide help and are run entirely in non-English languages. You can write to send in your code and have your colleagues from around the world on the listserv help you fix it in your native language. Arabic Bengali Chinese Danish Dutch Farsi Finnish French German German ASP Jobs German ASP Coffee House Hebrew Hindi Indonesian Icelandic Italian Japanese Korean Malay Norweigan Polish Portugese Russian Spanish Swedish Swedish Advanced Turkish Thai Urdu http://www.learnASP.com/learn/asptroubles3.asp by Charles M. Carroll Page 46 ASP Troubleshooting Resources Part 3 Sometimes your problem is tough and requires multiple mails to resolve and the answers becomes quite complex and/or obscure. Such problems don't get solved well on general lists like [aspfreeforall] or [aspdatabases]. However, we have some lists where specialized topics thrive. All the best people hang out there, the archives are devoid of general questions, game is plentiful, and the sun shines and nary a cloud appears. Here is a master list of all the specialized listserves we run. They will NOT FLOOD YOUR MAILBOX since the topic scope is so narrow. Beginners to Intermediate Lists ASPFreeForAll [aspfreeforall] The worlds noisiest and helpful ASP list -- 20-40 posts per day and any questions are allowed. It is the only unmoderated list we run. signup form at http://www.activeserverpages.com/aspfreeforall ASPDatabaseFreeForAll [aspfreeforall] Noisy, but an ideal place for database beginners. 1/2 the noise of [aspfreeforall] since only database questions are allowed. signup form at http://www.activeserverpages.com/aspdatabasefreeforall ADSI [aspadsi] beginners and all level of ADSI questions welcomed here. signup form at http://www.activeserverpages.com/aspadsi Ecommerce w/ASP [ecommerce] This list is to discuss credit cards, HTTPS://, shopping carts and the ASP topics that intersect with commerce. Non-commerce questions will be rejected. signup form at http://www.activeserverpages.com/aspcommerce Index Server [aspindexserver] Index Server only. No ASP general scripting questions allowed! signup form at http://www.activeserverpages.com/aspindexserver International/Multilingual ASP [aspinternational] This list is to discuss multilingual websites (including multi-byte character sets, FEPs, translation services, etc.) and non-English ASP issues, secure and international encryption issues, etc. Questions that don't deal with international or multilingual issues will be rejected. signup form at http://www.activeserverpages.com/aspinternational Jscript ASP [jscript] This list is to discuss server Jscript and client Jscript occasionally. Frames would not be out of the question here, as all the "right" type of people are there to answer. signup form at http://www.activeserverpages.com/aspjscript PerlScript w/ASP [aspPerlscript] This list is to discuss Perlscript only. signup form at http://www.activeserverpages.com/aspPerlscript ASP Site Server [aspsiteserver] This list is to discuss Site Server issues only. General ASP questions will be rejected. signup form at http://www.activeserverpages.com/aspsiteserver Component Building (including MTX, MSMQ) Visual Basic ASP component building [vbcomponents] This list is to discuss Visual Basic component building only. Of course MTX and MSMQ with components is right on topic too. General ASP scripting questions will be rejected here. signup form at http://www.activeserverpages.com/aspvbcomponents Delphi ASP component building [aspDelphi] This list is to discuss Delphi component building only. Of course MTX and MSMQ with components is right on topic too. General ASP scripting questions will be rejected here. signup form at http://www.activeserverpages.com/aspdelphi C++ low-level component building [low-levelcomponents] This list is to discuss C++ component building only. Of course MTX and MSMQ with components is right on topic too. General ASP scripting questions will be rejected here. signup form at http://www.activeserverpages.com/asplowlevelcomponents VB WebClasses [aspvbwebclasses] This list is to discuss IIS webclasses only. These are specific types of VB6 apps that are optimized to work with ASP. General scripting questions not allowed. signup form at http://www.activeserverpages.com/aspvbwebclasses Databases ASP SQL How-To [aspSQLhowto] This list is to discuss complex joins, complex queries, and how to do certain complex tasks involving SQL. It is not a troubleshooting list and broken code questions and questions that are newbie in nature are always rejected. signup form at http://www.activeserverpages.com/aspsqlhowto ASP Databases [aspdatabases] This list is to discuss database troubleshooting but is not a beginner's lists. Many beginners questions ( ' questions, permissions, how do I edit a database) will be rejected as to not distract from the tough issues being discussed. signup form at http://www.activeserverpages.com/aspdatabases ASP Reporting from Databases [aspreporting] This list is to discuss reports with tools like PDF, Crystal Reports, Chilisoft Reports, etc. No database questions or ASP questions will be allowed if reports are not part of the topic. signup form at http://www.activeserverpages.com/aspreporting ASP RDS (Remote Data Services) [aspRDS] This list is to discuss Remote Data Service and how they can be integrated into ASP sites. signup form at http://www.activeserverpages.com/asprds Databases/Vendor Specific DB2AS400 [aspdb2as400] Only to discuss drivers, stored procedures, SQL variations, and vendor specific issues concerning ASP pages and components communication with IBM DB2/AS400 databases. signup form at http://www.activeserverpages.com/aspdb2as400 Informix [aspinformix] Only to discuss drivers, stored procedures, SQL variations, and vendor specific issues concerning ASP pages and components communication with Informix databases. signup form at http://www.activeserverpages.com/aspinformix Oracle [asporacle] Only to discuss drivers, stored procedures, SQL variations, and vendor specific issues concerning ASP pages and components communication with Oracle databases. signup form at http://www.activeserverpages.com/asporacle Sybase [aspsybase] Only to discuss drivers, stored procedures, SQL variations, and vendor specific issues concerning ASP pages and components communication with Sybase databases. signup form at http://www.activeserverpages.com/aspsybase SQLserver7 [aspsqlserver7] Only to discuss drivers, stored procedures, SQL variations, and vendor specific issues concerning ASP pages and components communication with SQLServer 7 databases. signup form at http://www.activeserverpages.com/aspsqlserver7 Editors ASP with Visual Interdev [aspvisualinterdev] This list is to discuss Visual Interdev editor issues only. As long as you are editing your code with Interdev, this is the list for you! signup form at http://www.activeserverpages.com/aspvisualinterdev ASP with Drumbeat/Drumbeat 2000 [aspDrumbeat] This list is to discuss Drumbeat issues only. As long as you are editing your code with Drumbeat, this is the list for you! signup form at http://www.activeserverpages.com/aspdrumbeat ASP with NetObjects Fusion [aspnetobjects] This list is to discuss Netobject editor issues only. As long as you are editing your code with Netobjects, this is the list for you! signup form at http://www.activeserverpages.com/aspnetobjects Non-Technical Lists ASP Jobs [jobs/consult] This list is to post jobs, or indicate your availablity for jobs. Consulting assignments, full time jobs and resumes are the only topics allowed here; no how-to allowed. signup form at http://www.activeserverpages.com/aspjobs ASP Gripes [aspgripe] This list is for readers to complain about ASP products they bought and were unhappy with to share their experiences! signup form at http://www.activeserverpages.com/aspgripe ASP Convention [aspconvention] This list is to discuss the many www.aspconvention.com events that occur throughout the year. signup form at http://www.activeserverpages.com/aspconvention ASP Training [asptraining] This list is to discuss people who need training and companies who offer training can post their classes here too and interact with potential customers. signup form at http://www.activeserverpages.com/asptraining Free Code & Components [aspfreecodecomponents] This list is to offer FREE code and components. No how-to allowed, just send the list the FREE code or component URLs you are giving away. signup form at http://www.activeserverpages.com/aspfreecodecomponents Server Admin Crashed/Hung Servers [aspcrash] Only crashes and hung servers and mysterious error messages are discussed here. No scripting how-to or server admin allowed. signup form at http://www.activeserverpages.com/aspcrash Installing ASP [aspinstall] Only installs, service pack upgradees are allowed here. No scripting how-to allowed. signup form at http://www.activeserverpages.com/aspinstall Server Admin [aspserver] This list is to discuss IIS, NT, and MMC from a network administrators standpoint as they work with ASP coders. signup form at http://www.activeserverpages.com/aspserver 3rd Party Products ASPDB Product Support [aspdbmajormicro] This list is to discuss using the ASPDB component. General ASP questions not allowed. signup form at http://www.activeserverpages.com/aspdbmajormicro ServerObjects.com Support [aspserverobjectscom] This list is to discuss using components from www.serverobjects.com on your site. General ASP questions not allowed. signup form at http://www.activeserverpages.com/aspserverobjectscom SoftArtisans Product Support [aspsoftartisans] This list is to discuss using components made by www.softartisans.com. General ASP questions not allowed. signup form at http://www.activeserverpages.com/aspsoftartisans WROX Readers Support [aspwroxreaders] This list is to discuss questions and coding issues arising from reading books published by WROX -- i.e. the code in Chapter 13 has this problem etc. If your question didn't originate because of code in a WROX book it will be rejected. signup form at http://www.activeserverpages.com/aspwroxreaders Technology Specific LDAP [aspldap] Communicating with LDAP stores by any mechanism (whether using ADSI, APIs, etc.) is the only topic allowed in this list. signup form at http://www.activeserverpages.com/aspLDAP Lotus Notes [asplotusnotes] signup form at http://www.activeserverpages.com/asplotusnotes MAIL from ASP: Outlook, Exchange, CDO, 3rd Party [aspmail] only getting mail out of ASP pages and interface to mail and appointment stores are discussed here. signup form at http://www.activeserverpages.com/aspmail MSOffice and ASP [aspmsoffice] automating Word,Excel,Powerpoint, Project with ASP is the only topic here. signup form at http://www.activeserverpages.com/aspmsoffice Advanced Listserves ASP FastCode [aspFastCode] This list is to discuss speeding up code. Broken code or how-to is not the topic. Basically your code must work, but you want to make it faster. signup form at http://www.activeserverpages.com/aspfastcode ASP NotNewbie [aspnotnewbie] This list is for people who don't want to be on a beginners list but are not super-advanced yet. Beginners posts will be rejected always. signup form at http://www.activeserverpages.com/aspnotnewbie ASP Advanced ADSI [aspadvadsi] This list is to discuss the ADSI issues no other list has resolved after much research. signup form at http://www.activeserverpages.com/aspadvadsi http://www.learnASP.com/learn/versioncheck.asp by Charles M. Carroll Page 47 Version Check by Charles Carroll DRAFT This checks what software you are using on your server. 1 <%@ language=vbscript%> 2 <HTML> 3 <HEAD> 4 <TITLE>versioncheck.asp</TITLE> 5 </HEAD> 6 <body bgcolor="#FFFFFF"> 7 <script language=jscript runat=server> 8 response.write ("scripting engine=<b>" + ScriptEngine() + "</b><br>"); 9 response.write ("buildversion=<b>" + ScriptEngineBuildVersion() + "</b><br>"); 10 response.write ("majorversion=<b>" + ScriptEngineMajorVersion() + "</b><br>"); 11 response.write ("minorversion=<b>" + ScriptEngineMinorVersion() + "</b><br>"); 12 </script> 13 14 <% 15 response.write "<hr><br>" 16 response.write "scripting engine=<b>" & scriptengine() & "</b><br>" 17 response.write "buildversion=<b>" & scriptenginebuildversion() & "</b><br>" 18 response.write "majorversion=<b>" & scriptenginemajorversion() & "</b><br>" 19 response.write "minorversion=<b>" & scriptengineminorversion() & "</b><br>" 20 21 response.write "<hr><br>" 22 set tempconn=server.createobject("adodb.connection") 23 response.write "ado version=<b>" 24 response.write tempconn.version & "</b><br>" 25 set tempconn=nothing 26 27 response.write "<hr><br>" 28 serversoftware=request.servervariables("server_software") 29 response.write "server software=<b>" 30 response.write serversoftware & "</b><br>" 31 32 Response.Write "Script Timeout = <b>" & Server.ScriptTimeout & " seconds</b><br>" 33 Response.Write "Session Timeout = <b>" & Session.Timeout & " minutes</b><br>" 34 %> 35 36 </BODY></HTML> http://www.learnASP.com/learn/componentchecker.asp by Charles M. Carroll Page 48 Component Checker by Charles Carroll determine what components are on your server The script reads the component.ini file we created and reports whether each of the components in that file can be created. 1 <TITLE>componentchecker.asp</TITLE> 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 <body bgcolor="#FFFFFF"> <% dim successSTR, FailSTR, checkSTR whichfile=server.mappath("component.ini") Set fs = CreateObject("Scripting.FileSystemObject") Set thisfile = fs.OpenTextFile(whichfile, 1, False) counter=0 do UNTIL thisfile.AtEndOfStream counter=counter+1 thisline=thisfile.readline attempt=trim(thisline) pad=" " DO WHILE attempt="" thisline=thisfile.readline attempt=trim(thisline) LOOP If mid(thisline,1,1)="[" then ' ignore CheckSTR=CheckSTR & thisline & " " lastcategory=category category=lcase(thisline) oldcategory=mid(category,1,Len(category)-1) category=replace(category,"www.","<a href='http://www.") IF instr(category,"href")>0 then category=mid(category,2) category=category & "'>" & oldcategory & "]</a>" END IF group= "<b>" & category & " component group</b><br>" successcount=0 failcount=0 thisline=thisfile.readline attempt=thisline end if on error resume next set tempobject=server.createobject(attempt) eol="<br>" & vbcrlf whicherr=err.number If whicherr=0 then if successcount=0 then successSTR=successSTR & group end if vleft=" (ver=" vright=") " SELECT CASE lcase(attempt) CASE "adodb.connection" version= vleft & tempobject.version & vright CASE ELSE version="" END SELECT successSTR= successSTR & pad & "<b>" & attempt & version & "</b> successfull!" & eol successcount=successcount+1 else if failcount=0 then FailSTR=FailSTR & group end if IF whicherr=-2147221005 THEN msg = " is not registered!" ELSE msg = " failed. Error #" & whicherr END IF FailSTR= failSTR & pad & "<b>" & attempt & "</b>" & msg & eol failcount=failcount+1 end if set tempobject=nothing 69 70 71 72 73 74 75 76 77 78 loop thisfile.Close set thisfile=nothing set fs=nothing response.write "Checked: " & checkSTR & "<hr>" response.write successSTR & "<hr>" response.write failSTR %> This component.ini file contains a list of typical server components, grouped by type. Type is indicated within [ ] codes. Here is the contents of the current component.ini: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 [standard] mswc.browsertype mswc.nextlink scripting.dictionary scripting.filesystemobject [ado] adodb.recordset adodb.connection adodb.command [cdo] CDONTS.NewMail [cyscape] cyScape.browserObj [indexserver] ixsso.Query ixsso.Util [Lyris] Lyris.LCP [http://msdn.microsoft.com/scripting] Wscript.Shell [msfreebies] iissample.asp2htm iissample.contentrotator iissample.registry iissample.summaryinfos iissample.tracer mswc.adrotator mswc.counters mswc.myinfo MSWC.PageCounter MSWC.PermissionChecker mswc.tools mswc.loadbalance [msXML] microsoft.XMLHTTP microsoft.XMLDOM [www.aspdb.com] ASPdb.Free ASPdb.View ASPdb.Pro ASPdb.EP [www.serverobjects.com] ASPChart.Chart AspConv.Expert 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 AspDNS.Lookup AspFile.FileObj AspHTTP.Conn AspImage.Image AspInet.FTP AspMX.Lookup AspNNTP.Conn AspPager.Pager SMTPsvg.Mailer [www.softartisans.com] SoftArtisans.FileUp SoftArtisans.SACheck SoftArtisans.SASessionPro SoftArtisans.FileManager EZsite.Calender EZsite.CalendarManager EZsite.WebNotes [www.active4.com] ActiveLaunch.Control ActiveSAR.SearchAndReplace ActiveShopper.Cart ActiveShopper.BasketItem FileTouch.Control PCAuthX.Authorizer Prt2Disk.Control SemClient.Control SPrinterPro.Object TimeSpan.Control WWWPrint.Client [Zaks Software] ZaksPop3.Server JavaPop3.Mailer [www.persits.com] Persits.MailSender [www.oceantek.com] ASPL.Login [www.able-consulting.com] ACI.WhoIs [www.softwing.com] Softwing.EventLogReader Softwing.OdbcRegTool w3info.w3info.1 InetCtls.Inet.1 Softwing.AspQPerfCounters SQLOLE.SQLServer SOFTWING.ASPEventlog SOFTWING.ASPtear SOFTWING.EDConverter SOFTWING.EventLogReader SOFTWING.FileCache.1 SOFTWING.OdbcRegTool SOFTWING.LocaleFormatter SOFTWING.Profiler [www.dougdean.com] EZsite.EZuploadLite [www.algonet.se/~jekman] lightcom.xBrowser lightcom.xContent 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 lightcom.xPop3 lightcom.xSMTP lightcom.xTree lightcom.xBrowser JESoftware.xContent JESoftware.xPop3 JESoftware.xSMTP JESoftware.xTree [tech.dimac.net] Socket.TCP [www.de-info.com] checkemail.maccheckemail [www.pstruh.cz] TCPIP.Trace TCPIP.DNS [www.dana-net.com/products/aspcomponents/magicregistry] MagicRegistry.Tricks http://www.learnASP.com/learn/connectioninfo.asp by Charles M. Carroll Page 49 Connection Info by Christophe Wille Christoph.Wille@softwing.com http://www.softwing.com/iisdev If you want to know what drivers and other vital details are being used for a DSN, here is some code to the rescue. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <html><head> <title>connectioninfo.asp by Christophe Wille http://www.softwing.com</title> </head> <!--#include file="lib_connectioninfo.asp"--> <body> <% response.write "<hr>SQL Server Connection" Call DSNinfo("DSN=student;uid=student;pwd=magic") response.write "<hr>Access Connection Connection" theDSN="DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" theDSN=theDSN & server.mappath("/learn/test/biblio.mdb") Call DSNInfo(theDSN) %> </body> </html> The Include file looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <% SUB DSNInfo(strDSN) Set cnn1 = Server.CreateObject("ADODB.Connection") Set rsQuery = Server.CreateObject("ADODB.RecordSet") cnn1.open strDSN response.write response.write response.write response.write response.write response.write response.write response.write response.write "ADO Version: " & cnn1.Version "<BR>" & vbcrlf strVersionInfo & "DBMS Name: " & cnn1.Properties("DBMS Name") "<BR>" & vbcrlf "DBMS Version: " & cnn1.Properties("DBMS Version") "<BR>" & vbcrlf "OLE DB Version: " & cnn1.Properties("OLE DB Version") "<BR>" & vbcrlf "Provider Name: " & cnn1.Properties("Provider Name") 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 response.write response.write response.write response.write response.write "<BR>" & vbcrlf "Provider Version: " & cnn1.Properties("Provider Version") "<BR>" & vbcrlf "Provider Friendly Name: " & cnn1.Properties("Provider Friendly Name") "<BR>" & vbcrlf If 0 = Instr(LCase(cnn1.Properties("Provider Name")),"oledb") then ' ### no OLE DB Provider used, therefore : response.write "Driver Name: " & cnn1.Properties("Driver Name") response.write "<BR>" & vbcrlf response.write "Driver Version: " & cnn1.Properties("Driver Version") response.write "<BR>" & vbcrlf response.write "Driver ODBC Version: " & cnn1.Properties("Driver ODBC Version") response.write "<BR><BR>" end if Set rsQuery = nothing Set cnn1 = nothing END SUB %> http://www.learnASP.com/learn/PWS.asp by Charles M. Carroll Page 50 Personal Web Server (PWS) by Charles Carroll The Personal Web Server is a marvellous tool because it lets you develop and test websites ● without being connected to the Internet ● without placing your code on the World-Wide-Web or a server until it is tested off-line and totally debugged. The address of your personal web server is: http://127.0.0.1 It has other aliases, like http://localhost but it true reliable name is the one above. http://www.learnASP.com/learn/Form.asp by Charles M. Carroll Page 51 Forms: Introduction (formintro.asp) - Page 52 Forms: Text Box (formtextbox.asp) - Page 53 Forms: Text Area (formtextarea.asp) - Page 54 Forms: Check Box (formcheckbox.asp) - Page 55 Forms: Radio Buttons (formradio.asp) - Page 56 Forms: List Box (formlistbox.asp) - Page 57 Forms: CASE syntax #1 (case.asp) - Page 58 Forms: CASE syntax #2 (case2.asp) - Page 59 Forms: IF syntax #1 (if.asp) - Page 60 Forms: IF syntax #2 (if2.asp) - Page 61 Forms: IF syntax #3 (if3.asp) - Page 62 Forms: IF syntax #4 (if4.asp) - Page 63 Forms: For Each Iteration (formforeach.asp) - Page 64 Forms: mailing w/ASPMail (formsendmail.asp) - Page 65 Cookies: Reading Them (cookiesform.asp) - Page 66 Cookies: Writing Them (cookiesformrespond.asp) - Page 67 Cookies: Deleting Them (cookiesforget.asp) - Page 68 Cookies: Simplified by Paul Rigor (cookiesub.asp) - Page 69 http://www.learnASP.com/learn/formintro.asp by Charles M. Carroll Page 52 Forms Introduction by Charles Carroll Forms are the primary way that a user feeds information into ASP. A form is a web page that contains tags that cause the browser to show fields that the user can fill in. ● Forms can be HTML files. They only need to be ASP if ASPy type capabilities are needed (session variables, includes). ● The form must pass the variables onto a .asp file to process the form. ● An excellent form tutorial can be found at: http://www.mountaindragon.com/html/forms.htm Form with GET ● <form action="x.asp" name="whatever" method=get> .... <input type=submit> <input type=reset> </form> there is a limit on the number of characters (approximately 4,000 but varies depending on server and browsers involved. ● The form will show it's parameter in the browser address window, for example: testform.asp?state=md&city=Germantown would be the URL in the browser, if the state and city field were populated. ● An ASP script picks up a form field with: <%whatever=request.querystring("whichfield")%> Form with POST ● <form action="x.asp" name="whatever" method="post"> .... <input type=submit> <input type=reset> </form> It supports many more characters than get (megabytes of data in case of file uploads) ● The form will not show it's parameter in the browser address window, for example: http://whatever.com/testform.asp would be the only URL in the browser, regardless of how many fields and how much data is passed. ● An ASP script picks up the form field with: <%whatever=request.form("whichfield")%> Tips: Tip #1: If using response.redirect to simulate a GET don't forget to encode: /learn/encode.asp Tip #2: a text link to post above form would look like this: <a href="javascript:submitform(document.forms['whatever'])"> whatever</a> thanks to Remko van der Vossen <R.vanderVossen@chello.nl> for this tip I looked high and low for. http://www.learnASP.com/learn/formtextbox.asp by Charles M. Carroll Page 53 Forms - Text Box (by John Kauffman & Charles Carroll) This will create an input box of a default size and the browser will pass the user input to ASP with the label (identifier) of NameLast. This is not a limit to the number of characters that can <INPUT NAME="ZipCode" SIZE="10"> be entered. Do not use size as a validation technique to limit verbose users. This controls the maximum number of characters that <INPUT NAME="State" MaxLength="2"> can be entered. The name of Bertrand will appear when the page is <INPUT NAME="NameLast" VALUE="Bertrand"> opened and will re-appear if the form is reset. <INPUT NAME="NameLast"> 1 2 3 4 5 6 7 8 9 10 11 <html><head> <title>FormTextBox.asp</title> </head><body bgcolor="#FFFFFF"> <Form action = "FormTextBoxRespond.asp" method="get"> Fill Out This Form For Us:<p> Last Name -> <Input NAME="NameLast" size ="10"><br> Country -> <Input NAME="Country" value="USA" size=10><br> State -> <Input NAME="State" MaxLength="2" size=2><br> <Input type="submit" value="Give me your data!"> <hr></form> </body></html> 1 2 3 4 5 6 7 8 9 10 11 12 <html><head> <title>FormTextBoxRespond.asp</title> </head><body bgcolor="#FFFFFF"> <% lname=request.querystring("namelast") cty=request.querystring("country") st=request.querystring("state") response.write lname & "<br>" response.write cty & "<br>" response.write st & "<br>"%> </body></html> http://www.learnASP.com/learn/formtextarea.asp by Charles M. Carroll Page 54 Forms - Text Area (by John Kauffman) Multi-line text boxes are created using the TEXTAREA command as follows: <TEXTAREA NAME="UserComments" ROWS=5 COLS=50> ... default text is typed here </TEXTAREA> Notes: Windows browsers typically provide scroll bars automatically. Although the TEXT tag does not need to be closed, the TEXTAREA must have a </TEXTAREA> The TEXTAREA tag (like all of the user-input objects) must be within the form tags discussed earlier. 1 2 <html><head> <TITLE>formTextArea.asp</TITLE> 3 4 5 6 7 8 9 10 11 12 </head><body bgcolor="#FFFFFF"> <form action="FormTextAreaRespond.asp" method="post"> <p>TextArea Example</p> <p>Please type your special shipping comments:</p> <TEXTAREA NAME="shippingComments" ROWS=5 COLS=50> shipping comments go here </textarea> <p><input type=submit value="send in comments!"> </form> </body></html> The responder to the form will look like this: 1 2 3 4 5 6 7 8 9 <html><head> <TITLE>formTextArearespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% comm=request.form("shippingcomments") response.write comm %> <hr> </body></html> http://www.learnASP.com/learn/formcheckbox.asp by Charles M. Carroll Page 55 Forms - Check Boxes (by John Kauffman & Charles Carroll) The checkbox object is coded along the same lines as radio buttons, however each checkbox must get its own unique name since the state of "checked" or "not checked" will be passed to ASP for each box. Remember that you can set more than one option to be checked. 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <TITLE>FormCheckBox.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="FormCheckBoxRespond.asp" method="post"> <p>CheckBox Form Example</p> <p>How do you want your order confirmed?</p> <input TYPE="checkbox" NAME="USMail">confirmation sent by first class US Postal Service<br> <input TYPE="checkbox" NAME="UPS">confirmation sent by UPS overnight letter service<br> <input TYPE="checkbox" NAME="EMail" CHECKED>confirmation sent by EMail<br> <input TYPE="checkbox" NAME="Fax">confirmation sent by Fax<br> <input TYPE="checkbox" NAME="Tel" CHECKED>confirmation made by telephone call<br><br> <input type="submit"><input type="reset"> </form><hr></body></html> The responder looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <html><head> <TITLE>formCheckBoxRespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% If request.form("USMail")="on" then response.write "<br>We will confirm end if If request.form("UPS")="on" then response.write "<br>We will confirm end if If request.form("EMail")="on" then response.write "<br>We will confirm end if If request.form("fax")="on" then response.write "<br>We will confirm by US Mail" by UPS" by EMail" by fax" 16 17 18 19 20 21 end if If request.form("tel")="on" then response.write "<br>We will confirm by tel" end if%> </body> </html> http://www.learnASP.com/learn/formradio.asp by Charles M. Carroll Page 56 Forms - Radio Buttons (by John Kauffman) All of your user input objects in a form must have their own unique name which will be the label that the browser will assign to them when passing the data to ASP. The exceptions are radio buttons. Since only one piece of information will be passed to ASP from a set of radio buttons, they all get the same name. HTML requires that one of the buttons is selected by default, the one indicated by the CHECKED command. It is important to understand that the browser will send back to ASP the name and the value of the one button which is selected by the user. The browser will NOT send back the text which is associated with the button. For the example above, if the user checked on the button with the text New York City, then ASP would receive City=NY. 1 2 3 4 5 6 7 8 9 10 11 12 <html><head> <TITLE>formRadio.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="FormRadiorespond.asp" method="post"> <p><b>Radio Buttons </b> example</p> <p>Which Regional Office will you be visiting?</p> <input TYPE="radio" NAME="City" VALUE="NY">New York City <input TYPE="radio" NAME="City" VALUE="LA">Los Angeles <input TYPE="radio" NAME="City" VALUE="SV" CHECKED>Savannah <br><input type="submit" value="choose a city"> </form> </body></html> The responder looks like: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html><head> <TITLE>formradiorespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <%myCity = request.form("City") Select Case ucase(MyCity) case "NY" response.write "New York meeting is on Jan 3" case "LA" response.write "LA meeting meeting is on Jan 15" case "SV" response.write "Savannah meeting is on Jan 20" End Select%> </body> </html> http://www.learnASP.com/learn/formlistbox.asp by Charles M. Carroll Page 57 Forms - List Boxes (by John Kauffman & Charles Carroll) The listbox object is very popular since it makes data entry easy. They just pull down a list. 1 2 3 <html><head> <TITLE>FormListBox.asp</TITLE> </head><body bgcolor="#FFFFFF"> 4 5 6 7 8 9 10 11 12 13 <form action="FormListBoxRespond.asp" method="post"> <SELECT NAME="state"> <OPTION SELECTED VALUE="md">Maryland</OPTION> <OPTION value="dc">District of Columbia</OPTION> <OPTION value="va">Virginia</OPTION> <OPTION value="whoknows">Somewhere Else!</OPTION> </SELECT> <input type=submit value="Choose State"> </form> </body></html> The responder looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html><head> <TITLE>formlistboxrespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <%mystate = request.form("state") Select Case ucase(mystate) case "DC" response.write "DC meeting on 15th" case "MD" response.write "MD meeting on 20th" case else response.write "No meetings for you to attend!" End Select%> </body> </html> http://www.learnASP.com/learn/case.asp by Charles M. Carroll Page 58 Select Case (by John Kauffman & Charles Carroll) Using IF-THEN can be cumbersome, prone to programmer errors and slower to execute. A more efficient construct is SELECT CASE. It is optimized for testing one variable against many conditions. 1 2 3 4 5 6 7 8 9 <html><head> <TITLE>case.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="caserespond.asp" method="get"> Your First Name<INPUT NAME="FirstName" MaxLength=20><p> Your Last Name<INPUT NAME="LastName" MaxLength=20><p> <INPUT TYPE=submit><p><INPUT TYPE=reset> </form> </body></html> Here is the select case that will determine what the form input means. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html><head> <TITLE>caserespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% fname=request.querystring("Firstname") lname=request.querystring("Lastname") %> Nice to Meet You <%=fname%> <%=lname%><p> <%If fname="" then%> Sorry we are not on a first name basis...<p> <%end if select case lcase(lname) case "washington","adams" response.write "The first president has same last name<p>" case "jefferson" response.write "The third president has same last name<p>" 17 18 19 20 case "lincoln" response.write "The sixteenth president has same last name<p>" end select%> </body></html> http://www.learnASP.com/learn/case2.asp by Charles M. Carroll Page 59 Select Case Part2 (by John Kauffman & Charles Carroll) Using IF-THEN can be cumbersome, prone to programmer errors and slower to execute. A more efficient construct is SELECT CASE. It is optimized for testing one variable against many conditions. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html><head> <TITLE>case2.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="case2respond.asp" method="get"> Your First Name<INPUT NAME="FirstName" MaxLength=20><p> Your Last Name<INPUT NAME="LastName" MaxLength=20><p> Your Title <INPUT TYPE="Radio" name="Title" VALUE="employee">Entry Level <INPUT TYPE="Radio" name="Title" VALUE="temp" CHECKED>Temporary Employee <INPUT TYPE="Radio" name="Title" VALUE="manager">Management Candidate <INPUT TYPE="Radio" name="Title" VALUE="executive">Executive <INPUT TYPE="Radio" name="Title" VALUE="vice-prez">The Vice President of... <INPUT TYPE="Radio" name="Title" VALUE="CEO">The Boss<p> <INPUT TYPE=submit><p> </form> </body></html> Here is the select case that will determine what the form input means. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <html><head> <TITLE>case2respond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% fname=request.querystring("Firstname") lname=request.querystring("Lastname") title=request.querystring("title") response.write "Nice to Hire You " & fname & " " & lname & "<p>" Select Case lcase(Title) case "employee","temp" response.write("The washroom is in the hall") case "manager","executive" response.write("Here is your key to the Executive washroom") case "ceo", "vice-prez" response.write("The maid will attend to your private washroom") End Select%> </body></html> http://www.learnASP.com/learn/if.asp by Charles M. Carroll Page 60 IF statement (by John Kauffman & Charles Carroll) Very often you must determine what to do next based on user input. This is one of the roles of the IF statement. First we make a form that will ask a user for their first name and last name. 1 <html><head> 2 3 4 5 6 7 8 <TITLE>if.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="ifrespond.asp" method=get> Your First Name<INPUT NAME="FirstName" MaxLength=20><p> Your Last Name<INPUT NAME="LastName" MaxLength=20><p> <INPUT TYPE=submit><p><INPUT TYPE=reset> </form></body></html> Now we make a asp file that examines their first name and last name after the form is submitted. 1 2 3 4 5 6 7 8 9 10 11 <html><head> <TITLE>ifrespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <%fname=request.querystring("Firstname") lname=request.querystring("Lastname") If fname="George" and lname="Washington" then%> Hi.<p>You must be the first president! <%else%> Hi!<p>Nice to Meet You <%end if%> </body></html> http://www.learnASP.com/learn/if2.asp by Charles M. Carroll Page 61 IF statement Part2 (by John Kauffman & Charles Carroll) Very often you must determine what to do next based on user input. This is one of the roles of the IF statement. First we make a form that will ask a user for their first name and last name. 1 2 3 4 5 6 7 8 <html><head> <TITLE>if2.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="if2respond.asp" method=get> Your First Name<INPUT NAME="FirstName" MaxLength=20><p> Your Last Name<INPUT NAME="LastName" MaxLength=20><p> <INPUT TYPE=submit><p><INPUT TYPE=reset> </form></body></html> Now we make a asp file that examines their first name and last name after the form is submitted. As contrasted to the previous example this time we are checking multiple conditions utilizing elseif and we are dealing with entries no matter whether they were typed in upper or lower case. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <html><head> <TITLE>if2respond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% fname=lcase(request.querystring("Firstname")) lname=lcase(request.querystring("Lastname")) If fname="george" and lname="washington" then%> Hi.<p>You must be the first president! <%elseIf fname="ronald" and lname="reagan" then%> Hi.<p>You must be the actor president! <%elseIf fname="jimmy" and lname="carter" then%> Hi.<p>You must be the peanut farmer president! <%elseIf fname="naoko" or fname="charles" then%> Hi.<p>Your name reminds me of someone<p> but I am not sure who! <%else%> Hi!<p>Nice to Meet You <%end if%> </body></html> http://www.learnASP.com/learn/if3.asp by Charles M. Carroll Page 62 IF statement Part3 (by John Kauffman & Charles Carroll) Very often you must determine what to do next based on user input. This is one of the roles of the IF statement. First we make a form that will ask a user for their first name, last name and salary. 1 2 3 4 5 6 7 8 9 <html><head> <TITLE>if3.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="if3respond.asp" method=get> Your First Name<INPUT NAME="FirstName" MaxLength=20><p> Your Last Name<INPUT NAME="LastName" MaxLength=20><p> Your Salary <INPUT NAME="Salary" MaxLength=7><p> <INPUT TYPE=submit><p><INPUT TYPE=reset> </form></body></html> This example shows how IF can deal with ranges and use various other boolean operators. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <html><head> <TITLE>if3respond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% fname=request.querystring("Firstname") lname=request.querystring("Lastname") salary=request.querystring("Salary") response.write "Nice to Meet You " & fname & " " & lname & "<p>" if salary>100000 then%> Would you like to loan me some money?<p> <% sstaxMarginal=15 else SSTaxMarginal=15 end if If salary>6700 and salary<30000 then SSTaxMarginal=0%> Would you like me to loan you some money?<p> <%end if If salary<6700 then SSTaxMarginal=0 end if %> By the way your marginal tax rate is <%=sstaxmarginal%> </body></html> http://www.learnASP.com/learn/if4.asp by Charles M. Carroll Page 63 If Then Part4 (by John Kauffman & Charles Carroll) Very often you must determine what to do next based on user input. This is one of the roles of the IF statement. First we make a form that will ask a user for their first name, last name and salary. 1 2 3 4 5 6 <html><head> <TITLE>if4.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="if4respond.asp" method=get> Your First Name<INPUT NAME="FirstName" MaxLength=20><p> Your Last Name<INPUT NAME="LastName" MaxLength=20><p> 7 8 9 Your Salary <INPUT NAME="Salary" MaxLength=7><p> <INPUT TYPE=submit><p><INPUT TYPE=reset> </form></body></html> This example shows how IF can deal with ranges but this example illustrates the critical factor of ordering. If you were to re-arrange these IFs they would not accurately report your salary grade. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <html><head> <TITLE>if4respond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <%fname=request.querystring("Firstname") lname=request.querystring("Lastname") salary=request.querystring("Salary") response.write "Nice to Meet You " & fname & " " & lname & "<p>" if salary>80000 then salarygrade=4 end if if salary <=80000 then salarygrade=3 end if If salary <=60000 then salarygrade=2 end if if salary <=40000 then salarygrade=1 end if response.write ("Your Salary is $" & salary) response.write (", your Grade is " & salarygrade & ".<p>") %> </body></html> http://www.learnASP.com/learn/formforeach.asp by Charles M. Carroll Page 64 Forms - For Each/Iteration by Charles Carroll Forms with many elements may be easier to process if a FOR EACH construct is used to loop through every value submitted from the source form. In this example, there are many checkboxes and instead of many IF statements we replace them with one FOR EACH loop. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <html><head> <TITLE>monthlyForm.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form action="monthlyFormRespond.asp" method="post"> <p>CheckBox Form Example</p> <p><b>Check Off The Days You Worked</b></p> <% my_month=request.querystring("whichmonth") ' response.write my_month & "<br>" if my_month="" then my_date=now() else my_month=month("1/" & (request.querystring("whichmonth")) & "/1999") my_date=dateserial(year(now()),my_month,1) end if 'response.write my_date & "<br>" If my_month=12 then my_day=1 my_month=1 my_year=my_year+1 else my_day=1 24 25 26 27 28 29 30 31 32 33 34 35 36 my_month=month(my_date)+1 my_year=year(my_date) end if for counter=1 to lastdayofmonth%> <input TYPE="checkbox" NAME="workingday<%=counter%>">day <%=counter%> Worked?<br> <%next%> <input type="submit" value="Submit Days Worked"> </form> </body></html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html><head> <TITLE>monthlyFormRespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% daysworked=0 for each whatever in request.form thisvalue=request.form(whatever) If thisvalue="on" then daysworked=daysworked+1 end if next response.write "Thanks for working <b>" & daysworked & "</b> days" %> </body></html> lastdayofmonth=day(DateSerial(Year(my_Date), my_Month,0)) 'response.write lastdayofmonth & "<br>" http://www.learnASP.com/learn/formsendmail.asp by Charles M. Carroll Page 65 Forms - Sending Results via EMail by Charles Carroll Sometimes it makes sense to just email all the form results to someone. But the "mailto:" method used by many Web developers is not the best way as it has the following serious limitations: ● forms sent this way are difficult to read by a human recipient because of the encoded way it is sent ● Not all browsers support mailto (Netscape does, several IE versions before 4.0 do not, many browsers do not) ● The user may have a faulty email configuration that keeps the browser from sending the mail Server side mail has none of these limitations. Here is a form that will be sent to you provided you change the variables at the top of the code. This example uses ASPmail, which is available for a modest price at: http://www.serverobjects.com Here is a sample form that will be sent via email: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <% ' change these to reflect where form should go fromName="Whoever" fromAddress="somestudent@activeserverpages.com" toName="Charles M. Carroll" toAddress="cc@thebestweb.com" subject="form send mail tutorial" relay="relay.datareturn.com" %> <html><head> <title>FormToBeMailed.asp</title> </head><body bgcolor="#FFFFFF"> <form action="FormToBeMailedrespond.asp" method="GET"> Fill Out This Form For Us:<p> First Name -> <input NAME="NameFirst" size="10"><br> Last Name -> <input NAME="NameLast" size="10"><br> Country -> <input NAME="Country" value="USA" size="10"><br> 18 19 20 21 22 23 24 25 26 27 28 29 30 31 State -> <input NAME="State" MaxLength="2" size="2"><br> email copy to -> <input NAME="emailcopy" MaxLength="20" size="20"><br> <input type="submit"><input type="reset"> <% ' do not touch these lines. Needed to send mail! %> <input type="hidden" name="mail-from" value="<%=fromName%>"> <input type="hidden" name="mail-fromAddress" value="<%=fromAddress%>"> <input type="hidden" name="mail-to" value="<%=ToName%>"> <input type="hidden" name="mail-toaddress" value="<%=toaddress%>"> <input type="hidden" name="mail-subject" value="<%=subject%>"> <input type="hidden" name="mail-relay" value="<%=relay%>"> </form> </body></html> Here is the generic form responder that can be used with this or any form: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <html><head> <title>serverobjectsmailrespond.asp</title> </head><body bgcolor="#FFFFFF"> <% ' ASPMail(tm) from http://www.serverobjects.com ' is not part of ASP per se, ' but a excellent third party component my_from=request("mail-fromName") my_fromAddress=request("mail-fromaddress") my_to=request("mail-toName") my_toAddress=request("mail-toaddress") my_subject=request("mail-subject") my_relay=request("mail-relay") Set Mailer = Server.CreateObject("SMTPsvg.Mailer") Mailer.RemoteHost = my_relay Mailer.FromName = my_from Mailer.FromAddress = my_fromAddress Mailer.AddRecipient my_to, my_toaddress Mailer.Subject = my_subject for each whatever in request.querystring If instr(whatever,"mail-")=0 then Mailer.BodyText = whatever & "=" & vbcrlf Mailer.BodyText = request.querystring(whatever) & vbcrlf & vbcrlf end if next for each whatever in request.form If instr(whatever,"mail-")=0 then Mailer.BodyText = whatever & "=" & vbcrlf Mailer.BodyText = request.form(whatever) & vbcrlf & vbcrlf end if next my_emailcopy=request("emailcopy") If my_emailcopy="" then else Mailer.AddRecipient "form filler",my_emailcopy end if If Mailer.SendMail then Msg = "mail sent sucessfully!" Else Msg = "mail was not sent sucessfully" End If response.write Msg %> 51 </body></html> http://www.learnASP.com/learn/cookiesform.asp by Charles M. Carroll Page 66 Cookies Storing (by Juan Llibre & Charles Carroll) The script below demonstrates how to populate a form from a cookie. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <% response.buffer=true %> <html><head> <TITLE>cookiesform.asp</TITLE>& <body bgcolor="#FFFFFF"> <% ln=Request.Cookies("thatperson")("lastname") fn=Request.Cookies("thatperson")("firstname") st=Request.Cookies("thatperson")("state") %> <Form action = "cookiesformrespond.asp"> Form with Cookies<p> Please enter your First Name<p> <Input NAME="NameFirst" size ="40" value=<%=fn%>> <p> Please enter your Last Name<p> <Input NAME="NameLast" size ="40" value=<%=ln%>> <p> Please enter your State abbreviation<p> <Input NAME="State" MaxLength="2" value=<%=st%>> <Input type=submit></form> </body></html> http://www.learnASP.com/learn/cookiesformrespond.asp by Charles M. Carroll Page 67 Cookies Displaying (by Juan Llibre & Charles Carroll) The script below demonstrates how to store a cookie that was passed in from the form. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <%response.buffer=true%> <html><head> <TITLE>cookiesformrespond.asp</TITLE>& <body bgcolor="#FFFFFF"> <% l=request.querystring("namelast") f=request.querystring("namefirst") st=request.querystring("state") cookypath="/learn/test" cookydomain=".www.activeserverpages.com" cookydie=date+365 Response.Cookies("thatperson")("lastname") = l Response.Cookies("thatperson")("firstname") = f Response.Cookies("thatperson")("state") = st Response.Cookies("thatperson").Expires = cookydie Response.Cookies("thatperson").Domain = cookydomain Response.Cookies("thatperson").Path = cookypath response.write Request.Cookies("thatperson")("lastname") & "<p>" response.write Request.Cookies("thatperson")("firstname") & "<p>" 20 21 22 response.write Request.Cookies("thatperson")("state") & "<p>" %> </body></html> http://www.learnASP.com/learn/cookiesforget.asp by Charles M. Carroll Page 68 Cookies Deleting (by Juan Llibre & Charles Carroll) The script below demonstrates how to remove a cookie. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <%response.buffer=true%> <html><head> <TITLE>cookiesformforget.asp</TITLE>& <body bgcolor="#FFFFFF"> <% cookiepath="/learn/test" cookiedomain=".www.activeserverpages.com" cookiesdie=date-365 Response.Cookies("thatperson").Expires = cookiesdie Response.Cookies("thatperson").Domain = cookiesdomain Response.Cookies("thatperson").Path = cookiespath response.write "I will not remember you" %> </body></html> http://www.learnASP.com/learn/cookiesub.asp by Charles M. Carroll Page 69 Cookies Simplified (by Paul Rigor of http://www.mysticpc.com) A reader of the site submits this simplified cookie reading, writing and deleting by automatically determing the correct domain and path info without you having to specify it for each cookie. 1 2 3 4 5 6 7 8 9 10 11 12 <%response.buffer=true%> <!--#include file="cookielib.asp"--> <html><head> <TITLE>cookiesub.asp</TITLE>& <body bgcolor="#FFFFFF"> <% Call AddCookie("Person", "Firstname", "Robert", 365) Call AddCookie("Person", "LastName", "Forward", 365) response.write GetCookie("person","firstname") response.write GetCookie("person","lastname") %> </body></html> Here is the library code that does most of the work: 1 2 3 4 5 6 7 8 9 10 <% '======================================================================= ' CookieLib.asp by Paul Rigor (http://www.mysticpc.com) ' online at http://www.activeserverpages.com/learn/cookiesub.asp ' copyright 1998 by Paul Rigor ' ' application("cookiedomain") and application("cookiepath") can be ' set if firewall precludes accurate server variable ' ' AddCookie(Cname, CKey, CValue, CExpDays) 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 ' Example: Call AddCookie("MyCookie", "Cost", "$1.00", 100) ' ' KillCookie(Cname,CKey) ' Example: Call KillCookie("MyCookie", "Cost") ' ' GetCookie(Cname,Ckey) ' Example: Call GetCookie("MyCookie", "Cost") ' ' Cname = Cookie Name: Required, for cookie name ' Ckey = Cookie Key: Optional(empty sting), use if cookie should be a dictionary ' Cvalue = Cookie Value: Required, what the cookie should be set to. ' CExpDays = Cookie Expiration: number of days cookie is valid, default 365 Function AddCookie(Cname, CKey, CValue, CExpDays) If Cname = "" Then Exit Function End If If IsNumeric(CExpDays) = False Then CExpDays = 0 If CExpDays < 1 Then CExpDays = 365 If CValue = "" Then CValue = " " If CKey <> "" Then Response.Cookies(Cname)(CKey) = CValue Else Response.Cookies(Cname) = CValue End If Response.Cookies(CName).Expires = Date + CExpDays Response.Cookies(CName).Domain = GetCookieDomain() Response.Cookies(CName).Path = GetCookiePath() End Function Function KillCookie(Cname,CKey) If CKey <> "" Then Call AddCookie(Cname, Ckey, "", 0) Else Response.Cookies(Cname).Expires = Date - 365 Response.Cookies(CName).Domain = GetCookieDomain() Response.Cookies(CName).Path = GetCookiePath() End If End Function Function GetCookie(Cname, Ckey) If CKey <> "" Then GetCookie = Request.Cookies(Cname)(Ckey) Else GetCookie = Request.Cookies(Cname) End If End Function Function GetCookieDomain() If Application("CookieDomain") <> "" Then GetCookieDomain = Application("CookieDomain") Else GetCookieDomain = Request.ServerVariables("SERVER_NAME") End If End Function Function GetCookiePath() If Application("CookiePath") <> "" Then GetCookiePath = Application("CookiePath") Else TmpPath = Request.ServerVariables("SCRIPT_NAME") TmpPath = Split(TmpPath, "/") For PathArryCnt = 0 to Ubound(TmpPath) - 1 GetCookiePath = GetCookiePath & TmpPath(PathArryCnt) & "/" 78 79 80 81 82 Next If GetCookiePath = "/" Then GetCookiePath = "" End If End Function %> http://www.learnASP.com/learn/statemanagement.asp by Charles M. Carroll Page 70 State Management Introduction (stateintro.asp) - Page 71 What are ASP Sessions? (sessionswhat.asp) - Page 72 State Methods: Pros and Cons (stateproscons.asp) - Page 73 Pass Data w/Hidden Fields (hidden.asp) - Page 74 Pass Data w/Cookies (cookies.asp) - Page 75 Pass Data w/Session Vars (statesessions.asp) - Page 76 Pass Data w/ID tied to database (statedb.asp) - Page 77 State Managment Resources (statemore.asp) - Page 78 [aspStateManagement] Listserver (aspstatemanagement.asp) - Page 79 http://www.learnASP.com/learn/stateintro.asp by Charles M. Carroll Page 71 State Management Intro by Charles Carroll Not written yet. http://www.learnASP.com/learn/sessionswhat.asp by Charles M. Carroll Page 72 What are Sessions? Sessions are a very convenient ASP feature. When someone visits a web page on your site, ASP calls that a "session" and immediately can differentiate that user from all other users at a site. Anything stored in that user's session can be retrieved and manipulated from that page and the next pages they visit, and the data will be tied to that user. Session data is generally attached to one user. When a user visits their first page of your site, that page and every page they visit is collectively called a session. Any data attached stored in that session object is private to the pages that user is visiting. The code to store data in a session variable is simple. Here we will allow a user to flip a coin, i.e. flipcoin.asp and count their successes: 1 2 3 4 5 6 7 8 9 10 11 12 <% response.write "Coin Tossed!<br>" randomize randomnum=int(rnd*2)+1 IF randomnum=1 THEN session("heads")=session("heads")+1 ELSE session("tails")=session("tails")+1 END IF response.write "Heads= " & session("heads") & "<br>" response.write "Tails= " & session("tails") & "<br>" %> Even though there are many people at the site they all have different scores for their "heads" and "tails" count. They each has a session and it co-ordinates and differentiates their values. A much more practical example could protect access to a page based on a session variable that indicated their security level determined once upon login, see: http://www.learnasp.com/learn/security.asp Some basic things should be noted: ● Session data is stored on the server, not in cookies. No user could examine the session cookie and determine the contents of any session variables. ● A cookie is used to co-ordinate the user's session ID. Once again the cookie contains no data (just the session ID). This means if the user accepts no cookies, you can't use sessions as described here. ● If you absolutely need sessions without client cookies, installing an ISAPI filter named "Cookie Munger" will solve your problem, but at a performance penalty. Cookie Munger by Microsoft (FREE) Cookies are a necessity to maintain ASP session objects. Even though the session objects are physically maintained on the server the essential ID that identifies a user session is kept in a cookie. This ISAPI filter can only be applied globally but if applied, it actually rewrites any pages sent back to the user so that any URLs in the page will pass back user session info without any cookies involved. Basically (at a performance penalty) it transforms every page sent to the client to encode the session ID as part of the URLs on the page. So conceptually if you send a page back to the users with 20 URLs each URL gets a session ID "munged"/intermixed in so that when they click on the URL you have enough info to Identify them without writing a cookie to their machine. [../trash/msfree.asp] %> http://www.learnASP.com/learn/stateproscons.asp by Charles M. Carroll Page 73 State Management Intro by Charles Carroll Not written yet. http://www.learnASP.com/learn/hidden.asp by Charles M. Carroll Page 74 Passing Data with Hidden Fields by Charles Carroll This page demonstrates how to have several pages that are forms yet after all pages are filled out the final form has access to all inputs without session variables. surveypage1.asp asks the user the first questions: 1 2 3 4 5 6 7 8 9 10 <html><head> <TITLE>surveypage1.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <form action="surveypage2.asp" method="post"> First Name<br> <input type="text" name="first" size="20"><br> Last Name<br> 11 12 13 14 15 <input type="text" name="last" size="20"> <p> <input type="submit" value="Next Question ->"></p> </form> </body></html> surveypage2.asp asks the user the next questions: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html><head> <TITLE>surveypage2.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <form action="surveypage3.asp" method="post"> <% first=request.form("first") last=request.form("last") %> Hair Color<br> <input type="text" name="haircolor" size="20"><br> Favorite Color<br> <input type="text" name="favoritecolor" size="20"> <p> <input type="hidden" name="first" value="<%=first%>"> <input type="hidden" name="last" value="<%=last%>"> <input type="submit" value="Next Question ->"></p> </form> </body></html> surveypage3.asp asks the user yet some more questions: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <html><head> <TITLE>surveypage2.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% first=request.form("first") last=request.form("last") haircolor=request.form("haircolor") favoritecolor=request.form("favoritecolor") %> <form action="surveypage3respond.asp" method="post"> Street Address<br> <input type="text" name="street" size="20"> <br> City<br> <input type="text" name="city" size="20"><br> State<br> <input type="text" name="state" size="20"> <br> Zip<br> <input type="text" name="zip" size="20"> <br> <input <input <input <input type="hidden" type="hidden" type="hidden" type="hidden" name="first" value="<%=first%>"> name="last" value="<%=last%>"> name="haircolor" value="<%=haircolor%>"> name="favoritecolor" value="<%=favoritecolor%>"> <input type="submit" value="Final Step ->"> </form> </body></html> surveypage3respond.asp gathers all the answers and responds: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <html><head> <TITLE>surveypage3respond.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% first=request.form("first") last=request.form("last") haircolor=request.form("haircolor") favoritecolor=request.form("favoritecolor") street=request.form("street") city=request.form("city") state=request.form("state") zip=request.form("zip") %> Thanks for all your information<br> We are happy to meet you <%=first%> <%=last%><br> We know your hair color is <%=haircolor%><br> and your favorite color is <%=favoritecolor%><br> and we will ship all items to<br> <%=first%> <%=last%><br> <%=street%><br> <%=city%> <%=state%> <%=zip%> </body></html> http://www.learnASP.com/learn/cookies.asp by Charles M. Carroll Page 75 Passing Data with Cookies by Charles Carroll This page demonstrates how to have several pages that are forms yet after all pages are filled out the final form has access to all inputs even after the browser is opened and closed. The browser must accept cookies. surveypage1c.asp asks the user the first questions: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <html><head> <TITLE>surveypage1.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% first=request.cookies("prefs")("first") last=request.cookies("prefs")("last") %> <form action="surveypage2c.asp" method="post"> First Name<br> <input type="text" name="first" size="20" value="<%=first%>"><br> Last Name<br> <input type="text" name="last" size="20" value="<%=last%>"> <p> <input type="submit" value="Next Question ->"></p> </form> <% For Each cookie in Response.Cookies Response.Cookies(cookie).Expires = now()+365 Next %> </body></html> surveypage2c.asp asks the user the next questions: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <%response.buffer=true%> <html><head> <TITLE>surveypage2c.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% first=request("first") last=request("last") haircolor=request.cookies("prefs")("haircolor") favoritecolor=request.cookies("prefs")("favoritecolor") %> <form action="surveypage3c.asp" method="post"> Hair Color<br> <input type="text" name="haircolor" size="20" value="<%=haircolor%>"><br> Favorite Color<br> <input type="text" name="favoritecolor" size="20" value="<%=favoritecolor%>"> <p> <% response.cookies("prefs")("first")=first response.cookies("prefs")("last")=last For Each cookie in Response.Cookies Response.Cookies(cookie).Expires = now()+365 Next %> <input type="submit" value="Next Question ->"></p> </form> </body></html> surveypage3c.asp asks the user yet some more questions: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <%response.buffer=true%> <html><head> <TITLE>surveypage3c.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% haircolor=request("haircolor") favoritecolor=request("favoritecolor") street=request.cookies("prefs")("street") city=request.cookies("prefs")("city") state=request.cookies("prefs")("state") zip=request.cookies("prefs")("zip") %> <form action="surveypage3crespond.asp" method="post"> Street Address<br> <input type="text" name="street" size="20" value="<%=street%>"> <br> City<br> <input type="text" name="city" size="20" value="<%=city%>"><br> State<br> <input type="text" name="state" size="20" value="<%=state%>"> <br> Zip<br> <input type="text" name="zip" size="20" value="<%=zip%>"> <br> <% response.cookies("prefs")("haircolor")=haircolor response.cookies("prefs")("favoritecolor")=favoritecolor For Each cookie in Response.Cookies Response.Cookies(cookie).Expires = now()+365 Next %> 37 38 39 <input type="submit" value="Final Step ->"> </form> </body></html> surveypage3crespond.asp gathers all the answers and responds: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <%response.buffer=true%> <html><head> <TITLE>surveypage3respond.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% first=request.cookies("prefs")("first") last=request.cookies("prefs")("last") haircolor=request.cookies("prefs")("haircolor") favoritecolor=request.cookies("prefs")("favoritecolor") street=request("street") city=request("city") state=request("state") zip=request("zip") %> Thanks for all your information<br> We are happy to meet you <%=first%> <%=last%><br> We know your hair color is <%=haircolor%><br> and your favorite color is <%=favoritecolor%><br> and we will ship all items to<br> <%=first%> <%=last%><br> <%=street%><br> <%=city%> <%=state%> <%=zip%> <% response.cookies("prefs")("street")=street response.cookies("prefs")("city")=city response.cookies("prefs")("state")=state response.cookies("prefs")("zip")=zip For Each cookie in Response.Cookies Response.Cookies(cookie).Expires = now()+365 Next %> </body></html> http://www.learnASP.com/learn/statesessions.asp by Charles M. Carroll Page 76 State Management Intro by Charles Carroll Not written yet. http://www.learnASP.com/learn/statedb.asp by Charles M. Carroll Page 77 State Management Intro by Charles Carroll Not written yet. http://www.learnASP.com/learn/statemore.asp by Charles M. Carroll Page 78 Global.asa, Sessions, Custom Stats Resources The global.asa, application and sesion variables are certainly a more complex and controversial subject than most ASP topics. Other sites and my site has a lot to say on this: Everything you wanted to know about global.asa but were afraid to ask @ http://www.4guysfromrolla.com/webtech/113098-1.shtml The lowdown on Global.asa, session vars and app. vars http://www.asp101.com/resources/apps_sessions_gasa.asp An example of home-brewed stats: http://www.asp101.com/resources/active_users.asp Steve Smith's Stats examples: http://www.aspalliance.com/stevesmith/samples/whosoncode.asp http://www.aspalliance.com/stevesmith/samples/sitestats.asp http://www.learnASP.com/learn/aspstatemanagement.asp by Charles M. Carroll Page 79 aspstatemanagement Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/aspstatemanagement.asp Send Listserver Questions to aspstatemanagement@ls.asplists.com Related Links Global.asa Basics @ http://www.learnasp.com/learn/global.asp FREE Dictionary Component that is session/app safe @ http://www.caprockconsulting.com/comsoftware.htm Hidden Fields to Pass Data between pages @ http://www.learnasp.com/learn/hidden.asp Global.asa Sclability problems @ http://www.learnasp.com/learn/globalproblems.asp Sessions: what are they? @ http://www.learnasp.com/learn/sessionswhat.asp 4 Ways to Pass data from page to page @ http://www.4guysfromrolla.com/webtech/041399-1.shtml Cache application level Recordset @ http://msdn.microsoft.com/workshop/server/feature/cache.asp http://www.learnASP.com/learn/database.asp by Charles M. Carroll Page 80 DB: Troubleshooting Part 1 (dbtroubles.asp) - Page 81 DB: Troubleshooting Part 2 (dbtroubles2.asp) - Page 82 DB: Displaying Table w/Simple Code (dbsimple.asp) - Page 83 DB: Table Displayed Generically (dbtable.asp) - Page 84 DB: List Box Displayed Generically (dblist.asp) - Page 85 Database to ListBox Online Resources (dblistmore.asp) - Page 86 DB: Generic DB by Eli Robillard (genericdb.asp) - Page 87 DB: More ways To Display Tables (dbtablemore.asp) - Page 88 DB: DSNLess Connections (dbopen.asp) - Page 89 DB: DSN Setup #1 by Rob Martinson (dsn1.asp) - Page 90 DB: DSN Setup #2 by Rob Martinson (dsn2.asp) - Page 91 DB: DSN Setup #3 by Rob Martinson (dsn3.asp) - Page 92 DB: DSN Setup #4 by Rob Martinson (dsn4.asp) - Page 93 DB: DSN Setup #5 by Rob Martinson (dsn5.asp) - Page 94 DB: DSN Setup #6 by Rob Martinson (dsn6.asp) - Page 95 DB: Full Cycle #1 Show/Edit/Update (dbfull1.asp) - Page 96 DB: Full Cycle #2 Show/Edit/Update (dbfull2.asp) - Page 97 DB: Full Cycle #3 Show/Edit/Update (dbfull3.asp) - Page 98 DB: Converting a DB to a Comma-Delimited file (dbconvert.asp) - Page 99 DB: Deleting a Record w/SQL (dbSQLdelete.asp) - Page 100 DB: Access vs. SQL Server (accessSQLserver.asp) - Page 101 DB: Oracle and ASP (oracle.asp) - Page 102 http://www.learnASP.com/learn/dbtroubles.asp by Charles M. Carroll Page 81 Databases Troubleshooting Resources When your database code does not work, we actually manage a listserv you can write to send in your code and have your colleagues from around the world on the listserv help you fix it. People having trouble with ASP code communicating with a specific database should try their questions on one of these lists: Access DB2 AS400 Dbase Fox/Visual FoxPro Informix SQLserver 6.5 SQLserver 7.x Oracle Setup/Can't Connect! Oracle Paradox Reports/Printing (Crystal, PDF, etc.) RDS (Remote Data Services) SQL: Joins, complex queries, shaping Sybase http://www.learnASP.com/learn/dbtroubles2.asp by Charles M. Carroll Page 82 Databases Troubleshooting Resources Part 2 The web is replete with many database resources that we think people should read up on. User entered ' in Field @ http://www.learnasp.com/learn/FAQdbSinglequote.asp Error: Operation must use an updatable query @ http://www.learnasp.com/learn/FAQdbUpdate.asp Query with LIKE Results in Error @ http://www.learnasp.com/learn/FAQdbLIKE.asp Retrieveing Memo Field Results in Error @ http://www.learnasp.com/learn/FAQdbMEMO.asp Syntax Error in SQL statement @ http://www.learnasp.com/learn/FAQdbSQLSyntax.asp Build a Drilldown DB screen @ http://www.4guysfromrolla.com/webtech/070799-1.shtml Generic DB Free Display Tool @ http://www.ofifc.org/Eli/asp/ http://www.learnASP.com/learn/dbsimple.asp by Charles M. Carroll Page 83 Database -- Simple Table Display by Charles Carroll This page demonstrates the capabilities how to display a table from a SQL statement. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <html><head> <TITLE>dbsimple.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% ' this code opens the database myDSN="DSN=Student;uid=student;pwd=magic" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN ' this code retrieves the data mySQL="select * from publishers where state='NY'" set rstemp=conntemp.execute(mySQL) ' this code detects if data is empty If rstemp.eof then response.write "No records matched<br>" response.write mySQL & "<br>So cannot make table..." connection.close set connection=nothing response.end end if %> <table border=1> <% ' This code puts fieldnames into column headings response.write "<tr>" 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 for each whatever in rstemp.fields response.write "<td><B>" & whatever.name & "</B></TD>" next response.write "</tr>" ' Now lets grab all the records DO UNTIL rstemp.eof ' put fields into variables pubid=rstemp("pubid") name=rstemp("name") company_name=rstemp("company_name") address=rstemp("address") city=rstemp("city") state=rstemp("state") zip=rstemp("zip") telephone=rstemp("telephone") fax=rstemp("fax") comments=rstemp("comments") ' write the fields to browser cellstart="<td align=""top"">" response.write "<tr>" response.write cellstart & pubid & "</td>" response.write cellstart & name & "</td>" response.write cellstart & company_name & "</td>" response.write cellstart & address & "</td>" response.write cellstart & city & "</td>" response.write cellstart & state & "</td>" response.write cellstart & zip & "</td>" response.write cellstart & telephone & "</td>" response.write cellstart & fax & "</td>" response.write cellstart & comments & "</td>" response.write "</tr>" rstemp.movenext LOOP %> </table> <% ' Now close and dispose of resources rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </body></html> http://www.learnASP.com/learn/dbtable.asp by Charles M. Carroll Page 84 Display Table on Web Page by Charles Carroll This page demonstrates the capabilities how to display a table from a SQL statement. It illustrates not only how to display the table, but also how to detect that no records were returned from a query, and how to detect null and blank values in the data. 1 2 3 4 5 6 7 <html><head> <TITLE>dbtable.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% ' ASP program that displays a database in table form myDSN="DSN=Student;uid=student;pwd=magic" 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 mySQL="select * from publishers where state='NY'" showblank=" " shownull="-null-" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(mySQL) If rstemp.eof then response.write "No records matched<br>" response.write mySQL & "<br>So cannot make table..." conntemp.close set conntemp=nothing response.end end if %> <table border=1><tr> <% 'Put Headings On The Table of Field Names for each whatever in rstemp.fields%> <td><b><%=whatever.name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records DO UNTIL rstemp.eof %> <tr> <% for each whatever in rstemp.fields thisfield=whatever.value if isnull(thisfield) then thisfield=shownull end if if trim(thisfield)="" then thisfield=showblank end if%> <td valign=top><%=thisfield%></td> <% next %> </tr> <%rstemp.movenext LOOP%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </body></html> http://www.learnASP.com/learn/dblist.asp by Charles M. Carroll Page 85 HTML List Box from Column This page demonstrates the capabilities how to display a list box from a SQL statement. This is the simplest possible example. The script to display a list from a database is: 1 2 3 4 5 6 <html><head> <TITLE>dblist.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select author from authors where AU_ID<100" 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ' displays a database field as a listbox set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(mySQL) if rstemp.eof then response.write "no data for<br>" response.write mySQL conntemp.close set conntemp=nothing response.end end if %> <form action="dblistrespond.asp" method="post"> <Select name="authorname"> <% ' Now lets grab all the data do until rstemp.eof %> <option> <%=RStemp(0)%> </option> <% rstemp.movenext loop rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> <input type="submit" value="Choose Author"> </Select></form> </body></html> The form responder dblistrespond.asp is: 1 <html><head> 2 <TITLE>dblistrespond.asp</TITLE> 3 </head><body bgcolor="#FFFFFF"> 4 <% 5 my_author=request.form("authorname") 6 %> 7 You choose <%=my_author%><br>Thanks!<br> 8 </body></html> http://www.learnASP.com/learn/dblistmore.asp by Charles M. Carroll Page 86 Database Listbox Resources There are actually many approaches to creating listboxes from databases demonstrated on this site and other sites: http://www.learnasp.com/learn/subdblist.asp http://www.learnasp.com/learn/subdblistbest.asp http://www.siteexperts.com/tips/elements/ts25/page1.asp http://www.niblack.com/kbase/listbox_create_x.asp http://www.niblack.com/kbase/listboxmgmt_x.asp http://www.niblack.com/kbase/listbox_x.asp And many people like dynamic list boxes where one listbox choice affects the values available in the other listbox: http://www.learnasp.com/learn/listdynamic.asp http://www.learnasp.com/learn/listdynamicdb.asp http://www.learnasp.com/learn/listdynamicmore.asp There are also some alternative approaches to building alternative, gimicky listboxes that are helpful: http://www.learnasp.com/learn/listdual.asp http://www.siteexperts.com/tips/elements/ts22/page1.asp http://n2.neoshop.com/ http://www.learnASP.com/learn/genericdb.asp by Charles M. Carroll Page 87 Generic Database Display Made Easy When you want a quick easy generic database display, go on over to: http://www.ofifc.org/Eli/asp/homepage.asp Here Eli Robillard has done a lot of work for you. You modify one ASP file that specifies your database and query specs and his ASP scripts magically do the rest. Here is an example where I make a pubs.asp designed to plug into his ASP scripts. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <% ' Generic interface to the Northwinds Employee table. Session("dbGenericPath") = "/learn/test/genericdb/" Session("dbExitPage") = "http://www.activeserverpages.com" Session("dbTitle") = "Pubs" Session("dbType") = "SQL" Session("dbConn") = "DSN=student;uid=student;pwd=magic" Session("dbRs") = "Publishers" Session("dbKey") = 1 Session("dbOrder") = 2 Session("dbRecsPerPage") = 10 Session("dbFooter") = 1 Session("dbDispList") = "011101000000100010" Session("dbDispView") = "111111111111111111" Session("dbDispEdit") = "011111111111111111" Session("dbSearchFields") = "011100010010001000" Session("dbDefault6") = Date() Session("dbCombo11") = "LIST, ??, Unknown, CA, Canada, US, United States, DE, Denmark" Session("dbDefault17") = 10 Session("dbWhere") = "" Session("dbDebug") = 1 Session("dbCanEdit") = 1 Session("dbCanAdd") = 1 Session("dbCanDelete") = 1 Session("dbConfirmDelete") = 1 Session("dbViewPage") = Request.ServerVariables("PATH_INFO") Response.Redirect Session("dbGenericPath") & "GenericList.asp" %> There is even a listserve supporting this great FREE script collection. It is not a general database troubleshooting list, instead only questions concerning these wonderful scripts are allowed. aspgenericdb Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/genericdb.asp Send Listserver Questions to aspgenericdb@ls.asplists.com Related Links Generic DB Main Page @ http://www.ofifc.org/Eli/asp/ http://www.learnASP.com/learn/dbtablemore.asp by Charles M. Carroll Page 88 Display database table on Web Page Many Approaches by Charles Carroll There are many ways to display a table on a web page. So many that we feel that a brief description of the variations and some URLs will help. A good programmer knows many ways to tackle the same problem! Paging through arbitrary groups of records (i.e. record __ of __ ) at: /learn/dbtablepaged.asp Displaying a table without using a DSN, i.e. a DSNLess connection at: /learn/dbopen.asp Use the faster Getrows function to retrieve a recordset into an array: /learn/dbtablegetrows.asp Use the lightning fast Getstring function to retrieve a recordset into a string: /learn/dbtablegetstring.asp Using a very nice generic routine from Eli Robillard at: /learn/genericdb.asp Use an excellent 3rd party component (ASPDB): http://www.learnasp.com/learn/aspdb.asp Displaying a Table with many records as quick as possible is documented in depth at: /learn/speedtables.asp /learn/speedtablesall.asp Displaying a Table using simple subroutines & includes at: /learn/subdbtable.asp Displaying tables, listboxes and other arbitrary HTML at: /learn/subreusable.asp http://www.learnASP.com/learn/dbopen.asp by Charles M. Carroll Page 89 DSNless connection by Charles Carroll Any ASP script that needs to connect to a database must open it on the server first.There are several ways: a system DSN which must be setup on the server, see: /learn/dsn1.asp for detailed instructions or http://www.aspalliance.com/components/database.asp for components that automate this task. This is the fastest way since all the information resides on the server and need only be validated when the DSN is setup. a File DSN which is not recommended for high concurrency situations since all users would be limited speedwise to how fast the ASII file that holds the DSN could be accessed. a DSNless connection which requires no server setup, just a carefully constructed connection string as demonstrated below. This is a necessary evil if a DSN is not available and not as fast as a system DSN since the server must validate the connection information each attempt. The trouble with a File DSN is that every connection.open must: ● open, read, close an ASCII file (which may cause concurrency problems on a busy site) ● present the data anew to the provider/driver since the ASCII file may have changed since last connection. The designers of ASP have seen File DSNs fail on big busy sites because of reason a) so discourage them. System DSNs thay rely on registry keys in memory are much faster. Microsoft has a knowledge base article at: http://support.microsoft.com/support/kb/articles/q193/3/32.asp which explains all the DSNless connection strings. DSNless connections demand that that you know the name of the file (i.e. file based databases like Access, Paradox, FoxPro, etc.) or the address of the data server (SQLserver for example). Armed with appropriate information you could open a data source without a DSN! Note that you must know the actual filepath on the server, i.e. nwind.mdb is not good enough it needs to be "C:\thatserver\account17\nwind.mdb". Fortunately the server.mappath function can turn a filename into the proper fully qualified filename with path on the server. Here is a sample nwind.asp connecting to an access database named "nwind.mdb" in the root of the web site with a DSNless connection. 1 <HTML><HEAD> 2 <TITLE>nwind.asp</TITLE> 3 <body bgcolor="#FFFFFF"></HEAD> 4 <% 5 accessdb="nwind.mdb" 6 myDSN="DRIVER={Microsoft Access Driver (*.mdb)};" 7 myDSN=myDSN & "DBQ=" & server.mappath(accessdb) 8 mySQL="select * from customers" 9 10 call query2table(mySQL,myDSN) 11 %> 12 <!--#include virtual="/learn/test/lib_dbtable.asp"--> 13 </BODY> 14 </HTML> 15 Here is a sample sqldsn.asp connecting to an access database named "nwind.mdb" in the root of the web site with a DSNless connection. 1 <HTML><HEAD> 2 <TITLE>sqldsn.asp</TITLE> 3 <body bgcolor="#FFFFFF"></HEAD> 4 <% 5 accessdb="nwind.mdb" 6 myDSN="DSN=student;uid=student;pwd=magic" 7 mySQL="select * from publishers where state='NY'" 8 9 call query2table(mySQL,myDSN) 10 %> 11 <!--#include virtual="/learn/test/lib_dbtable.asp"--> 12 </BODY> 13 </HTML> 14 Here is a sample sqldsnless.asp connecting to an access database named "nwind.mdb" in the root of the web site with a DSNless connection. 1 <HTML><HEAD> 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <TITLE>sqlDSNless.asp</TITLE> <body bgcolor="#FFFFFF"></HEAD> <% mydb="PROVIDER=MSDASQL;DRIVER={SQL Server};" mydb=mydb & "SERVER=sql2.datareturn.com;DATABASE=;" mydb=mydb & "UID=student;PWD=magic;" mySQL="select * from publishers where state='NY'" call query2table(mySQL,mydb) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY> </HTML> The Include file lib_dbtable.asp looks like this: 1 <% 2 sub query2table(inputquery, inputDSN) 3 dim conntemp, rstemp 4 set conntemp=server.createobject("adodb.connection") 5 conntemp.open inputDSN 6 set rstemp=conntemp.execute(inputquery) 7 howmanyfields=rstemp.fields.count -1%> 8 <table border=1><tr> 9 <% 'Put Headings On The Table of Field Names 10 for i=0 to howmanyfields %> 11 <td><b><%=rstemp(i).name%></B></TD> 12 <% next %> 13 </tr> 14 <% ' Now lets grab all the records 15 do while not rstemp.eof %> 16 <tr> 17 <% for i = 0 to howmanyfields 18 thisvalue=rstemp(i) 19 If isnull(thisvalue) then 20 thisvalue=" " 21 end if%> 22 <td valign=top><%=thisvalue%></td> 23 <% next %> 24 </tr> 25 <%rstemp.movenext 26 loop%> 27 </table> 28 <% 29 rstemp.close 30 set rstemp=nothing 31 conntemp.close 32 set conntemp=nothing 33 end sub%> http://www.learnASP.com/learn/dsn1.asp by Charles M. Carroll Page 90 Setting up a system DSN on Windows 95/NT ©1998, 1999 by Rob Martinson rob.martinson@directionsmag.com The easiest way to begin learning ASP, is to install Microsoft PWS, and develop locally. To do this, you must also setup a DSN (Data Source Name) on your machine, if you wish to use any of ASP's database access abilities. This tutorial is meant to walk you through the process of setting up a system DSN on your Windows machine. The first step, after you have PWS installed, is to open your control panel and select the 32bit ODBC Data Source Administrator icon (shown below). http://www.learnASP.com/learn/dsn2.asp by Charles M. Carroll Page 91 Setting up a system DSN Part 2 ©1998, 1999 by Rob Martinson rob.martinson@directionsmag.com Setting up a system DSN on Windows 95/NT Once the ODBC Data Source Administrator window is open, select the System DSN tab at the top (I'm doing a system DSN because that's what I generally use. See here for more info on the differences between system and file DSNs). This will bring you to a list of System Data Sources that are setup on your machine. It may vary from the list above. From this point, click the "Add" button and move on to the next screen. http://www.learnASP.com/learn/dsn3.asp by Charles M. Carroll Page 92 Setting up a system DSN Part 3 ©1998, 1999 by Rob Martinson rob.martinson@directionsmag.com I began my development using Microsoft Access as I already had a copy, and it would help me to learn SQL syntax that would later be of use in larger projects. For this reason, I will choose the MS Access Database driver from this screen. If you are setting up a DSN for a different database format, select the associated driver here. http://www.learnASP.com/learn/dsn4.asp by Charles M. Carroll Page 93 Setting up a system DSN Part 4 ©1998, 1999 by Rob Martinson rob.martinson@directionsmag.com Here we will name our DSN. For web development, I generally setup a single DSN (depending on the project of course) and then just modify the database as needed. Because of that, I almost always name mine "tables.dsn". Name it whatever you like, just remember the name. From this screen you are also able to setup various options with your DSN including default authorization (click advanced), page timeout, database location, etc. For now we will leave the default options and move on to the next screen by choosing "Ok". http://www.learnASP.com/learn/dsn5.asp by Charles M. Carroll Page 94 Setting up a system DSN Part 5 ©1998, 1999 by Rob Martinson rob.martinson@directionsmag.com If we have not specified the location of the database associated with our DSN on the previous screen, we will be prompted to do so now. This is self explanatory I believe. http://www.learnASP.com/learn/dsn6.asp by Charles M. Carroll Page 95 Setting up a system DSN ©1998, 1999 by Rob Martinson rob.martinson@directionsmag.com That's it! Your System DSN is setup and running. All you need to do now is get ASP to use it (which is pretty easy). http://www.learnASP.com/learn/dbfull1.asp by Charles M. Carroll Page 96 Database Full Cycle #1 -Display Table, Edit Record, Update Record dbfull1.asp merely displays a table like we have in other examples, except every row of the table has a hyperlink to dbfull2.asp and passes the ID to that script in a variable called whichID. After the user edits that information and presses submit, dbfull3.asp is called. It's task is to gather all input fields and construct a SQL update statement. Here is a source printout of the script that displays the table and "starts the ball rolling": 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <% response.buffer=true Response.ExpiresAbsolute = Now() - 1 Response.AddHeader "Cache-Control", "private" %> <html><head> <title>authorshow.asp</title> <meta http-equiv="pragma" content="no-cache"> </head><body bgcolor="#FFFFFF"> <% myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select * from authors where AU_ID<100 order by author" IDfield="AU_ID" scriptresponder="authoredit.asp" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(mySQL) howmanyfields=rstemp.fields.count -1 %> <table border="1"> 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <tr> <td valign="top">---</td> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name %></b></td> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr><td valign="top"> <%my_link=scriptresponder & "?which=" & rstemp(idfield)%> <a HREF="<%=my_link%>">Edit</a></td> <% for i = 0 to howmanyfields%> <td valign="top"><%=rstemp(i)%></td> <% next %> </tr> <% rstemp.movenext loop rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </table></body></html> http://www.learnASP.com/learn/dbfull2.asp by Charles M. Carroll Page 97 Database Full Cycle #2 -Display Table, Edit Record, Update Record Here is the script that shows one record based on being linked to from the table 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <html><head> <title>authoredit.asp</title> </head><body bgcolor="#FFFFFF"> <% ' My ASP program that given an AU_ID, allows editing a record myDSN="DSN=Student;uid=student;pwd=magic" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN form_ID=request.querystring("which") sqltemp="select * from authors " sqltemp=sqltemp & " where AU_ID=" & form_id set rstemp=conntemp.execute(sqltemp) form_auID=rstemp("AU_ID") form_author=rstemp("Author") form_year_born=rstemp("Year_Born") rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> <body> 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <form name="myauthor" action="authoreditrespond.asp" method="POST"> <input type="hidden" name="id" value="<%=form_auid%>"> <p>Author ID: <%=form_auid%></p> <p> Author Name: <input type="TEXT" name="name" value="<%=form_author%>"></p> <p> Year Born: <input type="TEXT" name="year" value="<%=form_year_born%>"></p> <p> <input type="SUBMIT"> </p> </form> </body> http://www.learnASP.com/learn/dbfull3.asp by Charles M. Carroll Page 98 Database Full Cycle #3 -Display Table, Edit Record, Update Record Here is the script that updates one record after the submit button is pushed on the previous script. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <HTML><HEAD> <TITLE>authoreditrespond.asp</TITLE> <body bgcolor="#FFFFFF"></HEAD> <% on error resume next form_name=request.form("name") form_year=request.form("year") form_ID=request.form("ID") Set Conn = Server.CreateObject("ADODB.Connection") conn.open "DSN=Student;uid=student;pwd=magic" ' change apostrophe to double apostrophe form_name=Replace(form_name, "'", "''") SQLstmt SQLStmt SQLstmt SQLStmt = = = = "UPDATE SQLstmt SQLstmt SQLStmt authors SET " & "Author='" & form_name & "'," & "year_born=" & form_year & " WHERE AU_ID=" & form_id Set RS = Conn.Execute(SQLStmt) If err.number>0 then response.write "VBScript Errors Occured:" & "<P>" response.write "Error Number=" & err.number & "<P>" response.write "Error Descr.=" & err.description & "<P>" response.write "Help Context=" & err.helpcontext & "<P>" response.write "Help Path=" & err.helppath & "<P>" response.write "Native Error=" & err.nativeerror & "<P>" response.write "Source=" & err.source & "<P>" response.write "SQLState=" & err.sqlstate & "<P>" end if IF conn.errors.count> 0 then response.write "Database Errors Occured" & "<P>" response.write SQLstmt & "<P>" for counter= 0 to conn.errors.count response.write "Error #" & conn.errors(counter).number & "<P>" response.write "Error desc. -> " & conn.errors(counter).description & "<P>" 40 41 42 43 44 45 46 47 48 49 50 51 52 next else response.write "<B>Everything Went Fine. Record is updated now!</b>" response.write "<br>" & SQLstmt end if rs.close set rs=nothing Conn.Close set conn=nothing %> </BODY> </HTML> http://www.learnASP.com/learn/dbconvert.asp by Charles M. Carroll Page 99 Database -- Convert to Comma-Delimited File by Charles Carroll This page demonstrates the capabilities how to write an ASCII comma-delimited file from a SQL statement. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <html><head> <TITLE>dbconvert.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% whichname="/upload/tests/authors.txt" myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select * from authors where au_id<100" showblank="" shownull="<null>" linestart=chr(34) lineend=chr(34) delimiter=chr(34) & "," & chr(34) delimitersub="" whichFN=server.mappath(whichname) Set fstemp = server.CreateObject("Scripting.FileSystemObject") Set filetemp = fstemp.CreateTextFile(whichFN, true) ' true = file can be over-written if it exists ' false = file CANNOT be over-written if it exists set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(mySQL) ' this code detects if data is empty If rstemp.eof then response.write "No data to convert for SQL statement<br>" response.write mySQL & "<br>" connection.close set connection=nothing response.end end if DO UNTIL rstemp.eof thisline=linestart for each whatever in rstemp.fields thisfield=whatever.value if isnull(thisfield) then thisfield=shownull end if if trim(thisfield)="" then 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 thisfield=showblank end if thisfield=replace(thisfield,delimiter,delimitersub) thisline=thisline & thisfield & delimiter next tempLen=len(thisline) tempLenDelim=len(delimiter) thisline=mid(thisline,1,tempLEN-tempLenDelim) & lineend filetemp.WriteLine(thisline) ' response.write thisline & "<br>" rstemp.movenext LOOP filetemp.Close set filetemp=nothing set fstemp=nothing rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing If err.number=0 then response.write "File was converted sucessfully!<br>" response.write "Converted file is at <a href='" response.write whichname & "'>" & whichname & "</a>" else response.write "VBScript Errors Occured!<br>" response.write "Error Number=#<b>" & err.number & "</b><br>" response.write "Error Desc. =<b>" & err.description & "</b><br>" response.write "Help Path =<b>" & err.helppath & "</b><br>" response.write "Native Error=<b>" & err.nativeerror & "</b><br>" response.write "Error Source =<b>" & err.source & "</b><br>" response.write "SQL State=#<b>" & err.sqlstate & "</b><br>" end if %> </body></html> http://www.learnASP.com/learn/dbSQLdelete.asp by Charles M. Carroll Page 100 Database -- Delete Record with SQL statement SQL statements can be used to delete data as well. Here is a script that will add a bunch of records with the AU_ID of 200: 1 <TITLE>dbaddmany.asp</TITLE> 2 <body bgcolor="#FFFFFF"> 3 <HTML> 4 <!--#include file="lib_errors.asp"--> 5 <% 6 on error resume next 7 myDSN = "DSN=Student;uid=student;pwd=magic" 8 mySQL = "INSERT INTO authors (AU_ID,author,year_born) " 9 mySQL = mySQL & "VALUES (200,'Charles M. Carroll',1964)" 10 11 Set Conn = Server.CreateObject("ADODB.Connection") 12 conn.open myDSN 13 14 for counter=1 to 200 15 thistask="Task #" & counter & "<br>" 16 17 18 19 20 21 22 23 24 25 response.write thistask Conn.Execute(mySQL) Call ErrorVBScriptReport(thistask) Call ErrorADOReport(mySQL,conn) next Conn.Close set conn=nothing %> </BODY> </HTML> Now here is a script that will delete all the records the above script added: 1 <TITLE>dbdeletemany.asp</TITLE> 2 <body bgcolor="#FFFFFF"> 3 <HTML> 4 <!--#include file="lib_errors.asp"--> 5 <% 6 on error resume next 7 myDSN = "DSN=Student;uid=student;pwd=magic" 8 mySQL = "DELETE FROM authors WHERE au_id=200" 9 10 Set Conn = Server.CreateObject("ADODB.Connection") 11 conn.open myDSN 12 13 Conn.Execute mySQL,howmany 14 response.write "The statement " & mySQL & "<b> deleted " & howmany & " records</b><br>" 15 Call ErrorVBScriptReport("Deleting...") 16 Call ErrorADOReport(mySQL,conn) 17 18 Conn.Close 19 set conn=nothing 20 %> 21 </BODY> 22 </HTML> http://www.learnASP.com/learn/accessSQLserver.asp by Charles M. Carroll Page 101 Access vs. SQL Server by Charles Carroll DRAFT -- NOT FINISHED Microsoft Access is a database package that works well on one machine and with some careful coding can function well under a light network and concurrency load. It is rare that a website presents a "light" concurrency load. http://www.learnASP.com/learn/oracle.asp by Charles M. Carroll Page 102 Oracle and Active Server Pages by Charles Carroll DRAFT -- NOT FINISHED Oracle data can be easily incorporated into ASP scripts though all the details can become complex. If you have integrating Oracle with your ASP sites, we run a listserv/newgroup called [aspOracle] where that is the only topic allowed you can join to get help from your colleagues worldwide. aspOracle Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/oracle.asp Send Listserver Questions to aspOracle@ls.asplists.com Related Links The Hottest Set of Oracle sites/listserves @ http://www.doug.org How to Connect/Troubleshoot Oracle Connection by Bret H. Grade @ /learn/FAQOracleconnect.asp How to Call Oracle Stored Procedure by Surya Rao @ /learn/FAQOraclestoredproc.asp Returning Recordsets via ADO by John Kilgo @ /asplists/asporacleFAQ4.asp Know any good Oracle Books? @ /asplists/asporacleFAQ2.asp http://www.learnASP.com/learn/aspdb.asp by Charles M. Carroll Page 103 ASPDB - A Component That Simplifies Databases (aspdb.asp) - Page 1 ASP DB Sample #1: Displaying Data (aspdb1.asp) - Page 2 ASP DB Sample #2: Editing, Adding Data (aspdb2.asp) - Page 3 http://www.learnASP.com/learn/aspdb1.asp by Charles M. Carroll Page 104 ASPDB: Databases with No Work! This page demonstrates the capabilities how the third party component ASPDB from http://www.aspdb.com makes database programming simple. Here we will show the code to display a gorgeous table of the customers database just be starting the component and setting a few properties: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <% response.buffer=true %> <HTML> <Head><Title>ASPdb1.asp</Title></Head> <% Set MyDb = Server.CreateObject("ASPdb.Pro") MyDb.dbUnit = 1000 MyDb.dbMDB=Server.MapPath("/learn/test/nwind.mdb") MyDb.dbColor = "11" MyDb.dbGridTableTag = "border=3" MyDb.dbMode= "Grid" MyDb.dbSQL = "Select * FROM Customers" MyDb.dbNavigationItem = "top, bottom, next, prev, filter" MyDb.ASPdbPro set myDB=nothing %> </BODY> </HTML> Now we will display publishers: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <% response.buffer=true %> <HTML> <Head><Title>ASPdb1.asp</Title></Head> <% Set MyDb = Server.CreateObject("ASPdb.Pro") MyDb.dbUnit = 1000 MyDb.dbMDB=Server.MapPath("/learn/test/biblio.mdb") MyDb.dbColor = "11" MyDb.dbGridTableTag = "border=3" MyDb.dbMode= "Grid" MyDb.dbSQL = "Select * FROM Publishers" MyDb.dbNavigationItem = "top, bottom, next, prev, filter" MyDb.ASPdbPro set myDB=nothing %> </BODY> </HTML> http://www.learnASP.com/learn/aspdb2.asp by Charles M. Carroll Page 105 ASPDB: Database Editing with A Million Options! This page demonstrates the capabilities how the third party component ASPDB from http://www.aspdb.com makes database programming powerful and removes you worrying about how and rather what it looks like. Here we will show the code to display a gorgeous editable table by starting the component and setting dozens of properties: 1 <% response.buffer=true %> 2 <HTML> 3 <HEAD><title>ASPdb2.asp</title> 4 </HEAD> 5 <FONT FACE="Arial,Helvetica" Color=Black Size=3> 6 7 <% 8 Set MyDb = Server.CreateObject("AspDB.Pro") 9 MyDb.dbUnit = 1101 10 B=Request("ASPdbBut_1101") ' this is NOT case sensitive 11 L9=Left(B,9) 12 UL9=UCASE(L9) 13 L12=Left(B,12) 14 UL12=UCASE(L12) 15 if UL9 <> "ASPDBEDIT" then 16 response.write("<CENTER><B>Welcome to the ASP-db™ PRO Test Page.</B><P>") 17 response.write("For the benefit of others, please do not delete all of the records. Thanks.<P>") 18 response.write("<B>Click on the [Add New] button to see how ASP-db can put default values in certain fields.") 19 20 response.write("<HR WIDTH=66% Size=1>") 21 end if 22 23 ' Is it an ASPdbEditUpdate? If so, show user the Name in the "current" record. 24 THISNAME = Session("ASPdb_1101_Name") 25 26 if UL12 = "ASPDBEDITUPD" then 27 MSG1 = "<CENTER><FONT SIZE=4 COLOR=Black><B>" 28 MSG1 = MSG1 + "Please Update the Information for: " + THISNAME 29 MSG1 = MSG1 + "</B></FONT><P>" 30 response.write(MSG1) 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 end if if UL12 = "ASPDBEDITDEL" then MSG1 = "<CENTER><FONT SIZE=4 COLOR=red><B>" MSG1 = MSG1 + "You are about to DELETE all of the Information for: " + THISNAME MSG1 = MSG1 + "</B></FONT><P>" response.write(MSG1) end if if UL12 = "ASPDBEDITEDI" then MSG1 = "<CENTER><FONT SIZE=4 COLOR=red><B>" MSG1 = MSG1 + "You are about to EDIT all of the Information for: " + THISNAME MSG1 = MSG1 + "</B></FONT><P>" response.write(MSG1) end if Mydb.dbMDB = Server.MapPath("Pro-Demo.mdb") ' Has fields: Name, Age, Salary, NetWorth MyDb.DBColor = "11,auto,white" MyDb.dbGridTableTag = "border=3 cellspacing=3 cellpadding=3" MyDb.dbFormTableTag = "border=3 cellspacing=3 cellpadding=3" MyDb.dbGridDisplayFlds = "Name,Age,Salary,NetWorth" MyDb.DbMode = "dual-horiz" MyDb.dbGridInc = 10 MyDb.dbButtonAnchor=false MyDb.dbExportFlds = "Name" Mydb.dbFilterDropFlds = "Name,,People,Name,,,,,Distinct; Salary,,People,Salary,,,,,Distinct" Mydb.dbEditDropFlds = "Salary,,,9250.75/11000/15000/21000/25000/32000/38000/44000/75000" Mydb.dbEditFlds = "Name,Age[10],Salary,NetWorth[123]" ' added Name 07-27-98 MyDb.dbEditUpdateROFlds = "Name" ' ***** NEW!!!!! ***** EP = "TableName=People,BookMarkFlds=0,TableTag=Border=2" EP = EP & ",RecordScope=single,CriteriaSize=4x25,EditSemiColon=;" Mydb.dbEditParams = EP MyDb.dbSQL = "Select * from People" MyDb.dbMagicCell = _ "1, align=Left , <font size=2 face=ARIAL color=black><I><B>#1#</B></I>;" & _ "2, align=Center, <font size=2 face=ARIAL color=black> #2#;" & _ "3, align=right , <font size=2 face=ARIAL color=black>format=[currency];" & _ "4, align=right , <font size=2 face=ARIAL color=black>format=[currency];" MyDb.dbImageDir="images/" Mydb.dbNavigation="both" Mydb.dbNavigationItem="Next, Prev, Gridrow, Filter, add, update, edit, delete" Mydb.dbNavigationIcon="std" MyDb.aspDBPro set mydb=nothing %> </HTML> http://www.learnASP.com/learn/ado.asp by Charles M. Carroll Page 106 Getstring to display database table (dbtablegetstring.asp) - Page 107 Getrows to display database table (dbtablegetrows.asp) - Page 108 Disconnected Recordsets, Display Table (dbtabledisconnected.asp) - Page 109 ADO: Limiting Number of Records (dbmaxrecs.asp) - Page 110 ADO: Paging Records (dbtablepaged.asp) - Page 111 ADO: Count Records in Query (dbcount.asp) - Page 112 ADO: Cursor Types by Phil Paxton (adocursortypes.asp) - Page 113 ADO: Input Form (dbnewrec.asp) - Page 114 ADO: Input Form, added w/SQL (dbnewSQL.asp) - Page 115 ADO: Input Form, Added w/ADO .addnew (dbnewADO.asp) - Page 116 ADO: GetString function (dbgetstring.asp) - Page 117 ADO: Tables within Databases (dbtablelists.asp) - Page 118 ADO: Schemas to access table lists (dbschemas.asp) - Page 119 ADO: Schemas to access All Data (dbschemasall.asp) - Page 120 ADO: SQL Mistakes (dbtroubleshoot2.asp) - Page 121 ADO: Show Table,1 param (db1parm.asp) - Page 122 ADO: Update/edit Record (dbupdate.asp) - Page 123 http://www.learnASP.com/learn/dbtablegetstring.asp by Charles M. Carroll Page 107 Table Database Display via GetString by Charles Carroll This page demonstrates the capabilities how to display a table from a SQL statement a very fast and scaleable way using a recordset method called GetString. GetString essentially asks the backend database to build a huge string instead of moving the data as rows and columns. It allows very limited specifications, basically what string to place between each column and row and how to display nulls. Notice the total absence of the traditional EOF loop. Does this approach matter for small data sets for example 9 rows x 2 columns of data? YES!!!!!!!! My site has SQLserver scripts that run like lightning. I once needed to fill a 9 item listbox from Access and got 90 sec script timeouts with movenext. Getstring never timed out. So in a real production situation it makes weak databases feasible and of course reduces the load on more industrial back-ends so maybe the SQLserver doesn't need as many indexes or RAM upgrades. This example does require ADO 2.0 or greater which can be downloaded from: http://www.microsoft.com/data If you are unsure which ADO version your server has now this code will allow you to identify the version on your server: http://www.learnasp.com/learn/versioncheck.asp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <TITLE>dbtablegetstring.asp</TITLE> <body bgcolor="#FFFFFF"> <% whichDSN="DSN=Student;uid=student;pwd=magic" mySQL="select * from publishers where state='NY'" ' ASP program that displays a database in table form set conntemp=server.createobject("adodb.connection") conntemp.open whichDSN set rstemp=conntemp.execute(mySQL) If rstemp.eof then response.write "No records matched<br>" response.write mySQL & "<br>So cannot make table..." rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 response.end end if response.write "<table border='1'><tr>" 'Put Headings On The Table of Field Names for each whatever in rstemp.fields response.write "<td><b>" & whatever.name & "</B></TD>" next response.write "</tr><tr><td>" response.write rstemp.getstring(,, "</td><td>", "</td></tr><TR><TD>", "-null-") response.write "</td></tr></table>" rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </body></html> http://www.learnASP.com/learn/dbtablegetrows.asp by Charles M. Carroll Page 108 Table Database Display via GetRows by Charles Carroll This page demonstrates the capabilities how to display a table from a SQL statement a very fast and scaleable way using a recordset method called GetRows. GetRows that move many records and fields into a memory array. Once in the array it is accessed very fast. If you read the code closely you will notice it can free up the recordset and connection object earlier than the traditional loop thus freeing up those resources for other scripts. In terms of why this is faster, read: http://www.learnasp.com/advice/whygetrows.asp to see an in-depth explanation. http://www.learnasp.com/learn/dbtablegetstring.asp rips getrows to shreds speed-wise as the backend transfers one big string instead of a complex array structure but formatting is SOOOOO limited (unless you know Regexps like the back of your hand....) Since this code relies heavily on arrays you may want to read up on them at: 1 2 3 4 5 6 7 8 9 10 11 ● http://www.learnasp.com/learn/arrays.asp ● http://www.learnasp.com/learn/arrays2.asp ● http://www.learnasp.com/learn/arrays3.asp <%@enablesessionstate=false%> <%response.buffer=true%> <html><head> <TITLE>dbtablegetrows.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% ' displays a database in table form via GetRows myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select * from publishers where state='NY'" showblank=" " 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 shownull="-null-" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(mySQL) If rstemp.eof then response.write "No records matched<br>" response.write mySQL & "<br>So cannot make table..." rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing response.end end if response.write "<table border='1'><tr>" 'Put Headings On The Table of Field Names for each whatever in rstemp.fields response.write "<td><b>" & whatever.name & "</B></TD>" next response.write "</tr>" ' Now lets grab all the records alldata=rstemp.getrows rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing numcols=ubound(alldata,1) numrows=ubound(alldata,2) FOR rowcounter= 0 TO numrows FOR colcounter=0 to numcols thisfield=alldata(colcounter,rowcounter) if isnull(thisfield) then thisfield=shownull end if if trim(thisfield)="" then thisfield=showblank end if response.write "<td valign=top>" response.write thisfield response.write "</td>" NEXT response.write "</tr>" & vbcrlf NEXT response.write "</table>" %> </body></html> http://www.learnASP.com/learn/dbtabledisconnected.asp by Charles M. Carroll Page 109 Display Table and Disconnect Recordset by Charles Carroll This page demonstrates the capabilities how to display a table from a SQL statement. It illustrates not only how to display the table, but also how to detect that no records were returned from a query, and how to detect null and blank values in the data. This example disconnects the recordset so that the data will not be drawn from up to the millisecond database data BUT retrieval will be much faster. 1 2 3 <%@enablesessionstate=false%> <%response.buffer=true%> <!--#include virtual="/adovbs.inc"--> 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <html><head> <TITLE>dbtabledisconnected.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% ' displays a database in table form via GetRows myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select * from publishers where state='NY'" showblank=" " shownull="-null-" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN ' to disconnect a recordset it must be created explicitly set rstemp=server.createobject("adodb.recordset") rstemp.cursorlocation=aduseclient rstemp.open mySQL,conntemp ' this line below disconnects the recordset set rstemp.activeconnection=nothing If rstemp.eof then response.write "No records matched<br>" response.write mySQL & "<br>So cannot make table..." rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing response.end end if response.write "<table border='1'><tr>" 'Put Headings On The Table of Field Names for each whatever in rstemp.fields response.write "<td><b>" & whatever.name & "</B></TD>" next response.write "</tr>" DO UNTIL rstemp.eof response.write "<tr>" for each whatever in rstemp.fields thisfield=whatever.value if isnull(thisfield) then thisfield=shownull end if if trim(thisfield)="" then thisfield=showblank end if response.write "<td valign=top>" & thisfield & "</td>" next response.write "</tr>" rstemp.movenext LOOP response.write "</table>" %> </body></html> http://www.learnASP.com/learn/dbmaxrecs.asp by Charles M. Carroll Page 110 ADO Techniques -- The .maxrecords property This page demonstrates the capabilities how to display a table from a SQL statement but limit the output to a specific number of records. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <html><head> <TITLE>dbmaxrecs.asp</TITLE> </head><body bgcolor="#FFFFFF"> <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <% set rstemp=Server.CreateObject("adodb.Recordset") rstemp.maxrecords=15 connectme="DSN=Student;uid=student;pwd=magic" rstemp.open "select * from titles", _ connectme,adopenstatic ' table display howmanyfields=rstemp.fields.count -1 %> <table border=1><tr> <% for i=0 to howmanyfields %> <td><b><%=rstemp(i).name %></B></TD> <% next %> </tr> <% do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields%> <td valign=top><% = rstemp.fields(i).value %> </td> <% next %> </tr> <% rstemp.movenext loop rstemp.close set rstemp=nothing %> </table></body></html> http://www.learnASP.com/learn/dbtablepaged.asp by Charles M. Carroll Page 111 Paged Table Displays by Charles Carroll & Jeff Emrich This page demonstrates how to retrieve a recordset divided up into pages, and to only select data from a specified page. It does not in any way store a recordset or connection in memory when the page is not accessed unlike many solutions you will read about. The ADO properties that make this magic possible are .AbsolutePage, .PageCount and .PageSize. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <html><head> <TITLE>dbtablepaged.asp</TITLE> </head><body bgcolor="#FFFFFF"> <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <% connectme="DSN=Student;uid=student;pwd=magic" sqltemp="select * from publishers" ' ' ' ' ' ' ' ' ' ' ' ' Troubleshooting TIP: if you use this code and get an error, for example: ADODB.Recordset error 800a0cb3 The operation requested by the application is not supported by the provider. You may have a driver that is out of date, see: http://www.learnasp.com/learn/connectioninfo.asp for code that will identify what your driver version is this script works with Access, SQLserver and Oracle 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 ' with up-to-date drivers If aduseclient="" THEN ref="http://www.learnasp.com/adovbs.inc" response.write "You forgot to include:<br>" response.write "/adovbs.inc<br>" response.write "Get the file from <a href='" & ref & "'>" & ref & "<br>" response.end END IF mypage=request("whichpage") If mypage="" then mypage=1 end if mypagesize=request("pagesize") If mypagesize="" then mypagesize=10 end if mySQL=request("SQLquery") IF mySQL="" THEN mySQL=SQLtemp END IF set rstemp=Server.CreateObject("ADODB.Recordset") rstemp.cursorlocation=aduseclient rstemp.cachesize=5 rstemp.open mySQL,connectme rstemp.movefirst rstemp.pagesize=mypagesize maxpages=cint(rstemp.pagecount) maxrecs=cint(rstemp.pagesize) rstemp.absolutepage=mypage howmanyrecs=0 howmanyfields=rstemp.fields.count -1 response.write "Page " & mypage & " of " & maxpages & "<br>" response.write "<table border='1'><tr>" 'Put Headings On The Table of Field Names FOR i=0 to howmanyfields response.write "<td><b>" & rstemp(i).name & "</b></td>" NEXT response.write "</tr>" ' Now loop through the data DO UNTIL rstemp.eof OR howmanyrecs>=maxrecs response.write "<tr>" FOR i = 0 to howmanyfields fieldvalue=rstemp(i) If isnull(fieldvalue) THEN fieldvalue="n/a" END IF If trim(fieldvalue)="" THEN fieldvalue=" " END IF response.write "<td valign='top'>" response.write fieldvalue response.write "</td>" next response.write "</tr>" rstemp.movenext howmanyrecs=howmanyrecs+1 LOOP response.write "</table><p>" ' close, destroy rstemp.close set rstemp=nothing 88 89 ' Now make the page _ of _ hyperlinks 90 Call PageNavBar 91 92 sub PageNavBar() 93 ' Thanks to Jeff Emrich <jeff.emrich@datafuse.com> 94 pad="" 95 scriptname=request.servervariables("script_name") 96 response.write "<table rows='1' cols='1' width='97%'><tr>" 97 response.write "<td>" 98 response.write "<font size='2' color='black' face='Verdana, Arial,Helvetica, sans-serif'>" 99 if (mypage mod 10) = 0 then 100 counterstart = mypage - 9 101 else 102 counterstart = mypage - (mypage mod 10) + 1 103 end if 104 counterend = counterstart + 9 105 if counterend > maxpages then counterend = maxpages 106 if counterstart <> 1 then 107 ref="<a href='" & scriptname 108 ref=ref & "?whichpage=" & 1 109 ref=ref & "&pagesize=" & mypagesize 110 ref=ref & "&sqlQuery=" & server.URLencode(mySQL) 111 ref=ref & "'>First</a> : " 112 Response.Write ref 113 114 115 ref="<a href='" & scriptname 116 ref=ref & "?whichpage=" & (counterstart - 1) 117 ref=ref & "&pagesize=" & mypagesize 118 ref=ref & "&sqlQuery=" & server.URLencode(mySQL) 119 ref=ref & "'>Previous</a> " 120 Response.Write ref 121 end if 122 Response.Write "[" 123 for counter=counterstart to counterend 124 If counter>=10 then 125 pad="" 126 end if 127 if cstr(counter) <> mypage then 128 ref="<a href='" & scriptname 129 ref=ref & "?whichpage=" & counter 130 ref=ref & "&pagesize=" & mypagesize 131 ref=ref & "&sqlQuery=" & server.URLencode(mySQL) 132 ref=ref & "'>" & pad & counter & "</a>" 133 else 134 ref="<b>" & pad & counter & "</b>" 135 end if 136 response.write ref 137 if counter <> counterend then response.write " " 138 next 139 Response.Write "]" 140 if counterend <> maxpages then 141 ref=" <a href='" & scriptname 142 ref=ref & "?whichpage=" & (counterend + 1) 143 ref=ref & "&pagesize=" & mypagesize 144 ref=ref & "&sqlQuery=" & server.URLencode(mySQL) 145 ref=ref & "'>Next</a>" 146 Response.Write ref 147 148 149 ref=" : <a href='" & scriptname 150 ref=ref & "?whichpage=" & maxpages 151 ref=ref & "&pagesize=" & mypagesize 152 ref=ref & "&sqlQuery=" & server.URLencode(mySQL) 153 ref=ref & "'>Last</a>" 154 155 156 157 158 159 160 161 Response.Write ref end if response.write "<br></font>" response.write "</td>" response.write "</table>" end sub %> </body></html> http://www.learnASP.com/learn/dbcount.asp by Charles M. Carroll Page 112 Count Query/Table Records by Juan Llibre, Charles Carroll This script counts the records in a database. Many people who attempt to use the .recordcount property have the value -1 returned to them. In a nutshell, -1 means "I don't know how many records this query/table contains". It happens since the default cursortype is AdOpenforwardonly (see below for explanation of all cursor types). The critical part here is having a cursor that supports it and including adovbs.inc to define the cursor types. The file adovbs.inc can be obtained from http://www.learnasp.com/adovbs.inc Adopenstatic cursor The data is dead. If you retrieve a million records for example at 9:00am and it takes 6 minutes to read the data, at the 6th minute you will not be retrieving fresh or recently added data. It is like a snapshot of the data. Recordsets opened this way WILL contain an accurate recordcount. Adopenforwardonly cursor (the default) The data is alive but you can only move forward. Attempts to move backward or to specific record numbers will fail.. Recordsets opened this way WILL NOT contain an accurate recordcount, instead returning -1. Adopenkeyset cursor The data is alive and any record read will be the most recent data. f you retrieve a million records for example at 9:00am and it takes 6 minutes to read the data, at the 6th minute you will still be retrieving fresh data but NOT data added or deleted since 9am. Recordsets opened this way WILL NOT contain an accurate recordcount, instead returning -1. Adopendynamic cursor The data is alive and additions will be noticed. If you retrieve a million records for example at 9:00am and it takes 6 minutes to read the data, at the 6th minute you will still be retrieving fresh data and records added to the end of the data. Recordsets opened this way WILL contain an accurate recordcount. Here is the script that counts the query results: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <head><html> <TITLE>dbcount.asp</TITLE> </head><body bgcolor="#FFFFFF"> <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <% ' change these for your site connectme="DSN=Student;uid=student;pwd=magic" sqltemp="select * from publishers where state='NY'" set rstemp=Server.CreateObject("adodb.Recordset") rstemp.open sqltemp, connectme, adopenstatic howmanyrecs=rstemp.recordcount response.write howmanyrecs & " records in<br>" & sqltemp rstemp.close set rstemp=nothing %> </body></html> It is also important to understand that any situation where you open the database and are able to obtain an accurate record count is by nature slower than opening a database that also has the burden of knowing how many records it has upon demand. The additional overhead and limitations of a adopendynamic or adopenstatic cursor may be a poor way to retrieve the data because the recordset even though they count accurately. If you must count AND retrieve, I recommend counting first, closing the recordset and then re-opening the recordset with the best cursor for speed. http://www.learnASP.com/learn/adocursortypes.asp by Charles M. Carroll Page 113 ADO Cursor Types by Phil Paxton (juggler@iquest.net) ADO cursor types affects the properties and methods that are available as this table illustrates. Property Forward-Only Dynamic Keyset AbsolutePage N/A N/A R/W AbsolutePosition N/A N/A R/W ActiveConnection R/W R/W R/W BOF R/O R/O R/O Bookmark N/A N/A R/W CacheSize R/W R/W R/W CursorLocation R/W R/W R/W CursorType R/W R/W R/W EditMode R/O R/O R/O EOF R/O R/O R/O Filter R/W R/W R/W LockType R/W R/W R/W MarshalOptions R/W R/W R/W MaxRecords R/W R/W R/W PageCount N/A N/A R/O PageSize R/W R/W R/W RecordCount N/A N/A R/O Source R/W R/W R/W State R/O R/O R/O Status R/O R/O R/O Method AddNew Yes Yes Yes CancelBatch Yes Yes Yes CancelUpdate Yes Yes Yes Clone N/A N/A Yes Close Yes Yes Yes Delete Yes Yes Yes GetRows Yes Yes Yes Move Yes Yes Yes MoveFirst Yes Yes Yes MoveLast N/A Yes Yes MoveNext Yes Yes Yes MovePrevious N/A Yes Yes NextRecordset Yes Yes Yes Open Yes Yes Yes Requery Yes Yes Yes Static R/W R/W R/W R/O R/W R/W R/W R/W R/O R/O R/W R/W R/W R/W R/O R/W R/O R/W R/O R/O Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Resync Supports Update UpdateBatch N/A Yes Yes Yes N/A Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Legend: R/W = Read/Write R/O = Read-Only N/A = Not Available or Supported Yes = Available/Supported http://www.learnASP.com/learn/dbnewrec.asp by Charles M. Carroll Page 114 Database -- Form to Input a New Record This page demonstrates the capabilities how to setup a simple form for a new database record. The script: 1 2 3 4 5 6 7 8 9 10 <html><head> <title>dbnewrec.asp</title>& <body bgcolor="#FFFFFF"> <% ' My ASP program that allows you to append a record %> <form name="myauthor" action="dbnewrecSQL.asp" method="GET"> <p>Author ID: <input type="TEXT" name="id"></p> <p> Author Name: <input type="TEXT" name="name"></p> <p> Year Born: <input type="TEXT" name="year"></p> <p> <input type="SUBMIT"> </p> </form></body></html> http://www.learnASP.com/learn/dbnewSQL.asp by Charles M. Carroll Page 115 Database -- Add New Record with SQL statement This page demonstrates the capabilities how to add a record to a database with a SQL statement. To double check it is in the database try: Test This -->/learn/test/db1parm.asp?id=9000 If the script doesn't work when adapting it to YOUR database, see: http://www.activeserverpages.com/learn/dbtroubleshoot.asp to determine what the trouble is. The script is: 1 <TITLE>dbnewrecSQL.asp</TITLE> 2 <body bgcolor="#FFFFFF"> 3 <HTML> 4 <% 5 'on error resume next 6 auname=request.querystring("name") 7 auyear=request.querystring("year") 8 auID=request.querystring("ID") 9 If auid<9000 then 10 auid=auid+9000 11 end if 12 Set Conn = Server.CreateObject("ADODB.Connection") 13 conn.open "DSN=Student;uid=student;pwd=magic" 14 SQLStmt = "INSERT INTO authors (AU_ID,author,year_born) " 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 SQLStmt = SQLStmt & "VALUES (" & auid SQLStmt = SQLStmt & ",'" & auname & "'" SQLStmt = SQLStmt & "," & int(auyear) & ")" Set RS = Conn.Execute(SQLStmt) set rs=nothing If err.number>0 then response.write "VBScript Errors Occured:" & "<P>" response.write "Error Number=" & err.number & "<P>" response.write "Error Descr.=" & err.description & "<P>" response.write "Help Context=" & err.helpcontext & "<P>" response.write "Help Path=" & err.helppath & "<P>" response.write "Native Error=" & err.nativeerror & "<P>" response.write "Source=" & err.source & "<P>" response.write "SQLState=" & err.sqlstate & "<P>" else response.write "No VBScript Errors Occured" & "<P>" end if IF conn.errors.count> 0 then response.write "Database Errors Occured" & "<br>" response.write "<b>" & SQLstmt & "</b><P>" for counter= 0 to conn.errors.count response.write "Error #" & conn.errors(counter).number & "<P>" response.write "Error desc. -> " & conn.errors(counter).description & "<P>" next else response.write "No Database Errors Occured!" & "<P>" end if Conn.Close set conn=nothing %> </BODY> </HTML> http://www.learnASP.com/learn/dbnewADO.asp by Charles M. Carroll Page 116 Add New Record with ADO This page demonstrates the capabilities how to add a record to a database using ADO instead of SQL. The script is: 1 2 3 4 5 6 7 8 9 10 <html><head> <title>dbnewrec.asp</title>& <body bgcolor="#FFFFFF"> <% ' My ASP program that allows you to append a record %> <form name="myauthor" action="dbnewADOrespond.asp" method="GET"> <p>Author ID: <input type="TEXT" name="id"></p> <p> Author Name: <input type="TEXT" name="name"></p> <p> Year Born: <input type="TEXT" name="year"></p> <p> <input type="SUBMIT"> </p> </form></body></html> The form responder looks like this: 1 2 3 4 5 6 7 8 9 10 <TITLE>dbnewADO.asp</TITLE> <body bgcolor="#FFFFFF"> <HTML> <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <!--#INCLUDE VIRTUAL="/learn/test/lib_errors.asp" --> <% on error resume next auname=request.querystring("name") auyear=request.querystring("year") auID=request.querystring("ID") 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 If auid<9000 then auid=auid+9000 end if conn="DSN=Student;uid=student;pwd=magic" Set RS = Server.CreateObject("ADODB.Recordset") RS.Open "authors",Conn,adopenstatic,adlockoptimistic RS.AddNew 'RS("AU_ID")=auid RS("Author") = auname RS("Year_Born")= int(auyear) RS.Update Call ErrorVBscriptReport("Adding Record") Call ErrorADOReport("Adding Record",RS.activeconnection) RS.Close set rs=nothing %> </BODY> </HTML> http://www.learnASP.com/learn/dbgetstring.asp by Charles M. Carroll Page 117 Database -- Use GetString to speed code by Charles Carroll This page demonstrates the capabilities how to use getstring (part of ADO 2.0 or above, if you are not sure what ADO version is on your server, see /learn/versioncheck.asp) ● to display a table from a SQL statement with one call ● eliminate multiple response.writes ● eliminate do until eof tests. The script to display the table utilizing getstring is: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <TITLE>dbtablegetstring.asp</TITLE> <body bgcolor="#FFFFFF"> <% whichDSN="DSN=Student;uid=student;pwd=magic" mySQL="select * from publishers where state='NY'" ' ASP program that displays a database in table form set conntemp=server.createobject("adodb.connection") conntemp.open whichDSN set rstemp=conntemp.execute(mySQL) If rstemp.eof then response.write "No records matched<br>" response.write mySQL & "<br>So cannot make table..." rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing response.end end if response.write "<table border='1'><tr>" 'Put Headings On The Table of Field Names for each whatever in rstemp.fields response.write "<td><b>" & whatever.name & "</B></TD>" 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 next response.write "</tr><tr><td>" response.write rstemp.getstring(,, "</td><td>", "</td></tr><TR><TD>", "-null-") response.write "</td></tr></table>" rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </body></html> A similar script to display a list box utilizing getstring is: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <html><head> <TITLE>dblistgetstring.asp</TITLE>& <body bgcolor="#FFFFFF"> <% ' ASP program that displays a database in list form myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select distinct state from publishers" set conntemp=server.createobject("adodb.connection") conntemp.open "DSN=Student;uid=student;pwd=magic" ' Const adCmdUnknown, adCmdText, adCmdTable (no) , adCmdStoredProc set rstemp=server.createobject("adodb.recordset") rstemp.open mySQL, conntemp, adopenforwardonly, _ adlockReadOnly, adCmdUnknown response.write "<form><select name='state'><option>" tempSTR=rstemp.getstring(,, "", "</option><option>", " ") response.write tempSTR response.write "</select></form>" rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </body></html> http://www.learnASP.com/learn/dbtablelists.asp by Charles M. Carroll Page 118 Listing Tables within Databases by Charles Carroll DRAFT SQL Server allows you to list tables like this: 1 2 3 4 <HEAD><TITLE>sqlservertablelist.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% whichDSN="DSN=student;uid=student;pwd=magic" 5 6 7 8 9 call query2table("select name,type from sysobjects where type='U'", whichDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> Access allows you to list tables like this (assuming you allow system objects to be visible within the database on the Access side): 1 2 3 4 5 6 7 8 9 <HEAD><TITLE>accesstablelist.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% whichDSN="DRIVER={Microsoft Access Driver (*.mdb)}; " whichDSN=whichDSN & "DBQ=" & server.mappath("/learn/test/biblio.mdb") call query2table("select * from MsysObjects WHERE type = 1",whichDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> The Include file looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <% sub query2table(inputquery, inputDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open inputDSN set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/dbschemas.asp by Charles M. Carroll Page 119 ADO Schemas to list tables & fields You can examine a Schema for the table names and column names and column detail information. 1 <html><head> 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 <TITLE>dbschemas.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <!--#INCLUDE VIRTUAL="/learn/test/lib_fieldtypes.asp" --> <% myDSN="DSN=Student;uid=student;pwd=magic" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN Set rsSchema = conntemp.OpenSchema(adSchemaColumns) thistable="" pad=" " DO UNTIL rsSchema.EOF prevtable=thistable thistable=rsSchema("Table_Name") thiscolumn=rsSchema("COLUMN_NAME") IF thistable<>prevtable THEN response.write "Table=<b>" & thistable & "</b><br>" response.write "TABLE_CATALOG=<b>" & rsSchema("TABLE_CATALOG") & "</b><br>" response.write "TABLE_SCHEMA=<b>" & rsSchema("TABLE_SCHEMA") & "</b><p>" END IF response.write "<br>" & pad & "Field=<b>" & thiscolumn & "</b><br>" response.write pad & "Type=<b>" & fieldtypename(rsSchema("DATA_TYPE")) & "</b><br>" DIM colschema(27) colschema(0)="TABLE_CATALOG" colschema(1)="TABLE_SCHEMA" colschema(2)="TABLE_NAME" colschema(3)="COLUMN_NAME" colschema(4)="COLUMN_GUID" colschema(5)="COLUMN_PROP_ID" colschema(6)="ORDINAL_POSITION" colschema(7)="COLUMN_HASDEFAULT" colschema(8)="COLUMN_DEFAULT" colschema(9)="COLUMN_FLAGS" colschema(10)="IS_NULLABLE" colschema(11)="DATA_TYPE" colschema(12)="TYPE_GUID" colschema(13)="CHARACTER_MAXIMUM_LENGTH" colschema(14)="CHARACTER_OCTET_LENGTH" colschema(15)="NUMERIC_PRECISION" colschema(16)="NUMERIC_SCALE" colschema(17)="DATETIME_PRECISION" colschema(18)="CHARACTER_SET_CATALOG" colschema(19)="CHARACTER_SET_SCHEMA" colschema(20)="CHARACTER_SET_NAME" colschema(21)="COLLATION_CATALOG" colschema(22)="COLLATION_SCHEMA" colschema(23)="COLLATION_NAME" colschema(24)="DOMAIN_NAME" colschema(25)="DOMAIN_CATALOG" colschema(26)="DOMAIN_SCHEMA" colschema(27)="DESCRIPTION" ON ERROR RESUME NEXT FOR counter=4 to 27 thisColInfoType=colschema(counter) thisColInfo=rsSchema(thisColInfoType) If err.number<>0 then thiscolinfo="-error-" err.clear END IF IF thisColInfo<>"" THEN response.write pad & pad & pad & thiscolinfotype 69 70 71 72 73 74 75 76 77 78 79 80 81 82 response.write "=<b>" & thiscolinfo & "</b><br>" END IF NEXT response.flush rsSchema.MoveNext LOOP rsSchema.Close set rsSchema=nothing conntemp.close set conntemp=nothing %> </body></html> Here is the contents of lib_fieldtypes.asp which is included to make this example work: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <% FUNCTION fieldtypename(parm1) SELECT CASE Parm1 CASE 0 fieldtypename="adEmpty" CASE 16 fieldtypename="adTinyInt" CASE 2 fieldtypename="adSmallInt" CASE 3 fieldtypename="adInteger" CASE 20 fieldtypename="adBigInt" CASE 17 fieldtypename="adUnsignedTinyInt" CASE 18 fieldtypename="adUnsignedSmallInt" CASE 19 fieldtypename="adUnsignedInt" CASE 21 fieldtypename="adUnsignedBigInt" CASE 4 fieldtypename="adSingle" CASE 5 fieldtypename="adDouble" CASE 6 fieldtypename="adCurrency" CASE 14 fieldtypename="adDecimal" CASE 131 fieldtypename="adNumeric" CASE 11 fieldtypename="adBoolean" CASE 10 fieldtypename="adError" CASE 132 fieldtypename="adUserDefined" CASE 12 fieldtypename="adVariant" CASE 9 fieldtypename="adIDispatch" CASE 13 fieldtypename="adIUnknown" CASE 72 fieldtypename="adGUID" CASE 7 fieldtypename="adDate" CASE 133 fieldtypename="adDBDate" CASE 134 fieldtypename="adDBTime" 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 CASE 135 fieldtypename="adDBTimeStamp" CASE 8 fieldtypename="adBSTR" CASE 129 fieldtypename="adChar" CASE 200 fieldtypename="adVarChar" CASE 201 fieldtypename="adLongVarChar" CASE 130 fieldtypename="adWChar" CASE 202 fieldtypename="adVarWChar" CASE 203 fieldtypename="adLongVarWChar" CASE 128 fieldtypename="adBinary" CASE 204 fieldtypename="adVarBinary" CASE 205 fieldtypename="adLongVarBinary" CASE ELSE fieldtypename="Undefined by ADO" END SELECT END FUNCTION %> http://www.learnASP.com/learn/dbschemasall.asp by Charles M. Carroll Page 120 ADO Schemas/listing tables and fields You can examine a Schema for the table names and column names and column detail information. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <html><head> <TITLE>dbschemasall.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <!--#INCLUDE VIRTUAL="/learn/test/lib_schemas.asp" --> <% myDSN="DSN=Student;uid=student;pwd=magic" DIM colschema(30) colschema(0)=adSchemaProviderSpecific colschema(1)=adSchemaAsserts colschema(2)=adSchemaCatalogs colschema(3)=adSchemaCharacterSets colschema(4)=adSchemaCollations colschema(5)=adSchemaColumns colschema(6)=adSchemaCheckConstraints colschema(7)=adSchemaConstraintColumnUsage colschema(8)=adSchemaConstraintTableUsage colschema(9)=adSchemaKeyColumnUsage colschema(10)=adSchemaReferentialContraints colschema(11)=adSchemaTableConstraints colschema(12)=adSchemaColumnsDomainUsage colschema(13)= adSchemaIndexes colschema(14)=adSchemaColumnPrivileges colschema(15)=adSchemaTablePrivileges colschema(16)=adSchemaUsagePrivileges colschema(17)=adSchemaProcedures 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 colschema(18)=adSchemaSchemata colschema(19)=adSchemaSQLLanguages colschema(20)=adSchemaStatistics colschema(21)=adSchemaTables colschema(22)=adSchemaTranslations colschema(23)=adSchemaProviderTypes colschema(24)=adSchemaViews colschema(25)=adSchemaViewColumnUsage colschema(26)=adSchemaViewTableUsage colschema(27)=adSchemaProcedureParameters colschema(28)=adSchemaForeignKeys colschema(29)=adSchemaPrimaryKeys colschema(30)=adSchemaProcedureColumns FOR counter=1 to 30 thisSchema=colSchema(counter) Call Schema2Table(myDSN,thisSchema) response.write "<p>" NEXT %> </body></html> The include file lib_schemas.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <% FUNCTION schemaName(parm1) SELECT CASE parm1 CASE adSchemaProviderSpecific schemaname="adSchemaProviderSpecific" CASE adSchemaAsserts schemaName="adSchemaAsserts" CASE adSchemaCatalogs schemaName="adSchemaCatalogs" CASE adSchemaCharacterSets schemaName="adSchemaCharacterSets" CASE adSchemaCollations schemaName="adSchemaCollations" CASE adSchemaColumns schemaName="adSchemaColumns" CASE adSchemaCheckConstraints schemaName="adSchemaCheckConstraints" CASE adSchemaConstraintColumnUsage schemaName="adSchemaConstraintColumnUsage" CASE adSchemaConstraintTableUsage schemaName="adSchemaConstraintTableUsage" CASE adSchemaKeyColumnUsage schemaName="adSchemaKeyColumnUsage" CASE adSchemaReferentialContraints schemaName="adSchemaReferentialContraints" CASE adSchemaTableConstraints schemaName="adSchemaTableConstraints" CASE adSchemaColumnsDomainUsage schemaName="adSchemaColumnsDomainUsage" CASE adSchemaIndexes schemaName="adSchemaIndexes" CASE adSchemaColumnPrivileges schemaName="adSchemaColumnPrivileges" CASE adSchemaTablePrivileges schemaName="adSchemaTablePrivileges" CASE adSchemaUsagePrivileges schemaName="adSchemaUsagePrivileges" CASE adSchemaProcedures schemaName="adSchemaProcedures" CASE adSchemaSchemata schemaName="adSchemaSchemata" CASE adSchemaSQLLanguages schemaName="adSchemaSQLLanguages" CASE adSchemaStatistics 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 schemaName="adSchemaStatistics" CASE adSchemaTables schemaName="adSchemaTables" CASE adSchemaTranslations schemaName="adSchemaTranslations" CASE adSchemaProviderTypes schemaName="adSchemaProviderTypes" CASE adSchemaViews schemaName="adSchemaViews" CASE adSchemaViewColumnUsage schemaName="adSchemaViewColumnUsage" CASE adSchemaViewTableUsage schemaName="adSchemaViewTableUsage" CASE adSchemaProcedureParameters schemaName="adSchemaProcedureParameters" CASE adSchemaForeignKeys schemaName="adSchemaForeignKeys" CASE adSchemaPrimaryKeys schemaName="adSchemaPrimaryKeys" CASE adSchemaProcedureColumns schemaName="adSchemaProcedureColumns" CASE ELSE schemaName="-unknown-" END SELECT END FUNCTION SUB Schema2Table(parmDSN, parmSchemaName) set conntemp=server.createobject("adodb.connection") conntemp.open parmDSN on error resume next set rsSchema=conntemp.OpenSchema(parmSchemaName) IF err.number=3251 THEN response.flush response.write "<b>" & SchemaName(parmSchemaName) response.write "</b><br> is not supported<br>" err.clear ELSE Call Schema2Table(thisSchema) response.write "<P><b>" & schemaName(parmSchemaName) & "</b><br>" response.write "<table border=1><tr>" 'Put Headings On The Table of Field Names for each whatever in rsSchema.fields response.write "<td><b>" & whatever.name & "</b></td>" next response.write "</tr>" DO UNTIL rsSchema.eof response.write "<tr>" for each whatever in rsSchema.fields thisfield=whatever.value if isnull(thisfield) then thisfield=" " end if if trim(thisfield)="" then thisfield=" " end if response.write "<td valign=top>" & thisfield & "</td>" next response.write "</tr>" rsSchema.MoveNext LOOP response.write "</table><br>" response.flush END IF rsSchema.Close 112 113 114 115 116 117 set rsSchema=nothing conntemp.close set conntemp=nothing END SUB %> http://www.learnASP.com/learn/dbtroubleshoot2.asp by Charles M. Carroll Page 121 Troubleshooting SQL Statements (by Charles Carroll) Now we will show some SQL statements (below) with mistakes and the fixes indicated in red to show how to make the statements work. The kind of fixes we deploy include: ● text fields must have single quotes around the values. ● fields with spaces in their names must be surrounded with [] ● set parameters must have commas between them Text fields with single quote ' cannot be placed into SQL statements unmodified. Notice how the last example below uses the VBScript replace command to transform a string that may contain embedded ' . Statement with Flaws Improved Statement (fixes in red) added space before SET UPDATE mytableSET LocID=0007,Material=13 UPDATE mytable SET LocID='0007',Material='13 1/4', 1/4 Description=T-shirts ListPrice=35 Description='T-shirts', [List Price]=35 WHERE CusID=97 WHERE CusID=97 INSERT INTO authors (AU_ID, author, INSERT INTO authors (AU_ID, author, year_born) VALUES (7000, Joe year_born) VALUES (7000, 'Joe Smith,1950) Smith',1950) SELECT * from atable where state = 'MD' SELECT * from atable where state = MD and and year born<1955 and [year born]<1955 <% <% key=request.querystring("id") key=request.querystring("id") au=request.querystring("author") au=request.querystring("author") au=Replace(au, "'", "''") birthyear=request.querystring("year") birthyear=request.querystring("year") SQLstmt="INSERT INTO authors (AU_ID, SQLstmt="INSERT INTO authors (AU_ID, author, year_born) VALUES (" author, year_born) VALUES (" SQLstmt= SQLstmt & key & "," SQLstmt= SQLstmt & key & ",'" SQLstmt= SQLstmt & author & "," SQLstmt= SQLstmt & author & "'," SQLstmt= SQLstmt & birthyear & ")" SQLstmt= SQLstmt & birthyear & ")" %> %> http://www.learnASP.com/learn/db1parm.asp by Charles M. Carroll Page 122 Displaying A Table/User Supplied Query Input This page demonstrates the capabilities how to display a table from a SQL statement using one input variable from a user. The script to display a specified record in the table is: 1 2 3 <TITLE>db1parm.asp</TITLE> <body bgcolor="#FFFFFF"> <% 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ' My ASP program that talks to a database set conntemp=server.createobject("adodb.connection") conntemp.open "DSN=Student;uid=student;pwd=magic" p1=request.querystring("ID") temp="select * from authors where AU_ID=" & p1 set rstemp=conntemp.execute(temp) howmanyfields=rstemp.fields.count -1 %> <table border=1> <tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name %></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields%> <td valign=top><% = rstemp(i) %></td> <% next %> </tr> <% rstemp.movenext loop rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing%> </table> </body> </html> http://www.learnASP.com/learn/dbupdate.asp by Charles M. Carroll Page 123 Database -- Update Record This page demonstrates the capabilities to update an existing record in a database with a SQL statement. ● It is called like this: Test This -->/learn/test/dbupdate.asp?name=NewPerson&id=9000&year=1901 ● To double check it is in the database try: Test This -->/learn/test/db1parm.asp?id=9000 ● Now try: Test This -->/learn/test/dbupdate.asp?name=NewPerson&id=9000&year=1964 to change the "NewPerson" Birthday to 1964 again and Test This -->/learn/test/dbupdate.asp?name=NewPerson&id=9000&year=1901 The script is: 1 <TITLE>dbupdate.asp</TITLE> 2 <body bgcolor="#FFFFFF"> 3 <HTML> 4 <% 5 on error resume next 6 auname=request.querystring("name") 7 auyear=request.querystring("year") 8 auID=request.querystring("ID") 9 Set Conn = Server.CreateObject("ADODB.Connection") 10 conn.open "DSN=Student;uid=student;pwd=magic" 11 SQLstmt = "UPDATE authors " 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 SQLStmt = SQLstmt & "SET Author='" & auname & "'," SQLstmt = SQLstmt & "year_born=" & auyear SQLStmt = SQLStmt & " WHERE AU_ID=" & auid Set RS = Conn.Execute(SQLStmt) If err.number>0 then response.write "VBScript Errors Occured:" & "<P>" response.write "Error Number=" & err.number & "<P>" response.write "Error Descr.=" & err.description & "<P>" response.write "Help Context=" & err.helpcontext & "<P>" response.write "Help Path=" & err.helppath & "<P>" response.write "Native Error=" & err.nativeerror & "<P>" response.write "Source=" & err.source & "<P>" response.write "SQLState=" & err.sqlstate & "<P>" else response.write "No problems occured!" & "<P>" end if IF conn.errors.count> 0 then response.write "Database Errors Occured" & "<P>" for counter= 0 to conn.errors.count response.write "Error #" & conn.errors(counter).number & "<P>" response.write "Error desc. -> " & conn.errors(counter).description & "<P>" next else response.write SQLstmt response.write "Everything Went Fine. Author is updated now!" & "<P>" end if set rstemp=nothing Conn.Close set conntemp=nothing %> </BODY> </HTML> http://www.learnASP.com/learn/SQL.asp by Charles M. Carroll Page 124 SQL Troubles (SQLtroubles.asp) - Page 125 SQL: Example Tables (SQLexamples.asp) - Page 126 SQL: Where Clause Basics (SQLwhere.asp) - Page 127 SQL: Where Clause Examples (SQLwhere2.asp) - Page 128 SQL: Search Forms #1 (SQLwhereform1.asp) - Page 129 SQL: Search Forms #2 (SQLwhereform2.asp) - Page 130 SQL: Search Forms #3 (SQLwhereform3.asp) - Page 131 SQL: Search AND/OR Operators (SQLandor.asp) - Page 132 SQL: Search AND/OR Examples (SQLandor2.asp) - Page 133 SQL: COUNT, GROUPBY (SQLcount.asp) - Page 134 SQL: SUM, MIN, AVE, MAX (SQLaggregate.asp) - Page 135 SQL Joins by Aaron Alexander (dbjoin.asp) - Page 136 http://www.learnASP.com/learn/SQLtroubles.asp by Charles M. Carroll Page 125 SQL Troubleshooting Resources We also run a listserve for helping you setup complex SQL queries (Joins, multiple ands/ors, etc.) Unlike the list above, it is not a general database troubleshooting list, instead only complex SQL questions are allowed. aspsqlhowto Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/SQLtroubles.asp Send Listserver Questions to aspsqlhowto@ls.asplists.com Related Links John Hoffman's SQL Tutorial @ http://w3.one.net/~jhoffman/sqltut.htm Solution Partners Data Shaping Alternatives @ http://www.solpart.com/techcorner/HRS/HRSOverview.asp Book:SQL for Smarties by Joe Celko @ http://www.learnasp.com/books/sqlsmarties.asp Book: SQL Puzzles & Answers by Joe Celko @ http://www.learnasp.com/books/sqlpuzzles.asp Data Shaping Basics Part1 @ http://www.4guysfromrolla.com/webtech/092599-1.shtml Data Shaping Basics Part1 @ http://www.4guysfromrolla.com/webtech/100699-2.shtml Stump The SQL Guru @ http://www.4guysfromrolla.com/webtech/sqlguru/ 4Guys Inner Join Tutorial @ http://www.4guysfromrolla.com/webtech/050599-1.shtml Join Tutorial by Aaron Alexander @ http://www.learnasp.com/learn/dbjoin.asp General Database questions (i.e. code that is broken, non SQL database issues) needs to be sent to our database listserv, see: /learn/dbtroubles.asp http://www.learnASP.com/learn/SQLexamples.asp by Charles M. Carroll Page 126 Search Database #2 (SQL Where clause examples) For our next examples, knowing the structures of the tables will be helpful. The authors database has a structure like this: Au_ID Author Year_Born The titles database has a structure like this: Title Year_Published ISBN PubID Description Notes Subject Comments The Title_Author table looks like this: ISBN Au_ID The publisher' database has a structure like this: PubID Name Company_Name Address City State Zip Telephone Fax Comments http://www.learnASP.com/learn/SQLwhere.asp by Charles M. Carroll Page 127 Search Database #1 (SQL Where clauses) There are several ways to search the data using pure SQL once we review the simple rules of how a WHERE clause works. ● Text fields must be enclosed in single quotes, i.e. "select * from publishers where state='MD' ● Numeric fields need no special characters before and after "select * from publishers where PubID=10" ● If you aren't sure how to spell the text field or are looking for sound alikes, LIKE supports %% wildcards "select * from publishers where Name like 'A%%'" These basic WHERE clause guidelines above are the fundamental building block of searches. It is also helpful to utilize the equality operators, i.e. <> > < >= <= ● not equal greater than less than greater than OR equal less than or equal Numeric fields benefit most from the equality operators: "select * from publishers where PubID>10" http://www.learnASP.com/learn/SQLwhere2.asp by Charles M. Carroll Page 128 SQL Where Examples by Charles Carroll Here are some where statements and their results. 1 2 3 4 5 6 7 <HEAD><TITLE>SQLwhere1.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select * from publishers where name like 'A%%'") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>SQLwhere2.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select * from titles where Year_Published >= 1994") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>SQLwhere3.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select * from publishers where fax like '212%%'") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>sqlwhere4.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select * from publishers where state<> 'NY'") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> The Include file looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <% sub query2table(inputquery) set conntemp=server.createobject("adodb.connection") conntemp.open "DSN=Student;uid=student;pwd=magic" set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/SQLwhereform1.asp by Charles M. Carroll Page 129 Search Database (SQL Where Form examples) In the previous page we introduced the WHERE clause, but now we will see several examples of the WHERE clause in typical forms. This example allows users to choose a city: 1 2 3 4 <HEAD><TITLE>sqlwhereform1.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <Form action = "sqlwhereForm1respond.asp" method=GET> Choose A State:<p> 5 6 7 State: <Input NAME="st" MaxLength="2" size="3"><P> <Input type="submit" value="Get Data"> <Input type="reset" value="Clear State"></form> </BODY></HTML> 1 2 3 4 5 6 7 8 9 10 11 12 13 <HEAD><TITLE>sqlwhereform1respond.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mystate=request.querystring("st") SQLtemp="select * from publishers where state='" SQLtemp=SQLtemp & mystate & "'" call query2table(SQLtemp,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> The file lib_subdbtable.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <% sub query2table(inputquery, inputDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open inputDSN set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/SQLwhereform2.asp by Charles M. Carroll Page 130 Search Database (SQL Where Form examples) We will now present a form that allows people to choose a city but also supports inexact searches using LIKE are supported: 1 2 <HEAD><TITLE>SQLwhereform2.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> 3 4 5 6 7 8 9 <Form action = "SQLwhereForm2respond.asp" method=GET> Choose A City:<p> City: <Input NAME="cy" MaxLength="20" size="23"><P> <input TYPE="checkbox" NAME="ExactSearch" CHECKED>Exact Search<P> * note if Exact Search is -> NOT CHECKED <-<br>You can use % as a wildcard<p> <Input type="submit" value="Get Data"> <Input type="reset" value="Clear City"></form> </BODY></HTML> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <HTML><HEAD> <TITLE>sqlwhereform2respond.asp</TITLE>& <body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mycity=request.querystring("cy") myexactsearch=request.querystring("exactsearch") SQLtemp="select * from publishers where city" If myexactsearch="on" then SQLtemp=SQLtemp & " ='" Else SQLtemp=SQLtemp & " LIKE '" End If SQLtemp=SQLtemp & mycity & "'" 'response.write SQLtemp call query2table(SQLtemp,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> The file lib_dbtable.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <% sub query2table(inputquery, inputDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open inputDSN set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/SQLwhereform3.asp by Charles M. Carroll Page 131 Search Database (SQL Where Form #3) Ideally, the perfect "pick a city" example would show people a list of items so they can't choose wrong: 1 2 3 4 5 6 7 8 9 10 11 12 13 <HEAD><TITLE>SQLwhereform3.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <Form action = "SQLwhereForm3respond.asp" method=GET> Choose A City:<p> City: <% call query2list("select distinct city from publishers", _ "cy","DSN=student;uid=student;pwd=magic") %> <P> <Input type="submit" value="Get Data"> <Input type="reset" value="Clear City"></form> </BODY></HTML> <!--#include virtual="/learn/test/lib_dblist.asp"--> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <html><head><TITLE>sqlwhereform3respond.asp</TITLE></head> <body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mycity=request.querystring("cy") myexactsearch=request.querystring("exactsearch") SQLtemp="select * from publishers where city" If myexactsearch="on" then SQLtemp=SQLtemp & " ='" Else SQLtemp=SQLtemp & " LIKE '" End If SQLtemp=SQLtemp & mycity & "'" 'response.write SQLtemp call query2table(SQLtemp,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </body></html> The file lib_dbtable.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <% sub query2table(inputquery, inputDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open inputDSN set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> 24 25 26 27 28 29 30 31 32 33 </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> The file lib_dblist.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <%sub query2list(myquery,myname,myDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(myquery) %> <Select name="<%=myname%>"> <% do while not rstemp.eof thisfield=trim(RStemp(0)) if isnull(thisfield) or thisfield="" then ' ignore else response.write "<option>" & thisfield & "</option>" end if rstemp.movenext loop %> </select> <%rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/SQLandor.asp by Charles M. Carroll Page 132 SQL OR Search Example by Charles Carroll AND and OR operators expand the power of the WHERE clause and provide a powerful tool to check multiple conditions. The Basic Guidelines are as follows: If your goal is that several if conditions must ALL BE TRUE to suceed, this is the Role of the AND within a WHERE clause, i.e. "select * from publishers where state='MD' and city='Rockville' "select * from authors where Year_Born>1960 and Year_Born<1970' If several conditions can indivually be true this is the Role of an OR within a WHERE clause, i.e. "select * from publishers where state='MD' OR state='NY' 1 2 3 4 5 6 7 8 9 10 <HEAD><TITLE>SQLcities.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <Form action = "SQLcitiesrespond.asp" method="POST"> Choose City (or Cities):<p> <% call query2listm("select distinct city from publishers", _ "cy","DSN=student;uid=student;pwd=magic") %> <P> <Input type="submit" value="Get Data"> <Input type="reset" value="Clear City"></form> 11 12 13 </BODY></HTML> <!--#include virtual="/learn/test/lib_dblistm.asp"--> The responder looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <HEAD><TITLE>sqlcitiesrespond.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% citycount=request.form("cy").count If citycount=0 then%> <B>You never choose a city!</b><br> <a href="sqlcities.asp">Choose City</a> <% response.end end if firstcity=request.form("cy")(1) SQLtemp="select * from publishers " SQLtemp = SQLtemp & " where city='" & firstcity & "'" for counter=2 to citycount whichcity=request.form("cy")(counter) SQLtemp = SQLtemp & " or city='" & whichcity & "' " next response.write SQLtemp call query2table(SQLtemp,"DSN=student;uid=student;pwd=magic") %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> The file lib_dbtable.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <% sub query2table(inputquery, inputDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open inputDSN set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> The file lib_dblistm.asp looks like this: 1 <% 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 SUB query2listm(myquery,myname,myDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(myquery) %> <Select name="<%=myname%>" multiple> <% do while not rstemp.eof thisfield=trim(RStemp(0)) if isnull(thisfield) or thisfield="" then ' ignore else response.write "<option>" & thisfield & "</option>" end if rstemp.movenext loop %> </select> <%rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing END SUB %> http://www.learnASP.com/learn/SQLandor2.asp by Charles M. Carroll Page 133 SQL And/OR Examples by Charles Carroll Here are some examples of the AND plus OR operators and INLIST in typical ASP scripts. DRAFT -- NOT READY YET COMING SOON! http://www.learnASP.com/learn/SQLcount.asp by Charles M. Carroll Page 134 SQL Count Syntax/Examples SQL can count items. There are a few variations on the syntax and some simple rules to remember: ● Any field you want to count here is the simplest syntax "select count(*) from publishers where state='NY' ● If you count a specific field you must groupby that field or it won't work: "select count(city),city from publishers group by city" ● The AS operator allows you to specify a name for the counted field: "select count(city) as howmany,city from publishers group by city" 1 2 3 4 5 6 7 <HEAD><TITLE>SQLcount1.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select count(*) from publishers where state='NY'") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>SQLcount2.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select count(city),city from publishers group by city") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>SQLcount3.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select count(city) as howmany,city from publishers group by city") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>SQLcount4.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% call query2table("select count(*),city,state from publishers group by city,state") %> <!--#include virtual="/learn/test/subdbtable.inc"--> </BODY></HTML> The Include file looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <% sub query2table(inputquery) set conntemp=server.createobject("adodb.connection") conntemp.open "DSN=Student;uid=student;pwd=magic" set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/SQLaggregate.asp by Charles M. Carroll Page 135 SQL Aggregate Syntax/Examples SQL can also compute various aggregate items (MIN, MAX, AVERAGE are the most popular). http://www.learnASP.com/learn/dbjoin.asp by Charles M. Carroll Page 136 Database -- Inner Joins by Aaron Alexander In this demonstration I will explain to you how joins between tables work in SQL. I will use the verbose SQL rather than the shortcuts due to the fact that the shortcuts differ between databases. I would first like to define some terms that I will be using: Primary Key(PK): This is the unique field in your table that is used to identify each record. (Ex: RecID) Foreign Key(FK): This is a column that references a primary key of another table. It can have duplicate values. We have 2 tables defined: Customer CustomerID(PK) CustomerName 1 Joe Schmoe 2 Fred Flintstone Sales ID(PK) CustomerID(FK) SalesAmount 3 1 $1.00 4 1 $22.00 5 1 $3.00 6 20 $22.00 Inner Joins When joining two tables there are two ways to do it. The most common way is the inner join. The inner join will return all data where all joined data exists. Lets look at this example of an inner-join: SELECT Customer.CustomerName, Sales.SalesAmount FROM Customer INNER JOIN Sales ON customer.CustomerID = Sales.CustomerID In our example above, we are selecting all the Customer Names and amount of the sale where the customer numbers exist in both tables. The result of the query is this: CustomerName SalesAmount Joe Schmoe $1.00 Joe Schmoe $22.00 Joe Schmoe $3.00 Note that record ID 6 in the sales table with customer ID of 20 is not in our result. Since that joined data does not exist we do not see the data. Note: The SQL above can be written a lot simpler, doing it this way will avoid confusion when other tables are added: SELECT Customer.CustomerName, Sales.SalesAmount FROM Customer , Sales where customer.CustomerID = Sales.CustomerID Outer Joins The outer join is useful when we want to return all data from one table, and also return linked data from another, when it exists, but here is where we differ from the inner join, we want to return all data from table 1 no matter what. In our example we want to return all sales, even if there isn’t a valid customer associated with it. Here is what our SQL will look like: SELECT Customer.CustomerName, Sales.SalesAmount FROM Customer RIGHT JOIN Sales ON Customer.CustomerID = Sales.CustomerID Our results will look like this: CustomerName SalesAmount Joe Schmoe $1.00 Joe Schmoe $22.00 Joe Schmoe $3.00 $22.00 Notice we did a right join. We chose to select all the data from the right table in our join statement. What would it look like if we changed to this: SELECT Customer.CustomerName, Sales.SalesAmount FROM Customer LEFT JOIN Sales ON Customer.CustomerID = Sales.CustomerID; Our results: CustomerName SalesAmount Joe Schmoe $1.00 Joe Schmoe $22.00 Joe Schmoe $3.00 Fred Flintstone The results gave us all the records from the left table (Customer) and the linked data from the right. As with the inner join there are shortcuts for joins, but that depends on which database you are using. Writing the verbose SQL statement will work on all databases. I hope this helps clear things up. Aaron Alexander http://www.learnASP.com/learn/authenticate.asp by Charles M. Carroll Page 137 Authenticate: Overview by Kevin Flick (authenticateoverview.asp) - Page 138 Authenticate: Comparison by Kevin Flick (authenticatecomparisons.asp) - Page 139 Authenticate: NT Challenge/Response by Kevin Flick (authenticatentcr.asp) - Page 140 Authenticate: Basic Authentication by Kevin Flick (authenticatebasic.asp) - Page 141 Authenticate: Cookies by Kevin Flick (authenticatecookies.asp) - Page 142 Authenticate: Certificates by Kevin Flick (authenticatecertificate.asp) - Page 143 Authenticate: Build Your Own by Kevin Flick (authenticatebuild.asp) - Page 144 Authenticate: Protect Pages via Login #1 (security.asp) - Page 145 Authenticate: Protect Pages via Login #2 (security2.asp) - Page 146 Authenticate: 3rd Party by Kevin Flick (authenticate3rdparty.asp) - Page 147 http://www.learnASP.com/learn/authenticateoverview.asp by Charles M. Carroll Page 138 Authentication Overview written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix What is Authentication? Let's assume you want to restrict access to selected portions of your website. For example, you might have valuable information, such as real-time stock quotes (like Reuters or Datastream), or you want to charge a monthly fee in order to access your database. In these cases, you want to let people in, but only after checking that visitors have used an authorized username and password. Additionally, you might want to provide access to the bulk of your website for the simple price of a visitor's email address, creating an effective method for tracking visitors. Asking a visitor for their username and password (or their credentials) is called Authentication. On the world wide web, the oldest and most widely supported authentication method is Basic Authentication. What are my choices? Assuming you have the latest and greatest IIS, you have several choices when working with authentication including: ● IIS NT Challenge Response A good choice if if you are on a Windows Network, you can require the use of IE, and there's no proxy-server between the browser and the server. ● IIS Basic Authentication Can expose your NT usernames and passwords unless all connections are over SSL. ● A Basic Authentication filter such as AuthentiX Cannot compromise NT accounts. High performance, large numbers of users. Can validate against ODBC or internal database. Many advanced features. ● Write your own filter Flexible, but resource intensive to build. ● Cookie Based Authentication with ASP pages Only protects ASP pages. Can be slow. Requires cookies. Cookie-based systems can be susceptible to spoofing. ● Self-Authenticating ISAPI dlls, CGI-scripts using Basic Authentication. Good performance, all content generated though a single URL. Doesn't use conventional directory/file/html format. ● Certificate based. Secure, but intimidating for webmasters and surfers alike. Requires SSL. http://www.learnASP.com/learn/authenticatecomparisons.asp by Charles M. Carroll Page 139 Authentication Comparison written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix Which should I use? In deciding which type of Authentication to use, it's important to keep the following points in mind: ● You want the widest possible audience, along with browser and platform independence. (impacts NTCR and cookies) ● Performance is critical. If (as you hope), your site becomes wildly popular, you don't want a dead-slow server (impacts SSL/Certificates, ASP) Which Type Why use it? Why not use it? How to use it. Why Why not How Why Why not How Why Why not How Why Why not How Why Why not How Why Why not How Why Why not How IIS NT Challenge Response IIS Basic Authentication A Third Party Basic Authentication filter Write your own Basic Authentication filter Cookie Based Authentication with ASP pages Self-authenticating scripts Certificate based authentication. http://www.learnASP.com/learn/authenticatentcr.asp by Charles M. Carroll Page 140 Authentication -- NT Challenge/Response written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix Using NT Challenge Response is an obvious choice, and is included as one of the options when you set up each IIS directory. Any directory you want to protect must be on a NTFS partition. NTFS is the way to go if you are on a Windows Network. For intranets NTCR can be an ideal solution with these conditions: ● all users are on accessible domains ● there aren't too many users ● you can require the use of a compatible browser (Internet Explorer is the only browser which supports NTCR). You won't want to use NTFS if ● you want compatibility with browsers other than IE, or older browsers ● you want to protect directories on FAT partitions ● ● you expect (don't we all?) a large number of users. Having a large number of users becomes a problem because this clutters the NT user database and it becomes very difficult to maintain. It can also impair the speed of the operating system itself! Using the NT user base can also be a problem because of potential security risks. You are elevating a 'mere' web surfer to the status of a full NT user. You have to be careful not inadvertently grant too many permissions. there's a proxy server involved As documented in the IIS 4 Resource Kit, NTLM will not work through a proxy. The problem is that it requires more than 1 round trip to complete authentication and so needs a persistent connection end to end end, from client to origin server. Proxies don't generally work that way. Definitions ● ● ● NTCR = NT Challenge Response NTLM = NT Lan Manager NTFS = NT File System How to set up NTCR In Internet Service Manager (IIS1-3) or the Microsoft Management Console for IIS (IIS4 and up) select the directory you want to protect. Make sure Basic (Clear Text) is off and Windows NT Challenge Response is on. You can leave Allow Anonymous on. Create an account for each user you want to provide access, remove the permissions for "IUSR_machinename" from the directory, and add permissions for the added users. Alternatively, you could set up a group, permit access to that group, and add permitted users to the group. Remember, the user will need execute rights if the directory has any ASP, ISAPI extensions, counters, and so on. Note that when the user returns to a non-protected page, they will be prompted for their username and password again, unless you have also granted them read-access to non-protected pages. However cancelling the prompt will let them in, disconcerting though this may be. If the user has permission to access the directory but is in a different domain than the IIS machine, the user will have to prepend the domain name, so IIS knows where to look for the password. Because NTCR uses a token mechanism for verifying users, the password of the currently logged in user is not available to IIS. This will have an impact if you are trying to access a resource which is not on the same machine as IIS, since IIS will not be able to login using the current user to a machine elsewhere on the LAN. For example if an NTCR protected ASP page tried to read an Access mdb file on another machine, it would fail. Similarly for SQL Server with Integrated or Mixed security. See Q166029, Q149425. http://www.learnASP.com/learn/authenticatebasic.asp by Charles M. Carroll Page 141 Authentication - IIS Basic Authentication written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix IIS Basic Authentication is included as an option when you set up each IIS directory. Any directory you want to protect must be on a NTFS partition. IIS Basic Authentication is the way to go if you accept the need for SSL and don't mind paying the performance penalty. You already have a certificate or you don't mind paying for one and setting it up. You won't want to use IIS Basic Authentication if you are concerned about the security of your NT accounts and performance. IIS calls LogonUser and ImpersonateLoggedOnUser for each and every request, which is expensive in terms of CPU cycles. Definitions ● SSL = Secure Socket Layer. How to set up IIS Basic Authentication Setting up IIS Basic Authentication is similar to setting up NTCR. ● In Internet Service Manager (IIS1-3) or the Microsoft Management Console for IIS (IIS4 and up) select the directory you want to protect. Turn on Basic (Clear Text) and turn off Windows NT Challenge Response. It is OK to leave Allow Anonymous on. ● When you select Basic (Clear Text) you will be warned that you Windows NT usernames and passwords will be transmitted without being encrypted. For your NT accounts this is a pretty serious issue. You should only consider this option in combination with SSL, which is slow and requires you to buy a certificate from Verisign or Thawte (among others). ● Create an account for the each user to whom you want to give access, remove the permissions for "IUSR_machinename" from the directory, and add permissions for the users you added. Alternatively you could set up a group, permit access to that group, and add permitted users to that group. Remember the user will need execute rights if the directory has any ASP, ISAPI extensions, counters etc. http://www.learnASP.com/learn/authenticatecookies.asp by Charles M. Carroll Page 142 Authentication -- Cookie Based written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix You can use the cookie based session variables of Active Server Pages to capture a username and password from a form, validate the username and password, then set a session variable to indicate the user has correctly logged in. Cookie Based Authentication with ASP pages is the way to go if ● You are happy coding your own solution in VBScript, and you only have a few asp pages to protect. ● You don't mind excluding those who cannot or will not accept cookies. ● You don't have gif/jpeg/pdf or other non-ASP content, so you are not concerned about someone else creating web-pages linking directly to your non-ASP protected content. You won't want Cookie Based Authentication with ASP pages if ● You want to protect all content, not just ASP pages. ● You are worried about performance. Any reasonably large amount of Active Server Pages can have a significant detrimental effect on the performance of your server. The popularity of products such as XBuilder, which generates static html pages from ASP pages for performance reasons (among others), illustrates this point. ● Cookie-based systems can be susceptible to spoofing. Definitions ● ASP = Active Server Pages. How to use Cookie Based Authentication with ASP pages We have a example in this Tutorial on the next pages that implements session based authentication for people who want to implement this: ● http://www.activeserverpages.com/learn/security.asp ● http://www.activeserverpages.com/learn/security2.asp http://www.learnASP.com/learn/authenticatecertificate.asp by Charles M. Carroll Page 143 Authentication -- Certificate Based written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix Client certificates are an advanced form of authentication, and at this time they are still very much in their infancy with respect to compatibility and ease of use. Certificate based authentication is the way to go if : ● you want a high degree of certainty of the identity of the users accessing your site ● You accept the need for SSL and don't mind paying the performance penalty. ● You already have a certificate or you don't mind paying for one and setting it up. You won't want Certificate based authentication if : ● The process of issuing a client certificate is too complex and intimidating for both you and your users ● You do not want the performance hit of having all protected information exchanged via SSL Definitions ● SSL = secure socket layer. ● MMC = Microsoft Management Console. How to use Certificate based authentication Since this technology is still maturing, be sure to have the latest version of IIS4 installed on your system. ● Obtain a certificate from a certificate issuing authority such as Verisign or Thawte. Refer to the IIS documentation on Key Manager. ● Select a directory you want to protect in the MMC ● Click on the Secure Communicatations Edit button on the Directory Security property sheet and use the certificate you obtained. Select both Enable Client Certificates and Require Client Certificate ● Enable client certificates for this resource ● Issue client certificates for access to this resource. There are several good references to help understand and use Client Certificate technology. Some articles that are recommended include: ● "Internet Information Server 4.0 - Security for the Web-Enabled Enterprise" by Nick Evans in the Premier Edition of Security Advisor by Advisor.com publications, and ● "Web Project, Digital IDs" by Jon Udell in the March Edition of Byte magazine. ● "Issuing digital certificates with Microsoft Certificate Server" section of the IIS Security White Paper by Microsoft. http://www.learnASP.com/learn/authenticatebuild.asp by Charles M. Carroll Page 144 Authentication -- Write your own Filter written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix Writing your own Basic Authentication filter is an option if you have the skills, resources and time to do it. Writing your own Basic Authentication filter is the way to go if ● you have special requirements, and commissioning a custom enhancement to a third party Basic ● ● Authentication filter is not an option. you have the skills, resources and time. you want to validate against a specific or proprietary type of datasource, such as flat-file, or your own database. You won't want to write your own Basic Authentication filter if ● you have a short deadline ● you do not have the skills or resources required ● Basic Authentication is not secure enough for your purposes ● you want all accounts of every type in one userbase, specifically the NT user account database, for administrative reasons. ● a third party tool like AuthentiX meets all your needs Definitions ● ISAPI = Internet Server Application Programming Interface How to write your own Basic Authentication filter You will need to build a dll that conforms to the ISAPI filter specification and has the following entry points: ● GetFilterVersion ● HttpFilterProc The GetFilterVersion function is the first entry point called by the Internet Information Server. In this function you set the IIS notifications that you want to receive, and any other first time setup tasks. The HttpFilterProc function is called in response to the notifications set in GetFilterVersion and is where the work of the filter is actually done. There are several excellent references to help develop an ISAPI filter. Recommended is Que's "Special Edition Using ISAPI", ISBN 0-7897-0913-9 (to which this writer also contributed). http://www.learnASP.com/learn/security.asp by Charles M. Carroll Page 145 Custom Security/Authentication #1 You can limit access to specific pages in your website using several methods documented at http://www.activeserverpages.com/learn/authenticate.asp Here we will demonstrate how to use custom authentication and also cover session and application issues. You can try our authentication example by: ● Attempt to access test/securitytestlevel1.asp or test/securitytestlevel2.asp or test/securitylevel3required.asp All attempts to read those pages should fail. ● Now if you login at test/securitylogin.asp. Sample logins that will work because of the database data are: user=chaz, password=chaz, securitylevel=1 user=chaz2, password=chaz2, securitylevel=2 user=chaz3, password=chaz3, securitylevel=3 ● You can also try logging out at test/securitylogout.asp which will put you back to square one. No security level will exist then. The next page details the source code for all scripts needed to implement our example but here is the list: securitylogin.asp securityloginrespond.asp securitylogout.asp the login screen where someone can enter username/password and confirm security level. It is a form that submits to securityloginrespond.asp the screen to abandon someone's username/password and security level securitylevel1required.asp securitylevel2required.asp securitylevel3required.asp securitytestlevel1.asp securitytestlevel2.asp securitytestlevel3.asp which can be included on individual pages to limit access to people with that security level, i.e/: <!--#include file="securitylevel1required.asp"--> which demonstrate how security is implemented. These scripts cannot be seen unless you login. which anyone attempting to access a page without appropriate security level is redirected to. a 3 column Access database: username, password, security level. Sample data is: user=chaz, password=chaz, securitylevel=1 /learn/test/customsecurity.mdb user=chaz2, password=chaz2, securitylevel=2 user=chaz3, password=chaz3, securitylevel=3 Download Database securitynotallowed.asp In a production application, this database would be located OUTSIDE of the web structure (and accessed by DSN) so it could never be downloaded by a user. http://www.learnASP.com/learn/security2.asp by Charles M. Carroll Page 146 Custom Security/Authentication #2 To implement custom security via a database, we use the following scripts that we will present the source code for: Here is the securitylogin.asp script: 1 2 3 4 5 6 7 8 9 <html><head> <title>securitylogin.asp</title> </head><body bgcolor="#FFFFFF"> <form action="securityloginrespond.asp" method="POST"> Sign In Page:<p> Name -> <input NAME="userName" size="20"><br> Password -> <input NAME="userPassword" size="20"><br> <input type="submit"><input type="reset"> </form></body></html> Here is the securityloginrespond.asp script: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <html><head> <TITLE>securityloginrespond.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% dbname="/learn/test/secret/customsecurity.mdb" myname=request.form("username") mypassword=request.form("userpassword") set conntemp=server.createobject("adodb.connection") cnpath="DBQ=" & server.mappath(dbname) conntemp.Open "DRIVER={Microsoft Access Driver (*.mdb)}; " & cnpath sqltemp="select * from users where user='" sqltemp=sqltemp & myname & "'" set rstemp=conntemp.execute(SQLTemp) If rstemp.eof then%> we don't have a user named <%=Myname%> on file!<br> Try <A href='securitylogin.asp'>Logging in</a> again <%response.end end if If rstemp("Password")=mypassword then session("name")=rstemp("user") session("securitylevel")=rstemp("securitylevel") response.write "Security Level=" & session("securitylevel") else%> Password Unrecognized<br> 25 26 27 28 29 30 31 32 33 Try <A href='securitylogin.asp'>Logging in</a> again <%response.end end if rstemp.close conntemp.close set rstemp=nothing set conntemp=nothing %> </body></html> Here is the securitylogout.asp script: 1 2 3 4 5 6 7 8 9 <html><head> <title>securitylogout.asp</title>& <body> <% session.abandon %> Logged out Now!!! </body> </html> Here is the securitylevel1required.asp script: 1 2 3 4 5 6 7 8 <% response.expires=0 if session("securitylevel")>0 then ' nothing to do else response.redirect "securityunauthorized.asp" end if %> Here is the securityunauthorized.asp script: 1 2 3 4 5 <html><head> <title>unauthorized</title>& <body> You are unauthorized to read that page! </body></html> Here is the securitytestlevel1.asp script: 1 2 3 4 5 6 7 8 9 <!--#include file="securitylevel1required.asp"--> <html><head> <title>New Page </title> <META HTTP-EQUIV="Expires" CONTENT="Tue, 04 Dec 1993 21:29:02 GMT"> </head><body> My level 1 secret is Pretty Hot!!!<br> Our president may not be as honest as we believed! </body> </html> http://www.learnASP.com/learn/authenticate3rdparty.asp by Charles M. Carroll Page 147 Authentication -- 3rd Party Method written and ©1998, 99 by Kevin Flick www.flicks.com creator of Authentix You won't want to use a third party Basic Authentication filter if ● protecting your premium content directories does not warrant the price of registration. ● Basic Authentication is not secure enough for your purposes ● you want all accounts of every type in one userbase, specifically the NT user account database, for administrative reasons. Authentix, a third party Basic Authentication filter is the way to go if ● ● ● ● ● ● ● ● ● ● ● You want the high performance that a filter offers You want to be able to add and modify users from ASP and don't want the ASP pages to have SysAdmin priviledges You want browser independence You don't want any chance of compromising NT username/password security You want to separate your web-users from your NT Accounts You are concerned about performance. In addition to the speed associated with filter based solutions, AuthentiX is unique in that it does not impersonate an NT account to grant access, eliminating the CPU-expensive call to LogonUser on every request. You have directories you want to validate against an ODBC database You want to authenticate multiple IIS servers against a single ODBC machine on the LAN. You want to use browser based remote administration you need to protect all content in a directory: htm, asp, gif, jpg, zip, and so on. you want advanced features like ❍ limiting concurrent logins, ❍ bandwith, request and login throttling, ❍ protect by IP, Domain Name and by referrer AuthentiX is a fast, filter based third party tool for IIS authentication developed by Flicks Software (me). It allows you to protect content directories and individual files by asking for usernames and passwords held separately from the Windows NT usernames and passwords, ensuring the the security of your NT accounts. Definitions ● ODBC = Open Database Connectivity. How to set up AuthentiX, a third party Basic Authentication filter Setting up AuthentiX is easy and straighforward. Download the free evaluation version, unzip it and run setup.exe. Installshield will guide you through the rest of the installation process. ● Make sure Basic (Clear Text) is off and Allow Anonymous is on. You can leave Windows NT Challenge Response on or off. ● Create a user. From the main AuthentiX dialog, click the Users button, then Add. Type a username and password and click OK. The user will be added to the User List. Click OK. ● Create a group. From the main AuthentiX dialog, click the Groups button, then Add. Type a Groupname, click on a user (to highlight it) listed in the Non-Members list box, and click Add. The user will be moved to the Members list box. Click OK. You should now see the group in the group list. Click OK. ● Protect a directory. From the main AuthentiX dialog, click the Access button, then Add. Click the Browse button and select a directory that is part of your web directories, and that you would like to protect. Click the By Group button and add the group you created in the previous step. Click OK. You should now see that the group is protecting that directory. Verify that the group is protecting the desired directory and click OK twice ● Using a browser, go to the URL that the directory is accessed from using IIS. It should prompt you for your username and password. ● Type the username and password and you should be granted access. You can see how to set up ODBC and other advanced options by downloading the online Windows help file or checking out the online Guided Tour. Because the pace of enhancements and improvements to this product sometimes outstrips the documentation, you can find out more by working with the free evaluation download. http://www.learnASP.com/learn/qualitycode.asp by Charles M. Carroll Page 148 Strings: Core Functions (strings.asp) - Page 149 Strings: SPLIT Function (stringsplit.asp) - Page 150 Strings: REPLACE Function (stringreplace.asp) - Page 151 Strings: JOIN Function (stringjoin.asp) - Page 152 Arrays: Basics (arrays.asp) - Page 153 Arrays: Variable Size (arrays2.asp) - Page 154 Arrays: Best Way To Load (arrays3.asp) - Page 155 Dictionary Objects (dictionary.asp) - Page 156 Subroutine: Working with Dates #1 (subdates.asp) - Page 157 Subroutine: Working with Dates #2 (subdates2.asp) - Page 158 Subroutine: Query2Table (subdbtable.asp) - Page 159 Subroutine: Query2List (subdblist.asp) - Page 160 Subroutine: Highly Reusable (subreusable.asp) - Page 161 Subroutine: List Box w/optional params (subDBlistbest.asp) - Page 162 Subroutine: Abstract HTML by Phil Paxton (libhtml.asp) - Page 163 Function: Working Days (functionworkingdays.asp) - Page 164 New Features in VBScript version5 (vbs5.asp) - Page 165 http://www.learnASP.com/learn/strings.asp by Charles M. Carroll Page 149 String Functions by Charles Carroll String functions are very useful for parsing data from ASCII files, formatting output in complex ways and parsing form input. The following scripts provides a sample of some crucial VBScript string functions in action. The string functions demonstrated are: Instr(string,searchstring) returns a numeric position where search string was found Mid(string,start,length) chops string at a start position for a fixed number of characters. Mid(string,start) results in a string that has all characters before startpos removed. Trim(string) removes all spaces from a string. 1 2 3 4 5 6 7 8 9 <html><head> <title>citystatezip.asp</title> </head><body bgcolor="#FFFFFF"> <Form action = "citystatezipRespond.asp" method="post"> Enter City <b>,</b> State Zip<p> <Input NAME="CSZ" size ="40"><p> <Input type="submit" value="Here is my Data!"> </form> </body></html> The user can enter a city, state and Zip, i.e. Rockville, MD 20849 San Fransisco, CA xxxxx Pike's Peak, CO xxxxx and the program can use these functions to separate the data. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <html><head> <title>citystateziprespond.asp</title> </head><body> <% alldata=request("csz") IF instr(alldata,",")=0 THEN%> You need a comma<br>,<br>between city and state!<p> <%response.end END IF findcomma=instr(alldata,",") city=mid(alldata,1,findcomma-1) leftover=trim(mid(alldata,findcomma+1)) findspace=instr(leftover," ") state=mid(leftover,1,findspace) leftover=mid(leftover,findspace+1) zip=leftover response.write "city=" & city & "<br>" response.write "state=" & state & "<br>" response.write "zip=" & zip & "<br>" %> </body></html> http://www.learnASP.com/learn/stringsplit.asp by Charles M. Carroll Page 150 SPLIT String Function by Charles Carroll The various string functions can be used interchangeably often. We will write the same script using SPLIT, REPLACE and JOIN to demonstrate all 3 functions and how they often are used for similar tasks. However, your programming situations may be especially suited for 1 out of 3 of the functions. SPLIT(string,delimiter) is a function that returns an array with as many elements as are separated by delimiters within the string. The user can enter a state or multiple states. We write the program utilizing SPLIT to demonstrate how this can be used. statesplit.asp 1 2 3 4 5 6 7 8 9 <html><head> <title>states.asp</title> </head><body bgcolor="#FFFFFF"> <form action="statesplitrespond.asp" method="post"> Enter State (or many states separated by <b>,<b><p> <input NAME="states" size="40"><p> <input type="submit" value="Get The Publishers!"> </form> </body></html> statesplitrespond.asp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!--#include virtual="/learn/test/lib_dbtable.asp"--> <html><head> <title>statesrespond.asp</title>& <body> <% mySQL="select * from publishers " & whereclause myDSN="DSN=student;uid=student;pwd=magic" public allstates tempinput=request("states") allstates=split(tempinput,",") maxcounter=ubound(allstates) whereclause=" where state='" & allstates(0) & "'" FOR counter=1 TO maxcounter thisstate=allstates(counter) whereclause=whereclause & " OR state='" & thisstate & "'" NEXT mySQL=mySQL & whereclause Call Query2Table(mySQL,myDSN) %> </body></html> http://www.learnASP.com/learn/stringreplace.asp by Charles M. Carroll Page 151 Replace String Functions by Charles Carroll The various string functions can be used interchangeably often. We will write the same script using SPLIT, REPLACE and JOIN to demonstrate all 3 functions and how they often are used for similar tasks. However, your programming situations may be especially suited for 1 out of 3 of the functions. REPLACE(string,oldvalue,newvalue) results in a string that has all occurences of oldvalue replaced with a newvalue. The user can enter a state or multiple states. We write the program utilizing REPLACE to demonstrate how this function can be used. statereplace.asp 1 2 3 4 5 6 7 8 9 <html><head> <title>statereplace.asp</title> </head><body bgcolor="#FFFFFF"> <form action="statereplacerespond.asp" method="post"> Enter State (or many states separated by <b>,<b><p> <input NAME="states" size="40"><p> <input type="submit" value="Get The Publishers!"> </form> </body></html> statereplacerespond.asp 1 2 3 4 5 6 7 8 9 10 11 <!--#include virtual="/learn/test/lib_dbtable.asp"--> <html><head> <title>statesrespond.asp</title>& <body> <% mySQL="select * from publishers " & whereclause myDSN="DSN=student;uid=student;pwd=magic" tempinput=request("states") whereclause=" where state='" & tempinput 12 13 14 15 16 17 18 19 whereclause=replace(whereclause, ",","' OR state='") whereclause=whereclause & "'" mySQL=mySQL & whereclause response.write mySQL Call Query2Table(mySQL,myDSN) %> </body></html> http://www.learnASP.com/learn/stringjoin.asp by Charles M. Carroll Page 152 JOIN String Functions by Charles Carroll The various string functions can be used interchangeably often. We will write the same script using SPLIT, REPLACE and JOIN to demonstrate all 3 functions and how they often are used for similar tasks. However, your programming situations may be especially suited for 1 out of 3 of the functions. JOIN(array,delimiter) takes an array and converts it to one string with delimiters. The user can enter a state or multiple states. We write the program using the JOIN function to demonstrate how this function can be used. statejoin.asp 1 2 3 4 5 6 7 8 9 <html><head> <title>statejoin.asp</title> </head><body bgcolor="#FFFFFF"> <form action="statejoinrespond.asp" method="post"> Enter State (or many states separated by <b>,<b><p> <input NAME="states" size="40"><p> <input type="submit" value="Get The Publishers!"> </form> </body></html> statejoinrespond.asp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <!--#include virtual="/learn/test/lib_dbtable.asp"--> <html><head> <title>statejoinrespond.asp</title>& <body> <% mySQL="select * from publishers " myDSN="DSN=student;uid=student;pwd=magic" public allstates tempinput=request("states") allstates=split(tempinput,",") whereclause=" where state='" & JOIN(allstates, "' OR state='") & "'" mySQL=mySQL & whereclause response.write mySQL Call Query2Table(mySQL,myDSN) %> </body></html> http://www.learnASP.com/learn/arrays.asp by Charles M. Carroll Page 153 Arrays to store data Part #1 by Charles Carroll Here would be a code sample without arrays: 1 <html><head> 2 <title>arraysnot.asp</title> 3 </head><body bgcolor="#FFFFFF"> 4 <% 5 dim x,y,z 6 7 x=7 8 y=20 9 z=x+y 10 11 response.write z 12 %> 13 </body></html> Here is the same example with arrays 1 <html><head> 2 <title>arrays.asp</title> 3 </head><body bgcolor="#FFFFFF"> 4 <% 5 dim allstuff(3) 6 7 allstuff(0)=7 8 allstuff(1)=20 9 allstuff(2)=allstuff(0)+allstuff(1) 10 11 response.write allstuff(2) 12 %> 13 </body></html> http://www.activeserverpages.com/learn/subdates.asp has a good example of arrays in a practical context. http://www.learnASP.com/learn/arrays2.asp by Charles M. Carroll Page 154 Arrays to store data Part #2 by Charles Carroll Assigning an array size with a variable produces a variable unless the Redim command is used. ● Method #1: You know the size ● 1 2 3 4 5 6 7 8 9 10 11 12 13 Method #2: the size is in a variable <html><head> <title>arraysredim.asp</title> </head><body bgcolor="#FFFFFF"> <% ' this code dim a_array(100) ' this code will fail x=100 dim my_array(x) %> </body></html> Assigning an array size with a variable produces an error unless the Redim command is used. 1 <html><head> 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <title>arraysredimcorrect.asp</title> </head><body bgcolor="#FFFFFF"> <% dim my_array() x=100 redim preserve my_array(x) my_array(20)="Hi!" my_array(40)="How are You" lowcount=lbound(my_array) highcount=ubound(my_array) response.write "lowcount=" & lowcount & ";highcount=" & highcount & "<p>" for counter=lowcount to highcount response.write counter & " " response.write my_array(counter) & "<br>" next %> </body></html> http://www.learnASP.com/learn/arrays3.asp by Charles M. Carroll Page 155 Arrays to store data Part 3 by Charles Carroll There is a code intensive way to load an array and a less intensive one. For example, here is the code intensive one: 1 <html><head> 2 <title>arraysload.asp</title> 3 </head><body bgcolor="#FFFFFF"> 4 <% 5 dim my_months(13) 6 7 my_months(0)="" 8 my_months(1)="Jan" 9 my_months(2)="Feb" 10 my_months(3)="Mar" 11 my_months(4)="Apr" 12 my_months(5)="May" 13 my_months(6)="Jun" 14 my_months(7)="Jul" 15 my_months(8)="Aug" 16 my_months(9)="Sep" 17 my_months(10)="Oct" 18 my_months(11)="Nov" 19 my_months(12)="Dec" 20 21 lowcount=lbound(my_months) 22 highcount=ubound(my_months) 23 response.write "lowcount=" & lowcount & ";highcount=" & highcount & "<p>" 24 for counter=lowcount to highcount 25 response.write my_months(counter) & "<br>" 26 next 27 %> 28 </body></html> Here is the less code intense one: 1 2 3 4 5 6 7 <html><head> <title>arraysloadbest.asp</title> </head><body bgcolor="#FFFFFF"> <% dim my_months my_months=array("Jan","Feb","Mar","Apr", _ 8 9 10 11 12 13 14 15 16 17 18 19 "May","Jun","Jul","Aug", _ "Sep","Oct","Nov","Dec") ' finally here is how you loop through an array lowcount=lbound(my_months) highcount=ubound(my_months) response.write "lowcount=" & lowcount & ";highcount=" & highcount & "<p>" for counter=lowcount to highcount response.write my_months(counter) & "<br>" next %> </body></html> http://www.learnASP.com/learn/dictionary.asp by Charles M. Carroll Page 156 Dictionary objects to store data by Charles Carroll This is how to create and place items into a dictionary objects and display the contents: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <html><head> <title>dictionarybasics.asp</title> </head><body bgcolor="#FFFFFF"> <% set mysample=server.CreateObject("Scripting.Dictionary") mysample.Add "haircolor", "brown" mysample.add "eyecolor" , "blue" mysample.add "dateofbirth", "5/13/64" for each whatever in mysample response.write whatever & "=" response.write mysample.item(whatever) & "<br>" next set mysample=nothing %> </body></html> This is how to make an array of dictionary objects. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <html><head> <title>dictionaryarrays.asp</title> </head><body bgcolor="#FFFFFF"> <% dim people(3) Set people(0) people(0).Add people(0).Add people(0).Add people(0).add people(0).add = server.CreateObject("Scripting.Dictionary") "fname", "Jane" "lname", "Doe" "haircolor", "brown" "eyecolor" , "blue" "dateofbirth", "1/10/60" Set people(1) people(1).Add people(1).Add people(1).Add people(1).Add people(1).add people(1).add = server.CreateObject("Scripting.Dictionary") "fname", "Reginald" "mname", "Elton" "lname", "Dwight" "haircolor", "red" "eyecolor" , "dusty" "dateofbirth", "1/10/60" Set people(2) = server.CreateObject("Scripting.Dictionary") people(2).Add "fname", "Hitoshi" 24 25 26 27 28 29 30 31 32 33 34 35 36 people(2).Add "lname", "Yoshitsugu" ' print out one item for each whatever in people(1) response.write whatever & "=" response.write people(1).item(whatever) & "<br>" next for counter=0 to 2 set people(counter)=nothing next %> </body></html> The dictionary items can be removed individually unlike array elements. See: http://www.activeserverpages.com/docs --> vbscript docs for all the rest of the details about the dictionary object. http://www.learnASP.com/learn/subdates.asp by Charles M. Carroll Page 157 Subroutines - Choosing/Validating Dates by Charles Carroll Subroutines can be used to provide handy date entry list boxes. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <HEAD><TITLE>subdates.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <form action="subdatesrespond.asp"> Depart: <%call showdateform("depart")%> <br> Arrive: <%call showdateform("arrive")%> <input type="submit" value="Ready To Travel"> </form> <% sub showdateform(mylistname) call showmonth(mylistname) call showday(mylistname) call showyear(mylistname) end sub %> <%sub showmonth(listname)%> <select name="<%=listname%>month"> <% dim monthname monthname=array("Jan","feb","Mar","Apr", _ "May","Jun","Jul","Aug", _ "Sep","Oct","Nov","Dec") for counter=0 to 11 temp=monthname(counter) response.write "<option value='" & counter+1 response.write "'>" & temp & "</option>" next%> </select> <%end sub%> <%sub showday(listname)%> <select name="<%=listname%>day"> <%for counter=1 to 31 response.write "<option>" & counter & "</option>" next%> </select> <%end sub%> 42 43 44 45 46 47 48 49 50 51 <%sub showyear(listname)%> <select name="<%=listname%>year"> <%for counter=1964 to 2005 response.write "<option>" & counter & "</option>" next%> </select> <%end sub%> </BODY></HTML> http://www.learnASP.com/learn/subdates2.asp by Charles M. Carroll Page 158 Subroutines - Choosing/Validating Dates #2 by Charles Carroll The form handler for the previous example could validate and manipulate dates using some built-in VBscript date handling routines, for example: ● 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 isdate() to validate a date <HEAD><TITLE>subdatesrespond.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% dday=request.querystring("departday") dmonth=request.querystring("departmonth") dyear=request.querystring("departyear") departdate=dday & "/" & dmonth & "/" & dyear aday=request.querystring("arriveday") amonth=request.querystring("arrivemonth") ayear=request.querystring("arriveyear") arrivedate=aday & "/" & amonth & "/" & ayear If isdate(departdate) then response.write "Departure Date is Valid Date<br>" else response.write "Departure Date is INVALID<br>" end if If isdate(arrivedate) then response.write "Arrival Date is Valid Date<br>" else response.write "Arrival Date is INVALID<br>" end if %> </BODY></HTML> http://www.learnASP.com/learn/subdbtable.asp by Charles M. Carroll Page 159 Query2Table by Charles Carroll Subroutines can save you having to repeat blocks of code. This code illustrates how we can build tables with minimal code in the main script and by including a file with a convenient subroutine. 1 2 3 4 <HEAD><TITLE>subdbtable.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" 5 6 7 8 9 mySQL="select * from publishers" call query2table(mySQL,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> 1 2 3 4 5 6 7 8 9 <HEAD><TITLE>subdbtable2.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mySQL="select * from titles" call query2table(mySQL,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> 1 2 3 4 5 6 7 8 9 <HEAD><TITLE>subdbtable3.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mySQL="select * from authors" call query2table(mySQL,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> 1 2 3 4 5 6 7 8 9 10 11 12 13 <HEAD><TITLE>subdbtable4.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mySQL= "SELECT Publishers.Name, Titles.Title " mySQL= mySQL & "FROM Publishers " mySQL= mySQL & "INNER JOIN Titles ON Publishers.PubID = Titles.PubID " mySQL= mySQL & "order by Name" 1 2 3 4 5 6 7 8 9 <HEAD><TITLE>subdbtable5.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mySQL="select * from title_author" call query2table(mySQL, myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> 1 2 3 4 5 6 7 8 9 <HEAD><TITLE>subdbtable6.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN="DSN=student;uid=student;pwd=magic" mySQL="select name,type from sysobjects" call query2table(mySQL,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> call query2table(mySQL,myDSN) %> <!--#include virtual="/learn/test/lib_dbtable.asp"--> </BODY></HTML> The Include file lib_dbtable.asp looks like this: 1 2 3 4 5 6 <% sub query2table(inputquery, inputDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open inputDSN set rstemp=conntemp.execute(inputquery) 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records do while not rstemp.eof %> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/subdblist.asp by Charles M. Carroll Page 160 Subroutines Query2List by Charles Carroll Subroutines can save you having to repeat blocks of code and can optionally be placed in separate files and included when needed, thus making your pages not appear to have lots of code in-line. 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <TITLE>subdblist.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form> <% theDSN="DSN=student;uid=student;pwd=magic" call query2list("select distinct city from publishers","cy",theDSN) call query2list("select distinct state from publishers","st",theDSN) call query2list("select distinct zip from publishers","zp",theDSN) %> </form> <!--#include virtual="/learn/test/subdblist.inc"--> </body></html> The include file lib_dblist.asp looks like: 1 2 3 4 5 6 7 8 9 10 11 <%sub query2list(myquery,myname,myDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(myquery) %> <Select name="<%=myname%>"> <% do while not rstemp.eof thisfield=trim(RStemp(0)) if isnull(thisfield) or thisfield="" then 12 13 14 15 16 17 18 19 20 21 22 23 24 ' ignore else response.write "<option>" & thisfield & "</option>" end if rstemp.movenext loop %> </select> <%rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/subreusable.asp by Charles M. Carroll Page 161 Subroutines - A "Flexible Approach" by Charles Carroll Subroutines can be very cleverly constructed so that you can use the same routine to power several different tasks instead of copying code as the following examples illustrates! 1 2 3 4 5 6 7 <HEAD><TITLE>subreusabledataform.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/learn/test/subflexible.asp"--> <% call query2entryform("select * from publishers where pubid=16") %> </BODY></HTML> 1 2 3 4 5 6 7 8 9 10 <HEAD><TITLE>subreusabledatalist.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/learn/test/lib_subflexible.asp"--> <% call query2list("select distinct state from publishers","thestate") call query2list("select distinct city from publishers","thecity") call query2list("select distinct zip from publishers","thezip") %> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>subreusabledatatable.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/learn/test/subflexible.asp"--> <% call query2table("select * from publishers") %> </BODY></HTML> 1 2 3 4 5 6 7 <HEAD><TITLE>subreusableform.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/learn/test/subflexible.asp"--> <% call query2form("select * from publishers") %> </BODY></HTML> The library file lib_subflexible.asp looks like: 1 2 3 4 5 <% dim dim dim dim htmlstart, htmlend rowstart, rowend fieldstart, fieldend namestart, nameend 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 dim fieldnames fieldnames=false sub query2list(myquery,listname) htmlstart="<select name='" & listname & "'>" htmlend="</select>" rowstart="<option>" rowend="</option>" fieldstart="" fieldend="" call query2html(myquery) end sub sub query2table(myquery) htmlstart="<table border=1>" htmlend="</table>" rowstart="<tr>" rowend="</tr>" fieldstart="<td valign=top>" fieldend="</td>" call query2html(myquery) end sub sub query2form(myquery) htmlstart="" htmlend="" rowstart="" rowend="<hr>" fieldstart="" fieldend="<br>" fieldnames=true namestart="" nameend=" = " call query2html(myquery) end sub sub query2entryform(myquery) htmlstart="" htmlend="" rowstart="" rowend="" fieldstart="%name% = <input type='text name='%name%' value='" fieldend="' size='%size%'><br>" fieldnames=false namestart="" nameend=" =" call query2html(myquery) end sub sub query2html(inputquery) set conntemp=server.createobject("adodb.connection") conntemp.open "DSN=Student;uid=student;pwd=magic" set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1 redim fsa(howmanyfields) redim fea(howmanyfields) for i = 0 to howmanyfields tempstart=replace(fieldstart,"%name%",rstemp(i).name) tempend=replace(fieldend,"%name%",rstemp(i).name) tempstart=replace(tempstart,"%size%",rstemp(i).actualsize) tempend=replace(tempend,"%size%",rstemp(i).actualsize) fsa(i)=tempstart fea(i)=tempend next response.write htmlstart & vbcrlf counter=0 do until rstemp.eof 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 response.write rowstart & vbcrlf for i = 0 to howmanyfields if fieldnames=true then response.write namestart & rstemp(i).name & nameend end if response.write fsa(i) & rstemp(i) & fea(i) & vbcrlf next response.write rowend & vbcrlf counter=counter+1 rstemp.movenext if response.isclientconnected=false then exit do end if loop rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing response.write htmlend end sub %> http://www.learnASP.com/learn/subDBlistbest.asp by Charles M. Carroll Page 162 Subroutines Db2list "Best" Approach by Charles Carroll Subroutines could be considerably more useful if they took optional parameters. Since they don't we can jury rig a system whereby a subroutine is invoked with two parameters: a delimiter and a string. And the string itself contains the various parameters. This approach implements a more optional parameter "like" solution. 1 <html><head> 2 <TITLE>subdblistbest.asp</TITLE> 3 </head><body bgcolor="#FFFFFF"> 4 <form> 5 <%call db2list("^","select distinct city from publishers^city^New York")%> 6 <%call db2list("^","select distinct state from publishers^state^NY^table^DSN=student;uid=student;pwd=magic")%> 7 <%call db2list("^","select distinct zip from publishers^Zip Code^^table")%> 8 </form> 9 <!--#include virtual="/learn/test/lib_dblistbest.asp"--> 10 The include file lib_dblistbest.asp looks like: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <% sub db2list(mydelim,myparm) dim myparameters myparameters=SPLIT(myparm,mydelim) parmcount=ubound(myparameters) myquery=myparameters(0) label=myparameters(1) default=myparameters(2) if parmcount>2 then format=lcase(myparameters(3)) end if if parmcount>3 then connstring=myparameters(4) else connstring="DSN=Student;uid=student;pwd=magic" end if 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 set conntemp=server.createobject("adodb.connection") conntemp.open connstring set rstemp=conntemp.execute(myquery) If format="table" then%> <table width="100%" border="0" cellspacing="1"><td> <%end if response.write label If format="table" then%> </td><td> <%end if%> <Select> <option value="<%=default%>" selected><%=default%></option> <% do while not rstemp.eof %> <option><%=RStemp(0)%></option> <% rstemp.movenext loop conntemp.close %> </select> <%If format="table" then%> </td><tr></table> <%end if end sub%> http://www.learnASP.com/learn/libhtml.asp by Charles M. Carroll Page 163 Library of HTML Commands by Phil Paxton ©1999 by Phil Paxton (phil@matchw.com) Subroutines and Functions can be used, for example, to provide a layer of abstraction over HTML. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!--#include virtual="/learn/test/lib_htmlstuff.asp"--> <html><head> <title>libhtmldemo.asp by Phil Paxton</title>& <body> <form action="lib_htmldemorespond.asp"> <% Call Form_TextBox("first name","Fname",20,20,"") response.write "<br>" Call Form_TextBox("Last Name","Lname",20,20,"") response.write "<br>" Call Form_TextBox("City","cy",20,20,"") response.write "<br>" Call Form_TextBox("State","st",2,2,"") response.write "<br>" Call Form_TextBox("Zip Code","zp",10,10,"") response.write "<br>" Call Form_SubmitButton("Register Me","register") %> </form> </body> </html> The library that enables this (named lib_htmlstuff.asp) looks like: 1 2 3 4 <% Sub Display( Text ) Response.Write( Text ) End Sub 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 '---------------------------------------------------------------Sub HTML( Text ) Response.Write( Text ) End Sub '---------------------------------------------------------------Sub Test( Text ) Response.Write( Text ) End Sub '---------------------------------------------------------------Sub Form_HiddenField( Name, Value ) HTML "<INPUT " Form_Parm_Type "Hidden" Form_Parm_Name Name Form_Parm_Value Value HTML ">" End Sub '---------------------------------------------------------------Sub Form_Label( Label, Control ) If Len(Label) > 0 Then HTML "<label " HTML "for=" & Control HTML ">" HTML "<strong>" Display Label HTML "</strong>" HTML "</label>" End If End Sub '---------------------------------------------------------------Sub Form_TextBox( Label, Name, MaxLength, Size, Value ) Form_Label Label, Name HTML "<input " Form_Parm_Type "text" Form_Parm_Name Name Form_Parm_Size Size Form_Parm_ID Name Form_Parm_MaxLength MaxLength Form_Parm_Value Value HTML ">" End Sub '---------------------------------------------------------------Sub Form_Password( Label, Name, MaxLength, Size, Value ) Form_Label Label, Name HTML "<input " Form_Parm_Type "password" Form_Parm_Name Name 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 Form_Parm_Size Size Form_Parm_ID Name Form_Parm_MaxLength MaxLength Form_Parm_Value Value HTML ">" End Sub '---------------------------------------------------------------Sub Form_ScrollingText( Label, Name, Rows, Cols, Value ) Form_Label Label, Name HTML "<textarea " Form_Parm_Name Name If Len(Rows) > 0 Then HTML "rows=" & Rows & " " End If If Len(Cols) > 0 Then HTML "cols=" & Cols & " " End If Form_Parm_ID Name HTML ">" If Len(Value) > 0 Then Display Value End If HTML "</textarea>" End Sub '---------------------------------------------------------------Sub Form_ResetButton( Name, Value ) HTML "<input " Form_Parm_Type "reset" Form_Parm_Value Value Form_Parm_Name Name HTML ">" End Sub '---------------------------------------------------------------Sub Form_CommandButton( Name, Value ) HTML "<input " Form_Parm_Type "button" Form_Parm_Value Value Form_Parm_Name Name HTML ">" End Sub '---------------------------------------------------------------Sub Form_SubmitButton( Name, Value ) HTML "<input " Form_Parm_Type "submit" Form_Parm_Value Value Form_Parm_Name Name HTML ">" End Sub 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 '---------------------------------------------------------------Sub Form_RadioButton( Label, Name, Value, Checked ) HTML "<input " Form_Parm_Type "radio" Form_Parm_Value Value Form_Parm_Name Name Form_Parm_ID Name & Value If Len(Checked) > 0 Then If Checked Then HTML " checked " End If End If HTML ">" Form_Label Label, Name & Value End Sub '---------------------------------------------------------------Sub Form_Checkbox( Label, Name, Value, Checked ) Form_Label Label, Name HTML "<INPUT " Form_Parm_Type "checkbox" Form_Parm_Name Name Form_Parm_Value Value If Len( Checked ) > 0 Then If Checked = True Then HTML " checked " End If End If HTML ">" ' End Sub '---------------------------------------------------------------Sub Form_Begin( Action ) HTML HTML HTML HTML "<form " "method=post " "action =" & Chr(39) & Action & Chr(39) & " " ">" End Sub '---------------------------------------------------------------Sub Form_End( Name, Value ) Form_HiddenField Name, Value HTML "</FORM>" End Sub '---------------------------------------------------------------Sub Form_Table_Begin( Border, Width ) HTML "<table " If Len(Border) > 0 Then HTML "border=" & Chr(39) & Border & Chr(39) & " " End If Form_Parm_Width Width 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 HTML ">" End Sub '---------------------------------------------------------------Sub Form_Table_End() HTML "</table>" End Sub '---------------------------------------------------------------Sub Form_Table_Row_Begin( Dummy, Align, VAlign ) HTML "<tr " Form_Parm_Align Align Form_Parm_VAlign VAlign HTML ">" End Sub '---------------------------------------------------------------Sub Form_Table_Row_End( Dummy ) HTML "</tr>" End Sub '---------------------------------------------------------------Sub Form_Table_Cell_Begin( Dummy, Width, Align, VAlign ) HTML "<td " Form_Parm_Width Width Form_Parm_Align Align Form_Parm_VAlign VAlign HTML ">" End Sub '---------------------------------------------------------------Sub Form_Table_Cell_End( Dummy ) HTML "</td>" End Sub '---------------------------------------------------------------Sub Form_ComboBox_Begin( Label, Name, Size, Multiple ) Form_Label Label, Name HTML "<select " Form_Parm_Name Name Form_Parm_Size Size If Len(Multiple) > 0 Then If Multiple Then HTML " multiple " End If End If HTML ">" End Sub '---------------------------------------------------------------Sub Form_ComboBox_Item( Value, Selected ) HTML "<option " Form_Parm_Value Value If Len(Selected) > 0 Then If Selected Then HTML " selected " End If 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 End If HTML ">" End Sub '---------------------------------------------------------------Sub Form_ComboBox_End() HTML "</select>" End Sub '---------------------------------------------------------------Sub Form_Title( Title ) HTML "<title>" Display Title HTML "</title>& End Sub '---------------------------------------------------------------Sub Form_Center( Text ) HTML "<p align=" & Chr(39) & "center" & Chr(39) & ">" Display Text HTML "</p>" End Sub '---------------------------------------------------------------Sub Form_Left( Text ) HTML "<p align=" & Chr(39) & "left" & Chr(39) & ">" Display Text HTML "</p>" End Sub '---------------------------------------------------------------Sub Form_Right( Text ) HTML "<p align=" & Chr(39) & "right" & Chr(39) & ">" Display Text HTML "</p>" End Sub '---------------------------------------------------------------Sub Form_Parm_Align( Align ) If Len(Align) > 0 Then Select Case UCase(Align) Case "L", "LEFT" Display " align=" & Chr(39) & "left" & Chr(39) & " " Case "C", "CENTER" Display " align=" & Chr(39) & "center" & Chr(39) & " " Case "R", "RIGHT" Display " align=" & Chr(39) & "right" & Chr(39) & " " Case Else End Select End If End Sub '---------------------------------------------------------------Sub Form_Parm_VAlign( VAlign ) If Len(VAlign) > 0 Then Select Case UCase(VAlign) Case "T", "TOP" Display " align=" & Chr(39) & "top" & Chr(39) & " " Case "C", "CENTER" 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 Display " align=" & Chr(39) & "center" & Chr(39) & " " Case "B", "BOTTOM" Display " align=" & Chr(39) & "bottom" & Chr(39) & " " Case Else End Select End If End Sub '---------------------------------------------------------------Sub Form_Parm_Name( Name ) If Len(Name) > 0 Then Display " name=" & Chr(39) & Name & Chr(39) & " " End If End Sub '---------------------------------------------------------------Sub Form_Parm_Value( Value ) If Len(Value) > 0 Then Display " value=" & Chr(39) & Value & Chr(39) & " " End If End Sub '---------------------------------------------------------------Sub Form_Parm_Type( TypeValue ) If Len(TypeValue) > 0 Then Display " type=" & Chr(39) & TypeValue & Chr(39) & " " End If End Sub '---------------------------------------------------------------Sub Form_Parm_Size( Size ) If Len(Size) > 0 Then Display " size=" & Size & " " End If End Sub '---------------------------------------------------------------Sub Form_Parm_ID( ID ) If Len(ID) > 0 Then Display " id=" & Chr(39) & ID & Chr(39) & " " End If End Sub '---------------------------------------------------------------Sub Form_Parm_MaxLength( MaxLength ) If Len(MaxLength) > 0 Then Display " maxlength=" & MaxLength End If End Sub '---------------------------------------------------------------Sub Form_Parm_Length( Length ) If Len(Length) > 0 Then Display " length=" & Length End If End Sub '---------------------------------------------------------------Sub Form_Parm_Width( Width ) 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 If Len(Width) > 0 Then Display " width=" & Width End If End Sub '---------------------------------------------------------------Sub Anchor_Display( TextToDisplay, HRef ) HTML "<a href=" & Chr(39) & HRef & Chr(39) & ">" Display TextToDisplay HTML "</a>" End Sub '---------------------------------------------------------------Sub MenuItem ( TextToDisplay, HRef ) HTML "<ul>" HTML "<li>" HTML "<p " Form_Parm_Align "Left" Form_Parm_VAlign "Bottom" HTML ">" Anchor_Display TextToDisplay, HRef HTML "</p>" HTML "</li>" HTML "</ul>" End Sub '---------------------------------------------------------------Function FormatMoney( Amount ) ' ' Standard constants from the MS web site but not built ' into VBScript's default constants. ' Const TristateTrue = -1 Const TristateFalse = 0 Const TristateUseDefault = -2 ' If IsNull( Amount ) Then FormatMoney = vbNullString Else FormatMoney = FormatCurrency( Amount, 2, TristateTrue _ , False, TristateTrue) End If ' End Function '---------------------------------------------------------------%> http://www.learnASP.com/learn/functionworkingdays.asp by Charles M. Carroll Page 164 Functions -- The WorkingDays function This page demonstrates how to make a function and display it's results in your page. 1 2 3 4 5 <title>functionworkingdays.asp</title> <body bgcolor="#FFFFFF"> <% response.write "3 working days from today is " & dtaddWorkingDays(now(),3) & "<p>" %> 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 2 working days from today is <%=dtaddWorkingDays(now(),2)%> </body> <%Function dtAddWorkingDays(dtStartDate, nDaystoAdd) 'Adds working days based on a five day week Dim dtEndDate Dim iLoop 'First add whole weeks dtEndDate=DateAdd("ww",Int(nDaysToAdd/5),dtStartDate) 'Add any odd days For iLoop = 1 To (nDaysToAdd Mod 5) dtEndDate=DateAdd("d",1,dtEndDate) 'If Saturday increment to following Monday If WeekDay(dtEndDate)=vbSaturday Then 'Increment date to following Monday dtEndDate=DateAdd("d",2,dtEndDate) End If Next dtAddWorkingDays=dtEndDate End Function %> http://www.learnASP.com/learn/vbs5.asp by Charles M. Carroll Page 165 VBScript 5 Highlights by Charles Carroll Subroutines can save you having to repeat blocks of code. This code illustrates how we can build tables with minimal code in the main script and by including a file with a convenient subroutine. Eval function 1 2 3 4 5 6 7 8 9 10 <html><head> <title>vbs5eval.asp</title> </head> <body> <% x="2+2*3" response.write eval(x) %> </body> </html> Classes: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <html><head> <title>vb5classes.asp</title> </head> <body> <% ' Create a myCustomer variable Dim myCustomer ' Create a new instance of the Customer Class ' and set the value of myCustomer to be that instance set myCustomer = new Customer ' Add a new customer myCustomer.Add "Charles","Carroll" ' Set their Email address myCustomer.EmailName = "charlescarroll@aspalliance.com" ' Set their credit limit myCustomer.CreditLimit = 5000 ' Display the customers fullname 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 response.write myCustomer.FullName Class Customer Public FirstName, LastName Private nCreditLimit Private strEmailName Property Get EmailName EmailName = strEmailName End Property Property Let EmailName ( strName) StrEmailName = strName End Property Property Get FullName FullName= FirstName & " " & LastName End Property Property Let CreditLimit ( s ) if s >= 0 then nSalary = s End If End Property Property Get CreditLimit Salary = nSalary End Property Sub Add( First, Last ) FirstName = First LastName = Last End Sub Function RaiseCreditLimit( Amount ) nCreditLimit = nCreditLimit + Amount RaiseSalary = nSalary End Function End Class %> </body> </html> Execute Function: 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <title>vbs5execute.asp</title> </head> <body> <% S = "Sub Hi" & vbCrLf S = S & " Response.write ""Hi""" & vbCrLf S = S & "End Sub" Execute S Call Hi() %> </body> </html> Regular Expressions 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <title>vbs5reg.asp</title>& <body> <% address="joe@aol.com" validmail=checkemail(address) IF validmail THEN response.write address & " is good!" ELSE response.write address & " is bad!" END IF 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 address="sallyaol.com" validmail=checkemail(address) IF validmail THEN response.write address & " is good!" ELSE response.write address & " is bad!" END IF FUNCTION CheckEmail(parmaddress) set myRegExp = new RegExp ' Set the pattern to check for a word followed by ' an @ followed by a word myRegExp.pattern = "\w+\@[.\w]+" if myRegExp.Test(parmaddress) then CheckEmail=True else CheckEmail=false end if END FUNCTION %> </body> </html> With 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <title>vbs5with.asp</title> </head> <body> <% with response .write "Hi<br>" .write "how are you doing?<br>" .write "see you around" end with %> </body> </html> http://www.learnASP.com/learn/editors.asp by Charles M. Carroll Page 166 Visual Interdev + Admunsen Resources (admunsen.asp) - Page 167 ASPExpress: HOT ASP Editor (aspexpress.asp) - Page 168 Homesite: HTML editor (homesite.asp) - Page 169 http://www.learnASP.com/learn/admunsen.asp by Charles M. Carroll Page 167 Interdev Guru Michael Amundsen is the first place you should go with Interdev questions. http://www.amundsen.com/vinterdev/join/vi6talk.htm is his awesome Visual Interdev listserve. One of the best in the world. http://www.amundsen.com/mskb/Default.htm is his knowledge base Assistant. He offers Interdev Training, see: http://www.amundsen.com/training/default.htm There is a healthy assortment of FREE stuff there too. http://www.learnASP.com/learn/aspexpress.asp by Charles M. Carroll Page 168 ASPExpress - ASP Editor This is a very ASP centric HTML editor. Unlike homesite which claims ASP functionality but doesn't have it, or wizard/DTC based beasts like Visual Interdev this tool truly helps you write ASP Code with: ● The Connection Assistant ● The Request Assistant ● buttons that make CASE, IF, LOOPs for you ● Browsing for includes I personally use it instead of Visual Interdev. Take a look at the screenshots @ http://www.aspexpress.com/screenShots/screenshots.asp Of course I am biased, because the author is a student of mine (we hold classes, see www.asptraining.com) and whenever I send him a dozen items no ASP editor does and I want, within a month or two, a new editor arrives with all the nifty features I dreamed of. http://www.aspexpress.com is the place to get it. You will be blown away by the phenomenal tools that no other editor has to make ASPy tasks a snap. http://www.learnASP.com/learn/homesite.asp by Charles M. Carroll Page 169 Homesite - Popular HTML Editor This is a very popular HTML editor from http://www.allaire.com/products/homesite/ I don't like it as much as ASPExpress but if you are using it with ASP I recommend checking out: http://jw.conallen.net/asp4hs/ which focuses on how people using Homesite can edit their ASP scripts even easier. http://www.learnASP.com/learn/speedscale.asp by Charles M. Carroll Page 170 Application Data (sessionsapps.asp) - Page 171 Application Data: Worlds Fastest ListBox (speedappdata.asp) - Page 172 Sessions: What are they? (sessionswhat.asp) - Page 173 Sessions: Global.asa Events (global.asp) - Page 174 Session Overview & Myths (sessionoverview.asp) - Page 175 Sessions: Global.asa and Scalability (globalproblems.asp) - Page 176 Global.asa Resources (globalmore.asp) - Page 177 Speed: Server Optimization (speedserver.asp) - Page 178 Speed: Research Online (speedresearch.asp) - Page 179 Time Tasks with Millisecond Accuracy (speedtimer.asp) - Page 180 Speed: Coding Tips (speedtips.asp) - Page 181 Speed: Database Percieved Speed (speedtables.asp) - Page 182 Speed: Database Retrieval Speed (speedtablesall.asp) - Page 183 Speed: OLEDB & ODBC Drivers differences (speedtablesdrivers.asp) - Page 184 Scale: IsClientConnected & Stray Tasks (isclientconnected.asp) - Page 185 Scale: Virtues of Nothing (nothing.asp) - Page 186 Scale: Connection Pooling (dbpooling.asp) - Page 187 Thread Safety Issues (threadsafe.asp) - Page 188 Round-Robin Code Execution (roundrobin.asp) - Page 189 Why Buffer? (whybuffer.asp) - Page 190 Why GetRows or Getstring to get Data (whygetrows.asp) - Page 191 ASP Scalability Listserver (aspscalability.asp) - Page 192 http://www.learnASP.com/learn/sessionsapps.asp by Charles M. Carroll Page 171 Application Variables by Charles Carroll There are two kinds of data that your program can manipulate that can be used to "remember" data: Session data which is "attached" to a person browsing your site. If the same page is accessed by 12 different users each user may have totally different session values. Application data which is attached to the webserver and is the same no matter which user is accessing the site. Application values are visible to every user. But since, unlike session data, any web page could change the application's data there is a potential concurrency issue. The lock and unlock method of the application object eliminate concurrency issues. Once an application is locked, no other updates to the application object can occur until the unlock is executed. One use for an application variable would be to store variables most scripts on a site needed to access or even HTML cached from databases like in The Worlds Fastest Listbox Example @ http://www.learnasp.com/learn/speedappdata.asp One example I use to illustrate the conceptual use for each type of data would be a website that simulated a casino. Player's individual winnings make perfect sense to maintain in session variables. However, the total number of players at each "virtual table" (blackjack, roulette, etc.) would be application data as the would be the same regardless of an individual player's status. Here is a file called appblackjackarrive.asp that could be included in any script where someone arrived at the blackjack table! 1 2 3 4 5 <% response.write "Welcome to the BlackJack Table<br>" application.lock application("bjplayers")=application("bjplayers")+1 application.unlock 6 7 response.write "There are " & application("bjplayers") & " players here!<br>" %> Here is a file called appblackjacklook.asp that displays how many people are at the table. 1 2 3 4 <% response.write "Over at the BlackJack Table<br>" response.write "There are " & application("bjplayers") & " players there!<br>" %> Here is a file called appblackjackleave.asp that could be included in any script where someone left the blackjack table! 1 2 3 4 5 6 7 8 9 10 <% response.write "Thanks for playing BlackJack!<br>" application.lock application("bjplayers")=application("bjplayers")-1 IF application("bjplayers")<0 THEN application("bjplayers")=0 END IF application.unlock response.write "There are " & application("bjplayers") & " players still at the table!<br>" %> http://www.learnASP.com/learn/speedappdata.asp by Charles M. Carroll Page 172 Speed Data Display w/Application Data by Charles Carroll Sometimes data (like a HTML list box) is displayed on many pages of a website. In fact, the database generated list box is displayed thousands of times a day, and the database is queried every time, but it is uneccessary. The database it is drawn from is not changing thousands of times a day. In the following example any page that displays the listboxes needs to only access the application variables, not hit the database. Very speedy. If the data changes or gains new records, a trigger mechanism could invoke listmake.asp. Here is a demo script that displays the listboxes without requerying the database. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <HTML> <TITLE>listmakedemo.asp</TITLE> <body bgcolor="#FFFFFF"> </BODY> <% IF application("citylist")="" OR _ application("statelist")="" OR _ application("ziplist")="" THEN%> <!--#include virtual="/learn/test/listmake.asp"--> <%END IF response.write application("citylist") & "<br>" response.write application("statelist") & "<br>" response.write application("ziplist") & "<br>" %> </HTML> The listbox could be placed in an application variable, ala a "generator" script we will call listmake.asp. 1 2 3 4 5 6 7 8 9 10 <HTML> <TITLE>listmake.asp</TITLE> <body bgcolor="#FFFFFF"> </BODY> <% myDSN="DSN=student;uid=student;pwd=magic" mySQL="select distinct city from publishers" application("citylist")=query2htmlist(mySQL,"cities",myDSN) 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 mySQL="select distinct state from publishers" application("statelist")=query2htmlist(mySQL,"state",myDSN) mySQL="select distinct zip from publishers" application("ziplist")=query2htmlist(mySQL,"zip",myDSN) %> </HTML> <%function query2htmList(myquery,myname,myDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(myquery) query2HTMlist="<Select name='" & myname & "'>" do until rstemp.eof thisfield=trim(RStemp(0)) if isnull(thisfield) or thisfield="" then ' ignore else query2HTMlist=query2HTMlist & "<option>" & thisfield & "</option>" end if rstemp.movenext loop query2HTMlist=query2HTMlist & "</select>" rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end function%> http://www.learnASP.com/learn/sessionswhat.asp by Charles M. Carroll Page 72 What are Sessions? Sessions are a very convenient ASP feature. When someone visits a web page on your site, ASP calls that a "session" and immediately can differentiate that user from all other users at a site. Anything stored in that user's session can be retrieved and manipulated from that page and the next pages they visit, and the data will be tied to that user. Session data is generally attached to one user. When a user visits their first page of your site, that page and every page they visit is collectively called a session. Any data attached stored in that session object is private to the pages that user is visiting. The code to store data in a session variable is simple. Here we will allow a user to flip a coin, i.e. flipcoin.asp and count their successes: 1 2 3 4 5 6 7 8 9 10 11 12 <% response.write "Coin Tossed!<br>" randomize randomnum=int(rnd*2)+1 IF randomnum=1 THEN session("heads")=session("heads")+1 ELSE session("tails")=session("tails")+1 END IF response.write "Heads= " & session("heads") & "<br>" response.write "Tails= " & session("tails") & "<br>" %> Even though there are many people at the site they all have different scores for their "heads" and "tails" count. They each has a session and it co-ordinates and differentiates their values. A much more practical example could protect access to a page based on a session variable that indicated their security level determined once upon login, see: http://www.learnasp.com/learn/security.asp Some basic things should be noted: ● Session data is stored on the server, not in cookies. No user could examine the session cookie and determine the contents of any session variables. ● A cookie is used to co-ordinate the user's session ID. Once again the cookie contains no data (just the session ID). This means if the user accepts no cookies, you can't use sessions as described here. ● If you absolutely need sessions without client cookies, installing an ISAPI filter named "Cookie Munger" will solve your problem, but at a performance penalty. Cookie Munger by Microsoft (FREE) Cookies are a necessity to maintain ASP session objects. Even though the session objects are physically maintained on the server the essential ID that identifies a user session is kept in a cookie. This ISAPI filter can only be applied globally but if applied, it actually rewrites any pages sent back to the user so that any URLs in the page will pass back user session info without any cookies involved. Basically (at a performance penalty) it transforms every page sent to the client to encode the session ID as part of the URLs on the page. So conceptually if you send a page back to the users with 20 URLs each URL gets a session ID "munged"/intermixed in so that when they click on the URL you have enough info to Identify them without writing a cookie to their machine. [../trash/msfree.asp] %> http://www.learnASP.com/learn/global.asp by Charles M. Carroll Page 174 Global.asa Events by Charles Carroll This page demonstrates what a blank global.asa should look like: 1 2 3 4 5 6 7 8 9 10 11 12 13 <script language=vbscript runat=server> SUB Application_OnStart END SUB SUB Application_OnEnd END SUB SUB Session_OnStart END SUB SUB Session_OnEnd END SUB </script> A global.asa code is divided into four events, or segments: ● session_onstart if 100 users hit your website for example, 100 session starts are initiated and the code in this event is fired for each user before their first page is fetched and displayed. But those same 100 users can wander all over your site and another session start will not occur as long as they are actively fetching pages ● session_onend Any user that does not fetch any page from your site for 20 minutes (can be adjusted in the Registry/IIS3 or the metabase/IIS4) has ended their session. The code you put in this event can not affect the users as they have already left your site but it can allow you to place cleanup code or code that dumps for, example, session data into a database. ● application_onstart The webserver starts. dozens to hundreds to thousands of users hit the site. The minute the first user fetches the first file in an application directory an application_onstart occurs and never occurs again no matter how many people are visiting. But if a webserver stops and starts and application_onstart fires. But code inside an application_onstart is code that assumes the entire casino is a "blank slate" not a busy place. If for example, application_onstarts fire often this is not a desired behavior since it may have the role of bootsrapping an app and setting certain conditions that don't make sense to set while activity is occuring. ● application_onend The web server stops, the application ends. http://www.learnASP.com/learn/sessionoverview.asp by Charles M. Carroll Page 175 Session Overview & Myths by Charles Carroll Session data is greatly misunderstood. Sessions themselves were a subtle and complex issue, but the subject was confused considerably by bad information people gathered from code others made that misused sessions. It is also confused by anecdotal performance evidence when a site is small, or the testing is only done within simple stress tests that don't reveal all the speed issues. We will clarify it all now. A couple analogies may help. A Porsche seems really fast to get anywhere (of course we assume you have 2 passengers) until you have 3-10 passengers. Then a mini-van will beat it because you have less trips to make. In client-server terms the Porsche doesn't SCALE WELL for more than 2 passengers. On the other hand, when a group of 100 wants to go to Atlantic city for the weekend we recommend a Tour Bus. However, someone taking a Tour Bus to the grocery store has anecdotal evidence it is not as fast as a Porsche. Fact #1: When a browser window closes, the session DOES NOT end. Fact #2: <%session.abandon%> command can end a session. Fact #3: Another way a session ends is when a user has not visited any page within that site/application with ___ minutes. The default is 20 minutes of inactivity. The following script can show what the settings are on your server: 1 <html><head> 2 <TITLE>sessionsettings.asp</TITLE> 3 </head> 4 <body bgcolor="#FFFFFF"> 5 <% 6 response.write "Session Timeout=" & session.timeout & "minutes <br>" 7 %> 8 </body></html> Fact #4: Session ids are not guaranteed to be different anytime a new session is generated. If there are 1,000 sessions there will be 1,000 unique session ids. But if 200 people loose session (due to timeout or explicit .abandon) and 150 new sessions are begun ASP may and will certainly use the same session IDs it was using earlier. Myth #1: Storing large objects (recordsets, database data, objects) users access in sessions saves memory*. No. No. No. Since sessions start when users access one page and don't end until 20 minute after they access the last page. Think about it. If 200 news persons a minute hit your site for 5 minutes that is 1,000 sessions and appropriately 1000 x the memory consumed for session variables. If 500 people go away, you still have 1000 sessions and 500 users (twice as much memory is consumed as needed) until the server detects 20 minutes of inactivity for those 500 users who are not on the site. Application variables (not session variables) can be used this way without wasting memory. They could be to store variables most scripts on a site needed to access or even HTML cached from databases like in The Worlds Fastest Listbox Example @ http://www.learnasp.com/learn/speedappdata.asp Myth #2: Storing large objects (recordsets, database data, objects) users access in sessions speeds up access. No. No. No. Objects in sessions have several potential speed barriers depending on their memory model. ● Thread local storage is used internally in some objects (notably VB components). This means once you assign such a component to a session variable attached to that user all user request must remain on the thread they started on. If they for example were assigned Thread #3 upon their session start as they access many pages at the site all their activity will remain on thread #3. I nickname this phenomena Thread Locking. ● Free-threaded objects have no speed barriers (though as Myth #1 states, you will always have too many in memory if you store objects as session variables). ● Apartment-Threaded objects, notably VB components and the Microsoft Access databas driver which are Single-Threaded apartments (STA) have some performance limits. Simply put, every user request to a STA object must be serialized. Serialization explained: If 100 users hit the site their use of that code is in sequence. If all the users retrieves 10-20 records from a database you might notice no effect. But if person 3 retrieves 2,000 records, person 4 retrieving 2 records will occur after the person 3 retrieves 2,000 records. OUCH!!!!! Person 4 will think the webserver is very slow only retrieving 2 records. Free-Threading explained: Users execution is more round-robin like where the webserver does not have to finish each users request before moving to another user. The code may be able to move to User 4 and grab their records and then person 5 and later finish person 3's large request. Threads explained: Your web server spawns threads (4 per CPU is the default in IIS4; it should be adjusted to 20 see http://www.learnasp.com/learn/speedserver.asp. If your webserver had for example 4 threads, then 1000 users might be 250 per thread or 700 on one thread and 100 each on the other threads. The latter is a severe imbalance as one thread is overworked (thus slower) while other threads are underworked. http://www.learnASP.com/learn/globalproblems.asp by Charles M. Carroll Page 176 Global.asa Overkill by Charles Carroll A global.asa file is a used extraneously and quite wastefully, but can be a very useful tool. First let us bring out what is good and bad about it. Application variables are good. Since there is only one application variable in memory, no matter how many users are on your site, they can be a convenient place to store central information and retrieve it fast. Since there is only one application variable in memory regardless of the number of users at your site, remember the following characteristics: ● Of course Application variables have no dependence on cookies. They are not required at all. ● If a object or variable is accessed concurrently for anything other than reading it's value, this is a potential concurrency issue that needs to be carefully coded so that no problems arise, i.e. <% application.lock ... modify app object ... application.unlock %> Session variables (particularly COM objects put in a session variable) can: ● waste memory because they live for ___ minutes past their last use. ___ depends on your session. timeout, the default is 20 minutes. See /learn/nosessionobjects.asp for more details. ● waste threads if you put any objects (made with server.createobject) in a session variable. See /learn/buildvbthreads.asp for more details. ● limit the code to users accepting cookies which may mean someone who disables cookies may not use that script at all. Session Variable Constraints Session variables containing simple variables (texts, numbers, dates, NOT COM objects) are not so wasteful as to be prohibitive. BUT remember, if you write any script that depends on session variables you are working under the following assumptions (and if these restrictions are fine, then use sessions as much as you need to): ● the person browsing your site MUST enable cookies for your script to function. ● If your site is one giant application (i.e. the root folder is marked as an application) the person browsing the site will have access to their session variables in every script BUT if individual folders are marked as applications, all scripts within that directory set session variables that cannot be read from scripts in other folders marked as applications. In other words three folders: \A, \B and \C can set session variables but cannot see each others. If your goal with a session is to attach people to data and use it in many scripts this visibility can be an issue. ● the person using the scripts will never gets "switched" to another server in a web farm situation. If the task could be accomplished with hidden fields instead of session variables, then those limitations are not in effect -- and most tasks can. Good uses of global.asa and session data include: ● if you place any value in an Application_OnStart event that sets application variables, this is not wasteful and can be quite useful. ● If you place any non-object data in session variables the waste is not excessive. Examples of Wasteful Code and Alternatives... Code that is particularly wasteful is code that places database connection info in the global.asa, i.e. session_onstart session("dbname")="DSN=employees;" session("dbuser")="whoever" session("dbpass")="majic" end sub and the script that goes with it looks like this: ... code .... set conntemp=server.createobject("adodb.connection") conntemp.open session("dbname") & "uid=" & session("dbuser") & ";pwd=" & session("dbpass") ... code .... Why? Do 700 users hitting that site hit 700 different databases with 700 different userids and passwords at the database level. Just 700 wasted session variables...Session variables are the worst way to keep such data; application variables the best or other mechanisms. Unfortunately Visual Interdev grossly misuses sessions and creates this bizzare concept in people's brains. If for example, 700 users connect to a page using session variables to store DSN info, etc. You have 700 DSN variables in memory all with the same value. The purpose of sessions is to have separate data for users not the same data replicated for every session. Plus it means the site is unusable to a user not accepting cookies unnecessarily. It is really necessary to require cookies to display a database page where the DSN to the database does NOT change over a multi-month/year period? The better alternatives would be: Include Files (cheap and easy) lib_connection.asp <% dbname="DSN=employees;" dbuser="whoever" dbpass="majic" %> and the script that goes with it looks like this: <!--#include virtual="/lib_connection.asp"--> ... code .... set conntemp=server.createobject("adodb.connection") conntemp.open dbname & "uid=" & dbuser & ";pwd=" & dbpass ... code .... Application Data (involves a COM object, but is memory cheap) application_onstart application("dbname")="DSN=employees;" application("dbuser")="whoever" application("dbpass")="majic" end sub and the script that goes with it looks like this: ... code .... set conntemp=server.createobject("adodb.connection") conntemp.open application("dbname") & "uid=" & application("dbuser") & ";pwd=" & application("dbpass") ... code .... In both approaches, if 700 users hit the site, no user specific variables are created. The same three variables are available to all users with no wasted memory. http://www.learnASP.com/learn/globalmore.asp by Charles M. Carroll Page 177 Global.asa, Sessions, Custom Stats Resources The global.asa, application and sesion variables are certainly a more complex and controversial subject than most ASP topics. Other sites and my site has a lot to say on this: Everything you wanted to know about global.asa but were afraid to ask @ http://www.4guysfromrolla.com/webtech/113098-1.shtml The lowdown on Global.asa, session vars and app. vars http://www.asp101.com/resources/apps_sessions_gasa.asp An example of home-brewed stats: http://www.asp101.com/resources/active_users.asp Steve Smith's Stats examples: http://www.aspalliance.com/stevesmith/samples/whosoncode.asp http://www.aspalliance.com/stevesmith/samples/sitestats.asp http://www.learnASP.com/learn/speedserver.asp by Charles M. Carroll Page 178 Server Optimization by Charles Carroll Improving server performance is not so well documented and many of the articles lean towards vague, not specific tips. Here are our tips in we hope as concrete a way as possible. THREAD TIP: Increase threads per processor from 4 to 20 for each CPU. thanks to Smiling Jack for this one: http://www.aspmagazine.com/aspmagazine/issue10kb.asp see http://support.microsoft.com/support/kb/articles/q196/0/16.asp Implement the ADOFre15.reg file! If you don't use Access, run ADO as FREE THREADED instead of both. more details at: http://msdn.microsoft.com/workshop/server/components/daciisperf.asp WARNING: Access or any STA driver will not function well and may corrupt data. Do not make this change if you are running any Access code in the box. Additional Research We have essentially summarized the information and chosen only the clearest guidelines from the following resources: Web Application Stress Tool http://homer.rte.microsoft.com Improving the Performance of Data Access Components with IIS 4.0 http://msdn.microsoft.com/workshop/server/components/daciisperf.asp Mike Moore's Tuning IIS http://www.microsoft.com/isn/whitepapers/tuningiis.asp IIS4 Tuning Parameters for High Volume Sites http://msdn.microsoft.com/workshop/server/feature/tune.asp Hans Hugli's Seminar: Managing Microsoft Internet Information Server 4.0 for Performance @ http://www.microsoft.com/Seminar/1033/199811131-01MaxIISPerfor(HH/Portal.htm Backstage at Microsoft.com http://www.microsoft.com/backstage/whitepaper.htm IIS Research starts @ http://www.microsoft.com/technet/iis/default.htm Much ASP coding tips and advice related to scalability can be found at: http://www.learnasp.com/advice http://www.learnASP.com/learn/speedresearch.asp by Charles M. Carroll Page 179 Speed Research Resources by Charles Carroll Speed affects your web consumers very much. It is a big subject that we will cover in-depth in this section but if this advice doesn't help you enough you can join [aspfastcode] to get help. fastcode Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/speedresearch.asp Send Listserver Questions to fastcode@ls.asplists.com Related Links Niblacks Excellent ListBox/DB Speed Page @ http://niblack.com/kbase/listbox_x.asp Timing Tasks to Millisecond accuracy @ http://www.learnasp.com/learn/speedtimer.asp Web Application Stress Tool @ http://homer.rte.microsoft.com Caprocks FREE Scalable Dictionary Object Replacement @ http://www.caprockconsulting.com/comsoftware.htm Study up on Performance Counters @ http://msdn.microsoft.com/workshop/server/iis/usingWCAT.asp monitor PerfCounters from ASP via a nifty component @ http://www.alphasierrapapa.com/IisDev/Components/ Speed Percieved Table Display @ http://www.learnasp.com/learn/speedtables.asp Speeding Table Display - All Techniques @ http://www.learnasp.com/learn/speedtablesall.asp Worlds Fastest ListBox @ http://www.learnasp.com/learn/speedappdata.asp Charles Carroll's ASP Quick Lessons @ http://www.learnasp.com/learn/speedscale.asp http://www.learnASP.com/learn/speedtimer.asp by Charles M. Carroll Page 180 Speed: Measuring Code Speed by Richard A. Lowe drahcir@home.com with help from Jonathan McGuire jmcguire@solutionsatimpact.com Gregory Lybanon glybanon@sbcsystems.com Charles Carroll charlescarroll@learnasp.com Measuring speed to the millisecond was considered impossible with ASP. People built COM components that wrapped up API calls! So we called a COM component that called an API and then we distorted the measurement with overhead. Scripting has a few tricks up its sleeves yet as Richard demonstrates with the nifty Library implemented in Jscript. We will use it to time retrieving and displaying identical data three different ways: ● traditional loop and movenext ● one getrows call ● one getstring call This method is great for testing optimizations to 1 script but does not show how the script will run when many users are simultaneously executing it. Tools like the Stress Tester at: http://homer.rte.microsoft.com are great for simulating and recording measurements for multi-user performance. Here we retrieve data using a traditional loop (/learn/dbtable.asp): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html><head> <TITLE>timedbtable.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <!--#include file="lib_timethis.asp"--> <% Set HttpObj = Server.CreateObject("AspHTTP.Conn") HttpObj.Url = "http://www.learnasp.com/learn/test/dbtable.asp" timeThen = milliDif() strResult = HttpObj.GetURL timeNow = milliDif() SET HTTPobj = nothing elapsed=timeNow-timeThen msg="<br>Process time in ms: " & elapsed & "<br>" & elapsedpretty(elapsed) bodytag="<body bgcolor=""#FFFFFF"">" STRresult=replace(STRResult,bodytag,bodytag & msg) response.write STRresult %> </body></html> Here we retrieve data by fetching all the data into an array in one "gulp" (/learn/dbtablegetrows.asp): 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <TITLE>timedbtablegetrows.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <!--#include file="lib_timethis.asp"--> <% Set HttpObj = Server.CreateObject("AspHTTP.Conn") HttpObj.Url = "http://www.learnasp.com/learn/test/dbtablegetrows.asp" timeThen = milliDif() strResult = HttpObj.GetURL timeNow = milliDif() SET HTTPobj = nothing elapsed=timeNow-timeThen 14 15 16 17 18 19 20 21 msg="<br>Process time in ms: " & elapsed & "<br>" & elapsedpretty(elapsed) bodytag="<body bgcolor=""#FFFFFF"">" STRresult=replace(STRResult,bodytag,bodytag & msg) response.write STRresult %> </body></html> Here we retrieve data by asking the backend to combine the data into a custom string and not even bring fields and rows, just produce 1 string (/learn/dbtablegetstring.asp): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html><head> <TITLE>timedbtablegetstring.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <!--#include file="lib_timethis.asp"--> <% Set HttpObj = Server.CreateObject("AspHTTP.Conn") HttpObj.Url = "http://www.learnasp.com/learn/test/dbtablegetstring.asp" timeThen = milliDif() strResult = HttpObj.GetURL timeNow = milliDif() SET HTTPobj = nothing elapsed=timeNow-timeThen msg="<br>Process time in ms: " & elapsed & "<br>" & elapsedpretty(elapsed) bodytag="<body bgcolor=""#FFFFFF"">" STRresult=replace(STRResult,bodytag,bodytag & msg) response.write STRresult %> </body></html> The library that accomplishes this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <SCRIPT LANGUAGE=JScript RUNAT=Server> function y2k(number) { return (number < 1000) ? number + 1900 : number; } function milliDif() { var d = new Date(); return d.getTime() } function elapsedpretty(parm1) { var elapsedsecs = 0 var elapsedmins = 0 elapsedsecs=Math.floor(parm1/1000) parm1=parm1%1000 elapsedmins=Math.floor(elapsedsecs/60) elapsedsecs=elapsedsecs%60 elapsedpretty=elapsedmins + " minute" if(elapsedmins!=1) elapsedpretty=elapsedpretty+"s" elapsedpretty = elapsedpretty+" " + elapsedsecs+" second" if(elapsedsecs!=1) elapsedpretty=elapsedpretty+"s" elapsedpretty = elapsedpretty+ " "+parm1+" millisecond" if(parm1!=1) elapsedpretty=elapsedpretty+"s" 33 34 35 36 return elapsedpretty; } </script> http://www.learnASP.com/learn/speedtips.asp by Charles M. Carroll Page 181 Speed Tips by Charles Carroll There are several ways to speed up a given ASP page. These suggestions come from a very exciting listserver we run called [aspfastcode] (http://www.asplists.com/asplists/aspfastcode.asp) . There people submit their working scripts (broken ones are not allowed) that are running too slow and the members help them speed up that sample. #1 Any page that does not need session can benefit from this directive at the top: <%@ enablesessionstate=false %> #2 All pages should be buffered see /advice/whybuffer.asp for explanation. Also see /learn/speedtables.asp to see how flushing buffer and HTML tags can improve percieved speed. Add this to top: <%response.buffer=true%> #3 Pages doing database access will improve performance if the following techniques are used ● Getrows (see /learn/dbtablegetrows.asp and /advice/whygetrows.asp) ● GetString (see /learn/dbtablegetstring.asp) ● Disconnected recordsets (see /learn/dbtabledisconnected.asp). #4 Before just believing any article you read on the web or in an ASP book (many articles are not researched thoroughly) and implementing code changes TIME THE CODE BEFORE AND AFTER changes. /learn/speedtimer.asp has the needed code that will time scripts to millisecond accuracy. #5 Eliminate any code that reads com properties twice, /learn/propertyexpense.asp has some samples of this. #6 Just say no to VB components and/or recordsets stored at the session level. Several articles explain why: ● http://www.learnasp.com/advice/dbsessionapp.asp This is an attempt to settle this issue once and for all with very clear explanations why. This is NOT recommended by many who have tried and blown up quiet and busy web servers. ● http://www.learnasp.com/learn/nosessionobjects.asp ● http://www.learnasp.com/learn/sessionoverview.asp http://www.learnasp.com/learn/buildvbthreads.asp http://www.learnasp.com/learn/globalproblems.asp for earlier and other perspectives on Thread-locking, Serialization and Thread-Local storage. #7 Cache frequent query results/HTML generated from databases in application variables. http://www.learnasp.com/learn/speedappdata.asp. #8 Open database connections as late as possible, Close database connections immediately when done. Placing your code a few lines later could make a huge difference as your scripts run round-robin with other scripts, see /advice/roundrobin.asp for more whys about this. #9 Tune your server. At least make the 20 instead of 4 thread tweak (see http://www.learnasp.com/advice/threads.asp). The articles at /learn/speedserver.asp will tell you everything you need to know about tuning your server. #10 Don't waste time running scripts if the user hit the "stop" button or went to different page/site. Normally scripts run started by a user run to completion whether the user is there to read output or not running invisibly on server. See: /learn/isclientconnected.asp to see how to modify your scripts appropriately. #11 Bite the bullet and master remote scripting so your HTML and ASP scripts can communicate with ASP asynchronously and refresh portions of page without submitting page to server. Remote scripting works in both Netscape and IE; any Javascript capable browser. Some remote scripting links and a listserver to get help is at http://www.asplists.com/asplists/aspremotescripting.asp. http://www.learnASP.com/learn/speedtables.asp by Charles M. Carroll Page 182 Speed/Optimization Example: A Table Display Speeding up your scripts involves many big and small script changes. We have prepared this "before" and "after" example to illustrate the point. This example assumes you truly have to display this many records (for example, a corporate report). Alternatively: ● Paging records into page __ of ___ is much faster if this is appropriate (see /learn/dbtablepaged.asp) ● Throttling the maximum number of records if it is appropriate (see www.activeserverpages.com/learn/dbmaxrecs.asp) Side note: If anyone you know believes Access queries are done asynchronously, running a couple of these scripts will prove them wrong. Access queries execute one web user at a time sequentially. After Optimization Here is a very fast table display going against an identical huge SQL Server Table: 1 2 3 4 5 6 7 8 9 10 11 12 13 <%response.buffer=true%> <HEAD><TITLE>dbtablefast.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN = "DSN=student;UID=student;pwd=magic" mySQL="select * from authors order by author" call query2table(mySQL,myDSN) %> <!--#include virtual="/learn/test/lib_dbtablefast.asp"--> </BODY></HTML> Here is the optimized library lib_dbtablefast.asp which achieves this speed: 1 <% 2 sub query2table(inputquery, inputDSN) 3 dim conntemp, rstemp 4 set conntemp=server.createobject("adodb.connection") 5 ' 0 seconds means wait forever, default is 15 6 conntemp.connectiontimeout=0 7 conntemp.open inputDSN 8 set rstemp=conntemp.execute(inputquery) 9 howmanyfields=rstemp.fields.count -1 10 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 11 response.write tablestart 12 for i=0 to howmanyfields %> 13 <td><b><%=rstemp(i).name%></B></TD> 14 <% next %> 15 </tr> 16 <% ' Now lets grab all the records 17 DO UNTIL rstemp.eof 18 counter=counter+1 19 response.write "<tr>" 20 for i = 0 to howmanyfields 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if response.write "<td valign=top>" & thisvalue & "</td>" & vbcrlf next response.write "</tr>" rstemp.movenext IF counter mod 50=0 THEN If response.isclientconnected()=false THEN EXIT DO END IF response.write "</table>" & TableStart response.flush END IF loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> Before Optimization Here is the original slow script which basically demonstrates techniques that may work if your data and concurrency load is light, but the script above demonstrates the typical changes made to speed up a script when it becomes needed or you just want to wring every ounce of speed from your site. This script will probably timeout before it's completion! 1 2 3 4 5 6 7 8 9 10 <HEAD><TITLE>dbtableslow.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <% myDSN = "DSN=student;uid=student;pwd=magic" mySQL= "SELECT * from authors order by Author" call query2table(mySQL,myDSN) %> <!--#include virtual="/learn/test/lib_dbtableslow.asp"--> </BODY></HTML> Here is the original slow library lib_dbtableslow.asp : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <% sub query2table(inputquery, inputDSN) dim conntemp, rstemp set conntemp=server.createobject("adodb.connection") conntemp.open inputDSN set rstemp=conntemp.execute(inputquery) howmanyfields=rstemp.fields.count -1%> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name%></B></TD> <% next %> </tr> <% ' Now lets grab all the records DO UNTIL rstemp.eof and response.isclientconnected()%> <tr> <% for i = 0 to howmanyfields thisvalue=rstemp(i) If isnull(thisvalue) then thisvalue=" " end if%> <td valign=top><%=thisvalue%></td> <% next %> 24 25 26 27 28 29 30 31 32 33 </tr> <%rstemp.movenext loop%> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing end sub%> http://www.learnASP.com/learn/speedtablesall.asp by Charles M. Carroll Page 183 Speed/Optimization: All Variations Fetching records in an optimized way actually has many variations. We will list most of them here, provide code sample and typical timings for fetching and displaying records. These timings reveal an interesting behavior. Even if a script reports it ran in say, 7 seconds, that refers to the time that script received from the CPU. So that if 7 scripts take 8 seconds each there may be hundreds or thousands of scripts running on the server that are sharing the CPU. User #1 may see a 7 second result in 21 seconds, so their 7 second report reflects the time spent on the server/CPU for the script and the fact that 14 seconds of other stuff was executed round-robin with the rest of the scripts, not the time since the script started. Method: LOOP, .movenext, periodic response.flush Query took 6 seconds. Query processed 10835 records. Speed =1805.83333333333 records per second Method: LOOP, .movenext and periodic response.flush commands. String is assembled with & operator and writen periodically. Query took 52 seconds. Query processed 10835 records. Speed =208.365384615385 records per second. Observation: The & operator is VERY expensive! Unbelievably so. Method: Single GetString command Query took 4 seconds Query processed 10837 records. Speed =2709.25 records per second. Method: GetRows command with no LOOP + movenext but loop through the array with periodic response flushes. Query took 3 seconds. Query processed 10834 records. Speed =3611.33333333333 records per second. Note: Getstring often wins in many tests but it depends on many factors. I have seen a straight loop take 18 secs where GetRows takes 9 seconds and getstring take 4 secs. Method: GetRows command of a fixed row count (say 500 record clusters for example) with a reponse.flush after each array is read! Query took 3 seconds. Query processed 10782 records. Speed =3594 records per second. Method: Displaying a portion of the data (say the first 500 records) only. Query took 7 seconds. Query processed 500 records. Speed =71.4285714285714 records per second. Note: This was recorded as 7 seconds but actually was much faster actually due to speed the browser reported the results. Now here is the code that was used to gather all the data. Here is a table display with a simple LOOP: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <%response.buffer=true%> <HEAD><TITLE>dbtableLoopAll.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_LoopAll myDSN = "DSN=student;UID=student;pwd=magic" 'mySQL="select * from authors order by author " mySQL="select * from authors order by author " Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) Call TimerEnd %> </BODY></HTML> Here is a table display with a simple LOOP assembling a string: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <%response.buffer=true%> <HEAD><TITLE>dbtableLoopAllstring.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_LoopAll_string myDSN = "DSN=student;UID=student;pwd=magic" mySQL="select * from authors order by author " Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) Call TimerEnd %> </BODY></HTML> Here is a table display with a GetString call and no LOOP: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <%response.buffer=true%> <HEAD><TITLE>dbtablegetstringall.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_GetStringAll myDSN = "DSN=student;UID=student;pwd=magic" mySQL="select * from authors order by author" Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) response.write OptimizationName(optimize) & "<br>" Call TimerEnd %> </BODY></HTML> Here is a table display with a GetString call (buffered): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <%response.buffer=true%> <HEAD><TITLE>dbtablegetstringbuffered.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_GetStringBuffered myDSN = "DSN=student;UID=student;pwd=magic" mySQL="select * from authors order by author" Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) response.write OptimizationName(optimize) & "<br>" Call TimerEnd %> </BODY></HTML> Here is a table display with a GetRows call and no LOOP: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <%response.buffer=true%> <HEAD><TITLE>dbtablegetrowsall.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_getrowsall response.write OptimizationName(optimize) & "<p>" myDSN = "DSN=student;UID=student;pwd=magic" mySQL="select * from authors order by author " call TimerStart call query2table(mySQL,myDSN,optimize,howmany) call TimerEnd %> </BODY></HTML> Here is a table display with a GetRows (buffered): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <%response.buffer=true%> <HEAD><TITLE>dbtableGetRowsBuffered.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_GetRowsBuffered myDSN = "DSN=student;UID=student;pwd=magic" 'mySQL="select * from authors order by author " mySQL="select * from authors order by author " Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) Call TimerEnd %> </BODY></HTML> Here is a table display of a portion of the records: 1 2 3 4 <%response.buffer=true%> <HEAD><TITLE>dbtablelimitrows.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> 5 6 7 8 9 10 11 12 13 14 15 16 17 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_LimitRows myDSN = "DSN=student;UID=student;pwd=magic" mySQL="select * from authors order by author" Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) response.write OptimizationName(optimize) & "<br>" Call TimerEnd %> </BODY></HTML> Here is the optimized library lib_dbtablefastv2.asp which achieves this speed: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <% Const Const Const Const Const Const Const dim dim dim dim dim dim dim dim dim optimize_LoopAll = 1 optimize_GetstringAll = 2 optimize_GetrowsAll = 3 optimize_GetrowsBuffered = 4 optimize_GetStringBuffered = 5 optimize_LimitRows = 6 optimize_LoopAll_String = 7 optimize_buffersize optimize_started optimize_ended optimize_SQL optimize_DSN optimize_howmany optimize_cursorlocation optimize_maxrecs optimize_disconnectRS optimize_started=0 ' performance stuff optimize_buffersize=200 'optimize_cursorlocation=aduseclient optimize_maxrecs=500 optimize_cursorlocation=aduseserver optimize_disconnectRS=false optimize_stringwrite=false SUB TimerStart() optimize_started=now() END SUB SUB TimerEnd() optimize_ended=now() elapsed=DateDiff("s", optimize_started, optimize_ended) response.write "SQL=<b>" & optimize_SQL & "</b><br>" response.write "DSN=<b>" & optimize_DSN & "</b><br>" response.write "Query took <b>" & elapsed & " seconds.</b><br>" IF optimize_howmany=-1 THEN optimize_howmany=querycount(optimize_DSN,optimize_SQL) END IF response.write "Query processed <b>" & optimize_howmany & " records.</b><br>" response.write "Speed =<b>" & optimize_howmany/elapsed & " records per second.</b><br>" response.write "Notes:<br>" pad=" " response.write pad & "buffersize=<b>" & optimize_buffersize & "</b><br>" IF optimize_cursorlocation=adUseClient THEN response.write pad & "cursorlocation=<b>adUseClient</b><br>" END IF IF optimize_cursorlocation=adUseServer THEN response.write pad & "cursorlocation=<b>adUseServer</b><br>" 53 END IF 54 END SUB 55 56 sub query2table(parmQuery, parmDSN,parmMethod,parmcount) 57 ' method 1 = standard 58 ' method 2 = getrows 59 ' method 3 = getstring 60 dim howmany 61 SELECT CASE parmMethod 62 CASE 1 63 Call loopStandard(parmQuery,parmDSN,howmany) 64 CASE 2 65 Call loopGetString(parmQuery,parmDSN,howmany) 66 CASE 3 67 Call loopGetRows(parmQuery,parmDSN,howmany) 68 CASE 4 69 Call loopGetRowsBuffered(parmQuery,parmDSN,howmany) 70 CASE 5 71 Call loopGetStringBuffered(parmQuery,parmDSN,howmany) 72 CASE 6 73 Call LimitRows(parmQuery,parmDSN,howmany) 74 CASE 7 75 Call loopStandardStringWrite(parmQuery,parmDSN,howmany) 76 CASE ELSE 77 response.write "1, 2 or 3 are only valid speedmethods" 78 END SELECT 79 parmcount=howmany 80 If optimize_started<>0 THEN 81 optimize_DSN=parmDSN 82 optimize_SQL=parmquery 83 optimize_howmany=parmcount 84 END IF 85 END SUB 86 87 FUNCTION querycount(parmDSN,parmQuery) 88 set rstemp=Server.CreateObject("adodb.Recordset") 89 rstemp.open parmQuery, parmDSN, adopenstatic 90 querycount=rstemp.recordcount 91 rstemp.close 92 set rstemp=nothing 93 END FUNCTION 94 95 96 SUB loopstandard(inputquery, inputDSN,inputcount) 97 dim conntemp, rstemp 98 set conntemp=server.createobject("adodb.connection") 99 ' 0 seconds means wait forever, default is 15 100 conntemp.connectiontimeout=0 101 conntemp.cursorlocation=optimize_cursorlocation 102 conntemp.open inputDSN 103 set rstemp=conntemp.execute(inputquery) 104 IF optimize_disconnectRS=true THEN 105 conntemp.close 106 END IF 107 howmanyfields=rstemp.fields.count -1 108 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 109 response.write tablestart 110 for i=0 to howmanyfields %> 111 <td><b><%=rstemp(i).name%></B></TD> 112 <% next %> 113 </tr> 114 <% ' Now lets grab all the records 115 DO UNTIL rstemp.eof 116 counter=counter+1 117 response.write "<tr>" 118 for i = 0 to howmanyfields 119 thisvalue=rstemp(i) 120 If isnull(thisvalue) then 121 thisvalue=" " 122 end if 123 response.write "<td valign=top>" & thisvalue & "</td>" & vbcrlf 124 next 125 response.write "</tr>" 126 rstemp.movenext 127 IF counter mod 50=0 THEN 128 If response.isclientconnected()=false THEN 129 EXIT DO 130 END IF 131 response.write "</table>" & TableStart 132 END IF 133 134 loop%> 135 </table> 136 <% 137 inputcount=counter 138 rstemp.close 139 set rstemp=nothing 140 conntemp.close 141 set conntemp=nothing 142 END SUB%> 143 144 <%SUB loopstandardStringWrite(inputquery, inputDSN,inputcount) 145 dim conntemp, rstemp 146 set conntemp=server.createobject("adodb.connection") 147 ' 0 seconds means wait forever, default is 15 148 conntemp.connectiontimeout=0 149 conntemp.cursorlocation=optimize_cursorlocation 150 conntemp.open inputDSN 151 set rstemp=conntemp.execute(inputquery) 152 IF optimize_disconnectRS=true THEN 153 conntemp.close 154 END IF 155 howmanyfields=rstemp.fields.count -1 156 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 157 response.write tablestart 158 for i=0 to howmanyfields %> 159 <td><b><%=rstemp(i).name%></B></TD> 160 <% next %> 161 </tr> 162 <% ' Now lets grab all the records 163 tempSTR="" 164 DO UNTIL rstemp.eof 165 counter=counter+1 166 tempSTR=tempSTR & "<tr>" 167 for i = 0 to howmanyfields 168 thisvalue=rstemp(i) 169 If isnull(thisvalue) then 170 thisvalue=" " 171 end if 172 tempSTR=tempSTR & "<td valign=top>" & thisvalue & "</td>" & vbcrlf 173 next 174 tempSTR=tempSTR & "</tr>" 175 rstemp.movenext 176 IF counter mod 50=0 THEN 177 If response.isclientconnected()=false THEN 178 EXIT DO 179 END IF 180 tempSTR=tempSTR & "</table>" & TableStart 181 response.write tempSTR 182 response.flush 183 tempSTR="" 184 END IF 185 loop%> 186 </table> 187 <% 188 inputcount=counter 189 rstemp.close 190 set rstemp=nothing 191 conntemp.close 192 set conntemp=nothing 193 END SUB%> 194 195 <%SUB loopGetstring(inputquery, inputDSN,inputcount) 196 dim conntemp, rstemp 197 set conntemp=server.createobject("adodb.connection") 198 ' 0 seconds means wait forever, default is 15 199 conntemp.connectiontimeout=0 200 conntemp.open inputDSN 201 set rstemp=conntemp.execute(inputquery) 202 howmanyfields=rstemp.fields.count -1 203 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 204 response.write tablestart 205 for i=0 to howmanyfields %> 206 <td><b><%=rstemp(i).name%></B></TD> 207 <% next %> 208 </tr> 209 <% 210 ' Now lets grab all the records 211 tempSTR=rstemp.getstring(,, "</td><td>", "</td></tr><TR><TD>", " ") 212 response.write tempSTR 213 response.write "</table>" 214 inputcount=-1 215 rstemp.close 216 set rstemp=nothing 217 conntemp.close 218 set conntemp=nothing 219 END SUB%> 220 221 222 <%SUB loopGetstringbuffered(inputquery, inputDSN,inputcount) 223 dim conntemp, rstemp 224 set conntemp=server.createobject("adodb.connection") 225 ' 0 seconds means wait forever, default is 15 226 conntemp.connectiontimeout=0 227 conntemp.open inputDSN 228 set rstemp=conntemp.execute(inputquery) 229 howmanyfields=rstemp.fields.count -1 230 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 231 response.write tablestart 232 for i=0 to howmanyfields %> 233 <td><b><%=rstemp(i).name%></B></TD> 234 <% next %> 235 </tr> 236 <% 237 ' Now lets grab all the records 238 DO 239 tempSTR=rstemp.getstring(,optimize_buffersize, "</td><td>", "</td></tr><TR><TD>", " ") 240 response.write tempSTR 241 If response.isclientconnected()=false THEN 242 EXIT SUB 243 END IF 244 response.write "</table>" & TableStart 245 LOOP UNTIL rstemp.eof 246 response.write "</table>" 247 inputcount=-1 248 rstemp.close 249 set rstemp=nothing 250 conntemp.close 251 set conntemp=nothing 252 END SUB 253 254 SUB loopGetRows(inputquery, inputDSN,inputcount) 255 dim conntemp, rstemp 256 set conntemp=server.createobject("adodb.connection") 257 ' 0 seconds means wait forever, default is 15 258 conntemp.connectiontimeout=0 259 conntemp.open inputDSN 260 set rstemp=conntemp.execute(inputquery) 261 howmanyfields=rstemp.fields.count -1 262 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 263 response.write tablestart 264 for i=0 to howmanyfields %> 265 <td><b><%=rstemp(i).name%></B></TD> 266 <% next %> 267 </tr> 268 <% 269 ' Now lets grab all the records 270 alldata=rstemp.getrows 271 numcols=ubound(alldata,1) 272 numrows=ubound(alldata,2) 273 274 FOR rowcounter= 0 TO numrows 275 FOR colcounter=0 to numcols 276 response.write "<td valign=top>" 277 response.write alldata(colcounter,rowcounter) 278 response.write "</td>" 279 NEXT 280 response.write "</tr>" & vbcrlf 281 IF rowcounter mod 50=0 THEN 282 If response.isclientconnected()=false THEN 283 EXIT FOR 284 END IF 285 response.write "</table>" & TableStart 286 END IF 287 NEXT 288 response.write "</table>" 289 inputcount=numrows 290 rstemp.close 291 set rstemp=nothing 292 conntemp.close 293 set conntemp=nothing 294 END SUB 295 296 SUB loopGetRowsBuffered(inputquery, inputDSN,inputcount) 297 dim conntemp, rstemp 298 set conntemp=server.createobject("adodb.connection") 299 ' 0 seconds means wait forever, default is 15 300 conntemp.connectiontimeout=0 301 conntemp.open inputDSN 302 set rstemp=conntemp.execute(inputquery) 303 howmanyfields=rstemp.fields.count -1 304 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 305 response.write tablestart 306 for i=0 to howmanyfields %> 307 <td><b><%=rstemp(i).name%></B></TD> 308 <% next %> 309 </tr> 310 <% 311 ' Now lets grab all the records 312 DO 313 alldata=rstemp.getrows(optimize_buffersize) 314 numcols=ubound(alldata,1) 315 numrows=ubound(alldata,2) 316 317 FOR rowcounter= 0 TO numrows 318 FOR colcounter=0 to numcols 319 response.write "<td valign=top>" 320 response.write alldata(colcounter,rowcounter) 321 response.write "</td>" 322 NEXT 323 response.write "</tr>" & vbcrlf 324 NEXT 325 howmany=howmany+numrows 326 If response.isclientconnected()=false THEN 327 EXIT SUB 328 END IF 329 response.write "</table>" & TableStart 330 LOOP UNTIL rstemp.eof 331 response.write "</table>" 332 inputcount=howmany 333 rstemp.close 334 set rstemp=nothing 335 conntemp.close 336 set conntemp=nothing 337 END SUB 338 339 SUB LimitRows(inputquery, inputDSN,inputcount) 340 set rstemp=Server.CreateObject("adodb.Recordset") 341 rstemp.maxrecords=optimize_maxrecs 342 'rstemp.open inputquery, inputDSN, adopenforwardonly, adlockReadOnly 343 rstemp.open inputquery, inputDSN,adopenstatic 344 345 howmanyfields=rstemp.fields.count -1 346 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 347 response.write tablestart 348 for i=0 to howmanyfields %> 349 <td><b><%=rstemp(i).name%></B></TD> 350 <% next %> 351 </tr> 352 <% 353 response.flush 354 tempSTR=rstemp.getstring(,, "</td><td>", "</td></tr><TR><TD>", " ") 355 response.write tempSTR 356 response.write "</td></tr></table>" 357 358 inputcount=optimize_maxrecs 359 rstemp.close 360 set rstemp=nothing 361 END SUB 362 363 FUNCTION optimizationName(parmNum) 364 SELECT CASE parmnum 365 CASE optimize_LoopAll 366 optimizationName="LoopAll" 367 CASE optimize_GetstringAll 368 optimizationName="GetstringAll" 369 CASE optimize_GetrowsAll 370 optimizationName="GetrowsAll" 371 CASE optimize_GetrowsBuffered 372 optimizationName="GetrowsBuffered" 373 CASE optimize_GetStringBuffered 374 optimizationName="GetStringBuffered" 375 CASE optimize_LimitRows 376 optimizationName="LimitRows" 377 CASE ELSE 378 optimizationName="undefined" 379 END SELECT 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 END FUNCTION %> http://www.learnASP.com/learn/speedtablesdrivers.asp by Charles M. Carroll Page 184 Speed/Optimization: What about the Driver? Fetching records in an optimized way may have many variations but before you get to the database you interact with a driver. Here we time the difference between arbitrary drivers. We will benchmark with the simplest method: Fetching and displaying all records with a LOOP, .movenext and periodic response.flush commands. Here is a table display against a SQL server with a OLEDB driver. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <%response.buffer=true%> <HEAD><TITLE>dbtableSQLoledb.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 optimize=optimize_LoopAll mySQL="select * from authors where au_id<2000 order by author " myDSN="PROVIDER=SQLOLEDB;DATA SOURCE=sql2.datareturn.com;" myDSN=myDSN & "USER ID=student;PASSWORD=magic;" Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) Call TimerEnd %> </BODY></HTML> Here is a table display against a SQL server with a ODBC driver: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <%response.buffer=true%> <HEAD><TITLE>dbtableSQLODBC.asp</TITLE></HEAD> <HTML><body bgcolor="#FFFFFF"> <!--#include virtual="/adovbs.inc"--> <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"--> <% server.scripttimeout=240 mySQL="select * from authors where au_id<2000 order by author " optimize=optimize_LoopAll myDSN="PROVIDER=MSDASQL;DRIVER={SQL Server};" myDSN=myDSN & "SERVER=sql2.datareturn.com;UID=student;PWD=magic;" Call TimerStart call query2table(mySQL,myDSN,optimize,howmany) 16 17 18 Call TimerEnd %> </BODY></HTML> Here is the optimized library lib_dbtablefastv2.asp which achieves this speed: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <% Const Const Const Const Const Const Const dim dim dim dim dim dim dim dim dim optimize_LoopAll = 1 optimize_GetstringAll = 2 optimize_GetrowsAll = 3 optimize_GetrowsBuffered = 4 optimize_GetStringBuffered = 5 optimize_LimitRows = 6 optimize_LoopAll_String = 7 optimize_buffersize optimize_started optimize_ended optimize_SQL optimize_DSN optimize_howmany optimize_cursorlocation optimize_maxrecs optimize_disconnectRS optimize_started=0 ' performance stuff optimize_buffersize=200 'optimize_cursorlocation=aduseclient optimize_maxrecs=500 optimize_cursorlocation=aduseserver optimize_disconnectRS=false optimize_stringwrite=false SUB TimerStart() optimize_started=now() END SUB SUB TimerEnd() optimize_ended=now() elapsed=DateDiff("s", optimize_started, optimize_ended) response.write "SQL=<b>" & optimize_SQL & "</b><br>" response.write "DSN=<b>" & optimize_DSN & "</b><br>" response.write "Query took <b>" & elapsed & " seconds.</b><br>" IF optimize_howmany=-1 THEN optimize_howmany=querycount(optimize_DSN,optimize_SQL) END IF response.write "Query processed <b>" & optimize_howmany & " records.</b><br>" response.write "Speed =<b>" & optimize_howmany/elapsed & " records per second.</b><br>" response.write "Notes:<br>" pad=" " response.write pad & "buffersize=<b>" & optimize_buffersize & "</b><br>" IF optimize_cursorlocation=adUseClient THEN response.write pad & "cursorlocation=<b>adUseClient</b><br>" END IF IF optimize_cursorlocation=adUseServer THEN response.write pad & "cursorlocation=<b>adUseServer</b><br>" END IF END SUB sub query2table(parmQuery, parmDSN,parmMethod,parmcount) ' method 1 = standard ' method 2 = getrows ' method 3 = getstring dim howmany SELECT CASE parmMethod 62 CASE 1 63 Call loopStandard(parmQuery,parmDSN,howmany) 64 CASE 2 65 Call loopGetString(parmQuery,parmDSN,howmany) 66 CASE 3 67 Call loopGetRows(parmQuery,parmDSN,howmany) 68 CASE 4 69 Call loopGetRowsBuffered(parmQuery,parmDSN,howmany) 70 CASE 5 71 Call loopGetStringBuffered(parmQuery,parmDSN,howmany) 72 CASE 6 73 Call LimitRows(parmQuery,parmDSN,howmany) 74 CASE 7 75 Call loopStandardStringWrite(parmQuery,parmDSN,howmany) 76 CASE ELSE 77 response.write "1, 2 or 3 are only valid speedmethods" 78 END SELECT 79 parmcount=howmany 80 If optimize_started<>0 THEN 81 optimize_DSN=parmDSN 82 optimize_SQL=parmquery 83 optimize_howmany=parmcount 84 END IF 85 END SUB 86 87 FUNCTION querycount(parmDSN,parmQuery) 88 set rstemp=Server.CreateObject("adodb.Recordset") 89 rstemp.open parmQuery, parmDSN, adopenstatic 90 querycount=rstemp.recordcount 91 rstemp.close 92 set rstemp=nothing 93 END FUNCTION 94 95 96 SUB loopstandard(inputquery, inputDSN,inputcount) 97 dim conntemp, rstemp 98 set conntemp=server.createobject("adodb.connection") 99 ' 0 seconds means wait forever, default is 15 100 conntemp.connectiontimeout=0 101 conntemp.cursorlocation=optimize_cursorlocation 102 conntemp.open inputDSN 103 set rstemp=conntemp.execute(inputquery) 104 IF optimize_disconnectRS=true THEN 105 conntemp.close 106 END IF 107 howmanyfields=rstemp.fields.count -1 108 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 109 response.write tablestart 110 for i=0 to howmanyfields %> 111 <td><b><%=rstemp(i).name%></B></TD> 112 <% next %> 113 </tr> 114 <% ' Now lets grab all the records 115 DO UNTIL rstemp.eof 116 counter=counter+1 117 response.write "<tr>" 118 for i = 0 to howmanyfields 119 thisvalue=rstemp(i) 120 If isnull(thisvalue) then 121 thisvalue=" " 122 end if 123 response.write "<td valign=top>" & thisvalue & "</td>" & vbcrlf 124 next 125 response.write "</tr>" 126 rstemp.movenext 127 IF counter mod 50=0 THEN 128 If response.isclientconnected()=false THEN 129 EXIT DO 130 END IF 131 response.write "</table>" & TableStart 132 END IF 133 134 loop%> 135 </table> 136 <% 137 inputcount=counter 138 rstemp.close 139 set rstemp=nothing 140 conntemp.close 141 set conntemp=nothing 142 END SUB%> 143 144 <%SUB loopstandardStringWrite(inputquery, inputDSN,inputcount) 145 dim conntemp, rstemp 146 set conntemp=server.createobject("adodb.connection") 147 ' 0 seconds means wait forever, default is 15 148 conntemp.connectiontimeout=0 149 conntemp.cursorlocation=optimize_cursorlocation 150 conntemp.open inputDSN 151 set rstemp=conntemp.execute(inputquery) 152 IF optimize_disconnectRS=true THEN 153 conntemp.close 154 END IF 155 howmanyfields=rstemp.fields.count -1 156 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 157 response.write tablestart 158 for i=0 to howmanyfields %> 159 <td><b><%=rstemp(i).name%></B></TD> 160 <% next %> 161 </tr> 162 <% ' Now lets grab all the records 163 tempSTR="" 164 DO UNTIL rstemp.eof 165 counter=counter+1 166 tempSTR=tempSTR & "<tr>" 167 for i = 0 to howmanyfields 168 thisvalue=rstemp(i) 169 If isnull(thisvalue) then 170 thisvalue=" " 171 end if 172 tempSTR=tempSTR & "<td valign=top>" & thisvalue & "</td>" & vbcrlf 173 next 174 tempSTR=tempSTR & "</tr>" 175 rstemp.movenext 176 IF counter mod 50=0 THEN 177 If response.isclientconnected()=false THEN 178 EXIT DO 179 END IF 180 tempSTR=tempSTR & "</table>" & TableStart 181 response.write tempSTR 182 response.flush 183 tempSTR="" 184 END IF 185 loop%> 186 </table> 187 <% 188 inputcount=counter 189 rstemp.close 190 set rstemp=nothing 191 conntemp.close 192 set conntemp=nothing 193 END SUB%> 194 195 <%SUB loopGetstring(inputquery, inputDSN,inputcount) 196 dim conntemp, rstemp 197 set conntemp=server.createobject("adodb.connection") 198 ' 0 seconds means wait forever, default is 15 199 conntemp.connectiontimeout=0 200 conntemp.open inputDSN 201 set rstemp=conntemp.execute(inputquery) 202 howmanyfields=rstemp.fields.count -1 203 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 204 response.write tablestart 205 for i=0 to howmanyfields %> 206 <td><b><%=rstemp(i).name%></B></TD> 207 <% next %> 208 </tr> 209 <% 210 ' Now lets grab all the records 211 tempSTR=rstemp.getstring(,, "</td><td>", "</td></tr><TR><TD>", " ") 212 response.write tempSTR 213 response.write "</table>" 214 inputcount=-1 215 rstemp.close 216 set rstemp=nothing 217 conntemp.close 218 set conntemp=nothing 219 END SUB%> 220 221 222 <%SUB loopGetstringbuffered(inputquery, inputDSN,inputcount) 223 dim conntemp, rstemp 224 set conntemp=server.createobject("adodb.connection") 225 ' 0 seconds means wait forever, default is 15 226 conntemp.connectiontimeout=0 227 conntemp.open inputDSN 228 set rstemp=conntemp.execute(inputquery) 229 howmanyfields=rstemp.fields.count -1 230 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 231 response.write tablestart 232 for i=0 to howmanyfields %> 233 <td><b><%=rstemp(i).name%></B></TD> 234 <% next %> 235 </tr> 236 <% 237 ' Now lets grab all the records 238 DO 239 tempSTR=rstemp.getstring(,optimize_buffersize, "</td><td>", "</td></tr><TR><TD>", " ") 240 response.write tempSTR 241 If response.isclientconnected()=false THEN 242 EXIT SUB 243 END IF 244 response.write "</table>" & TableStart 245 LOOP UNTIL rstemp.eof 246 response.write "</table>" 247 inputcount=-1 248 rstemp.close 249 set rstemp=nothing 250 conntemp.close 251 set conntemp=nothing 252 END SUB 253 254 SUB loopGetRows(inputquery, inputDSN,inputcount) 255 dim conntemp, rstemp 256 set conntemp=server.createobject("adodb.connection") 257 ' 0 seconds means wait forever, default is 15 258 conntemp.connectiontimeout=0 259 conntemp.open inputDSN 260 set rstemp=conntemp.execute(inputquery) 261 howmanyfields=rstemp.fields.count -1 262 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 263 response.write tablestart 264 for i=0 to howmanyfields %> 265 <td><b><%=rstemp(i).name%></B></TD> 266 <% next %> 267 </tr> 268 <% 269 ' Now lets grab all the records 270 alldata=rstemp.getrows 271 numcols=ubound(alldata,1) 272 numrows=ubound(alldata,2) 273 274 FOR rowcounter= 0 TO numrows 275 FOR colcounter=0 to numcols 276 response.write "<td valign=top>" 277 response.write alldata(colcounter,rowcounter) 278 response.write "</td>" 279 NEXT 280 response.write "</tr>" & vbcrlf 281 IF rowcounter mod 50=0 THEN 282 If response.isclientconnected()=false THEN 283 EXIT FOR 284 END IF 285 response.write "</table>" & TableStart 286 END IF 287 NEXT 288 response.write "</table>" 289 inputcount=numrows 290 rstemp.close 291 set rstemp=nothing 292 conntemp.close 293 set conntemp=nothing 294 END SUB 295 296 SUB loopGetRowsBuffered(inputquery, inputDSN,inputcount) 297 dim conntemp, rstemp 298 set conntemp=server.createobject("adodb.connection") 299 ' 0 seconds means wait forever, default is 15 300 conntemp.connectiontimeout=0 301 conntemp.open inputDSN 302 set rstemp=conntemp.execute(inputquery) 303 howmanyfields=rstemp.fields.count -1 304 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 305 response.write tablestart 306 for i=0 to howmanyfields %> 307 <td><b><%=rstemp(i).name%></B></TD> 308 <% next %> 309 </tr> 310 <% 311 ' Now lets grab all the records 312 DO 313 alldata=rstemp.getrows(optimize_buffersize) 314 numcols=ubound(alldata,1) 315 numrows=ubound(alldata,2) 316 317 FOR rowcounter= 0 TO numrows 318 FOR colcounter=0 to numcols 319 response.write "<td valign=top>" 320 response.write alldata(colcounter,rowcounter) 321 response.write "</td>" 322 NEXT 323 response.write "</tr>" & vbcrlf 324 NEXT 325 howmany=howmany+numrows 326 If response.isclientconnected()=false THEN 327 EXIT SUB 328 END IF 329 response.write "</table>" & TableStart 330 LOOP UNTIL rstemp.eof 331 response.write "</table>" 332 inputcount=howmany 333 rstemp.close 334 set rstemp=nothing 335 conntemp.close 336 set conntemp=nothing 337 END SUB 338 339 SUB LimitRows(inputquery, inputDSN,inputcount) 340 set rstemp=Server.CreateObject("adodb.Recordset") 341 rstemp.maxrecords=optimize_maxrecs 342 'rstemp.open inputquery, inputDSN, adopenforwardonly, adlockReadOnly 343 rstemp.open inputquery, inputDSN,adopenstatic 344 345 howmanyfields=rstemp.fields.count -1 346 tablestart="<table border=1 cols=3><col width='15%'><col width='70%'><col width='15%'><tr>" 347 response.write tablestart 348 for i=0 to howmanyfields %> 349 <td><b><%=rstemp(i).name%></B></TD> 350 <% next %> 351 </tr> 352 <% 353 response.flush 354 tempSTR=rstemp.getstring(,, "</td><td>", "</td></tr><TR><TD>", " ") 355 response.write tempSTR 356 response.write "</td></tr></table>" 357 358 inputcount=optimize_maxrecs 359 rstemp.close 360 set rstemp=nothing 361 END SUB 362 363 FUNCTION optimizationName(parmNum) 364 SELECT CASE parmnum 365 CASE optimize_LoopAll 366 optimizationName="LoopAll" 367 CASE optimize_GetstringAll 368 optimizationName="GetstringAll" 369 CASE optimize_GetrowsAll 370 optimizationName="GetrowsAll" 371 CASE optimize_GetrowsBuffered 372 optimizationName="GetrowsBuffered" 373 CASE optimize_GetStringBuffered 374 optimizationName="GetStringBuffered" 375 CASE optimize_LimitRows 376 optimizationName="LimitRows" 377 CASE ELSE 378 optimizationName="undefined" 379 END SELECT 380 END FUNCTION 381 382 %> 383 384 385 386 387 388 389 390 391 392 393 394 http://www.learnASP.com/learn/isclientconnected.asp by Charles M. Carroll Page 185 IsClientConnected -- eliminating stray tasks by Charles Carroll response.IsClientConnected() is available beginning with IIS4 (if you want to see if you have it, see /learn/versioncheck.asp) and can be used within a page to determine if the user is still fetching that page, i.e. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <%server.scripttimeout=20 ' this times out the script in 20 seconds whether done or not%> <TITLE>infiniteloop.asp</TITLE> <body bgcolor="#FFFFFF"> <% DO x=x+1 response.write x & "<br>" If x=10000 then x=1 end if LOOP %> </body></html> This loop could tie up the CPU for quite a while, even though the user hit the "stop" button the task would still be "spinning/executing" on the server even though the user was long gone. This is particularly true in database tasks. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <%server.scripttimeout=20 ' this times out the script in 20 seconds whether done or ' the user hit the STOP button %> <TITLE>infiniteloopfixed.asp</TITLE> <body bgcolor="#FFFFFF"> <% DO x=x+1 response.write x & "<br>" If x=10000 then x=1 end if LOOP WHILE response.isclientconnected() %> </body></html> this code will stop when user hits the stop button. I recommend that all loops through database recordsets incorporate this so that they don't execute invisibly wasting CPU and database server resources. So here is a database table listing script that incorporates this functionality: 1 2 3 4 <TITLE>dbtableisclientconnected.asp</TITLE> <body bgcolor="#FFFFFF"> <% ' ASP program that displays a database in table form 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select * from publishers" set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(mySQL) howmanyfields=rstemp.fields.count -1 %> <table border=1><tr> <% 'Put Headings On The Table of Field Names for i=0 to howmanyfields %> <td><b><%=rstemp(i).name %></B></TD> <% next %> </tr> <% ' Now lets grab all the records do until (rstemp.eof or response.isclientconnected=false)%> <tr> <% for i = 0 to howmanyfields%> <td valign=top><%=rstemp(i)%></td> <% next %> </tr> <%rstemp.movenext loop %> </table> <% rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> </body></html> http://www.learnASP.com/learn/nothing.asp by Charles M. Carroll Page 186 The controversy over Nothing by Charles Carroll Rule #1: All objects created with SET whatever=server.createobject("whatever") need to be destroyed on that page, i.e. set whatever=nothing Rule #2: All objects created with SET whatever=server.createobject("whatever") should never be put in a session variable. These two statements are the source of much controversy. I would like to address the veracity of these statements and address the real truth of this matter and why this truth is important to building high traffic websites. The session is issue is dealt with in: http://www.learnasp.com/learn/sessionoverview.asp http://www.learnasp.com/learn/globalproblems.asp http://www.activeserverpages.com/learn/buildvbthreads.asp http://www.learnasp.com/learn/nosessionobjects.asp Scenario #1: set x=server.createobject("whatever.whatever") .... set x=nothing Scenario #2 set x=server.createobject("whatever.whatever") .... In Scenario #1, I can guarantee ● the object is cleared from memory ● exactly the line of code where the object is removed from memory In Scenario #2, I cannot guarantee: ● that the object WAS cleared from memory (I am basing this on a promise in the MS docs, and that the IIS code internally is flawless). IIS is good but if you think it is flawless I would like to ask you to buy some undervalued land in Florida. ● when the object was cleaned from memory (the docs do not say when garbage collection occurs) I will also state that large ISPs (Innerhost, DataReturn) will guarantee your webserver will come down several times a day or week with scenario #2 (depending on how many objects are created throughout the day). With Scenario #1 the webserver stays up without incident. This evidence indicates the IIS garbage collection screws up. http://www.learnASP.com/learn/dbpooling.asp by Charles M. Carroll Page 187 Database Connection Pooling by Charles Carroll Connection pooling takes care of re-using connections. Lets say Scripta.asp ● creates a connection ● process data ● close connection, set to nothing and 1,000 users do this simultaneously. It is not quite simultaneous, let us say that what happens when eight users access a script and create, close and destroy eight connections. User #1 #2 #3 #4 #5 #6 #7 #8 Time - open conns 1:00am .001 - 1 1:00am .002 - 2 1:00am .010 - 4 1:00am .013 - 4 1:00am .014 - 3 1:00am .016 - 2 1:00am .022 1:00am .027 1:00am .029 - Open conn. time 1:00am .001 1:00am .002 1:00am .003 1:00am .003 1:00am .007 1:00am .009 1:00am .016 1:00am .017 Open conns #1 #1, #2 #1, #2, #4, #5, #6 #2, #4, #5, #6 #4, #5, #6 #6, #7 #7, #8 #7 Process Start time 1:00am .002 1:00am .003 1:00am .004 1:00am .004 1:00am .008 1:00am .010 1:00am .017 1:00am .018 Pool to be reused 0 0 #3 #1 #1, #2 #2, #4 #1, #3, #4, #5 #1, #3, #4, #5 #1, #3, #4, #5 waiting Close time 1:00am .012 1:00am .013 1:00am .009 1:00am .015 1:00am .014 1:00am .021 1:00am .028 1:00am .026 Being Re-used #6 using #3 #7 using #1 #8 using #2 Because of connection pooling they will use MUCH less than 1,000 brand new connections as conn.open statements will be provided with already existing connections invisibly PROVIDING they were closed and thus guaranteed available for re-use. The pool connections can only be re-used if they are closed. They expire in sixty seconds by default. This is all explained in: http://msdn.microsoft.com/library/techart/pooling2.htm http://www.learnASP.com/learn/threadsafe.asp by Charles M. Carroll Page 188 Threading Issues by Charles Carroll with some help from George Reilly All the work done by a webserver is handled by threads. They are the worker bees of the webserver. Any process running on the webserver runs on a given thread. Threads can affect ASP in several ways but we will focus on Thread Safety issues here. A component that is not thread-safe ● Leaks memory and/or places locks on resources in subtle-ways and/or does not behave predictably when many objects are running round-robin. The registry may have settings that indicate it is safe to be invoked many times from many clients and marked and FREE threaded or both, the programmer due to inexperience or lack of stress testing did not truly do the locks, synchronization, memory protection, critical section code they thought they did. ● behaves unstable when many clients are calling it and it's behavior causes the callers damage since they assume each call is safe and handling parameters correctly, etc. ● If they get hit hard and fail in some complex way in some % of their requests, they don't recover gracefully and eat more resources than normal and/or leave locks on memory, disk, resources, etc. and never release them. Thread Safety testing on home-grown components can be done with tools like http://webtool.rte.microsoft.com. Thread Safety issues are more likely to be discovered on multiprocessor machines and that it's vital to stress test components on MP machines to ensure thread safety. WinInet - Not Thread Safe Basically this a serious limitation in current ASP. I recommend finding vendors who have seriously stress-tested (Soft-Artisans comes to mind, Serverobjects.com perhaps) their HTTP components. It is almost guaranteed their implementations are not perfect and are serialized in some situations and not as fast as WinInet, but better than WinInet because slower and less complex internally is better than a faster mess that does systemic damage to the whole process it runs in. http://support.microsoft.com/support/kb/articles/Q188/9/55.ASP explains how it could be used in ASP with light load. http://support.microsoft.com/support/kb/articles/Q183/1/10.ASP http://support.microsoft.com/support/kb/articles/Q238/4/25.ASP explains about Thread-Safe issues. Other articles can be found by searching for kbWinInet (kbASP can be added to qualify it) Because XML core functionality is built on WinInet, I am convinced MS will have to replace/fix WinInet in 6-9 months but in the meantime 3rd party is our safest bet. http://support.microsoft.com/support/kb/articles/q237/9/06.asp There are reasons to believe ASPHTTP from www.serverobjects.com may be thread-safe BUT I don't have any evidence they are or are not. ASP Tear from http://www.alphasierrapapa.com/ComponentCenter/ is built on WinInet so shares its limitations. Dictionaries - Threading Problems in App or Session Vars The scripting dictionary is useful but if used at session or application scope can be slow and prohibit scalability in terms of serialization and resource issues. A FREE replacement interface compatible component can be found at: http://www.caprockconsulting.com/comsoftware.htm http://msdn.microsoft.com/workshop/management/planning/msdnchronicles2.asp explains how Microsoft had difficulty with scalability at session scope on their site. http://msdn.microsoft.com/library/techart/d4cache.htm demonstrates a useful page caching technique. http://support.microsoft.com/support/kb/articles/Q194/8/03.ASP discusses using it as application scope object. A WinNT Option Pack 4 Dictionary Glitch This is only a problem with the original Windows Option Pack. It's fixed in later service packs and Win2K and it's fixed in everything that installs more recent script engines. Also an important note for people who have installed WinNT Option Pack 4 to run ASP*: /iishelp/iis/htm/core/iisread.htm The Scripting.Dictionary object is erroneously marked as Both-threaded. It should be marked as Apartment-threaded. To change this, use the Registry Editor to open the following registry key: HKEY_CLASSES_ROOT\ CLSID \{EE09B103-97E0-11CF-978F-00A02463E06F} \InprocServer32 Change the named value for ThreadingModel to Apartment. If you use the Dictionary object at Application scope without making this change, corruption of data may occur. http://www.learnASP.com/learn/roundrobin.asp by Charles M. Carroll Page 189 Server Code Execution Pattern by Charles Carroll A common expression you will hear when shifting paradigms (Flat Earth to Round Earth, Cold-Blooded to Warm Blooded Dinosaurs, Traditional Applications to Web Apps) is that everything you know is wrong. Great.... My next question is "What is the right answer in this environment?". Often they have only learned to get rid of the wrong tactics, but are not so fluent in the new tactics. Here we will explain the correct things to do. Round-Robin Code Execution Scripts on a webserver run round-robin. If a script say x.asp is run by 100 people and 50 people are running y.asp then the server may be running: Person1 x.asp lines 1-3 Person2 x.asp lines 1-3 Person1 x.asp lines 4-20 Person3 x.asp lines 1-3 Person4 x.asp lines 1-3 Person2 x.asp lines 4-10 Person1 y.asp lines 1-5 Person3 x.asp lines 4-6 etc. So if your process opens recordsets a couple of lines before manipulating them this could lead to more open recordsets for the total webserver than you think. <% rs1.open rs2.open rs3.open rs4.open ... process rs1 ... process rs2 ... process rs3 ... process rs4 rs1.close rs2.close rs3.close rs4.close %> It is certainly more wasteful than ... rs1.open process rs1 rs1.close ... rs2.open ... process rs2 rs2.close rs3.open ... process rs3 rs4.close rs4.open .. process rs4 rs4.close mostly because of the round-robin effect. This is one of the many reason Getrows and GetString, can be so durn fast ala: http://www.learnasp.com/learn/dbtablegetrows.asp http://www.learnasp.com/learn/dbtablegetstring.asp This is also why disconnected recordets can help an application perform better see: http://www.learnasp.com/learn/dbtabledisconnected.asp http://www.learnASP.com/learn/whybuffer.asp by Charles M. Carroll Page 190 Buffer That Output by Charles Carroll In my recent advanced class we recently confirmed my fanatical belief in <%response.buffer=true%> and cautious <%response.flush%> something I hammer into every Intro student I teach every day of my class. We did dozens of millisecond speed tests ala: http://www.learnasp.com/learn/speedtimer.asp reading 500 database records. Every change (Getrows or Getstring, One gulp, or 50 rows at a time, named or numbered fields) was timed. Many of these suboptimizations reduced a 4 second task to 2 seconds. But the buffer strick got it down to 3/10 of a second!!!! Why????? Lets tell the waiter story.... A waiter comes to your table in a busy restaurant. There are 5 at your table. He asks what drink person #1 wants and THEN hops to a different table and lets them order 1 drink and then hops to a different table and asks 1 person what their main course is and then a different table to ask what dessert another person wants. Then he comes back to your table and asks person #2 what drink they want. Then hops all over again. This story is your webserver with <%response.buffer=false%> (the default in IIS4 and IIS3). Though it might seem slower to the adjacent table for him to finish your order, overall it is faster for him to do one at a time. Also if a script is <%response.buffer=false%> the number of gulps it takes to move 10k is determined by the browser and server in a chaotic very hard to determine fashion... 5 gulps of 2k 10 gulps of 1k 3 gulps of 3k + 1k gulp It is not efficient. But if a script is <%response.buffer=true%> ==> 1 gulp of 10k <== If 300 people ask for that script, 300 transfers, not 301...3000 transfers depending on many factors. BUT, lets say you have a page like this: <%response.buffer=true%> ... 1k of HTML ... ... 20k graphic ... ... 45k background sound ... ... 4k of HTML ... Some facts: - The page will serve quicker if many people hit the site. Go back to waiter analogy. 69k in 1 gulp x a couple hundred users is much easier than a couple hundred fragmented gulps. Now the sane man compromises: <%response.buffer=true%> ... 1k of HTML and/or ASP ... <%response.flush%> ... 20k graphic ... <response.flush%> ... 45k background sound ... ... 4k of HTML and/or ASP ... Now: ● ● ● The user sees some output at the browser for every upon each flush. The whole page serves in 3 controlled gulps NO more chaos. Control. Not anarchy. I once had an overloaded 100% CPU server. I changed registry so all pages were buffer=true. The server then oscillated instead of staying pegged at 100%. Proof incarnate. Users were much happier. No money spent no code changes. http://www.learnASP.com/learn/whygetrows.asp by Charles M. Carroll Page 191 GetRows or GetString... Don't retrieve data any other way! http://www.learnasp.com/learn/dbtablegetrows.asp shows how to retrieve data fast but doesn't discuss why. If your data formatting is simple: http://www.learnasp.com/learn/dbtablegetstring.asp can accomplish even faster results. Most people write database retrieval code like his: <% Open Database Do UNTIL eof city=rs("city") st=rs("state") zip=rs("zip") rs.movenext ... process and format data .... LOOP Close database %> If there are 700 records for example, we have 2,100 database read requests over the wire. Lots of round-trips. Actually I am fudging a little here.... It actually will transfer the data in chunk sizes defined by rstemp.cachesize -- setting it or reading it will determine how many gulps it is reading many records in. A cachesize for example of 50 would reduce the previous examples trips to the backend databse to 14 since when you asked for the first record you got 50. Until the MOVENEXT triggers record 51-101 being retrieved. A better alternative code approach: <% Open Database myarray=rstemp.GetRows rstemp.close set rstemp=nothing close database maxcounter=ubound(myarray) For counter=0 to maxcounter city=myarray(counter,1) st=myarray(counter,2) zip=myarray(counter,3) ... process/format data ... NEXT %> One transfer for seven-hundred records. We can close Rs and connection BEFORE formatting or calcing data. Imagine the backend gets to make one transfer. Very efficient. The main reason that people do MOVENEXT and field at a time because that is what they learned. But let us say 300 people hit my main page and it read a database; well if I do my reads without getrows or getstrings I may need a much more powerful CPU as the scripts spin, round-robin and save their context and store their data at a low-level to serve all those users simultaneously. On a webserver every millisecond you waste in one script may be multiplied by tens of thousands of users (Amazon.com, Cnn.com) so it behooves traditional programmers to bite the bullet and throw away one at a time field reads and movenexts. Notice how my Getrows example can close RS and CN before processing data. Lets say do LOOP and PROCESS/FORMAT in the loop. Well, if the reads take 1.5 seconds and the processing/formatting takes 2.5 seconds the database is open for 4 seconds. With Getrows the same operation retrieve might take 3/4 second and the rs and cn are closed and back in the pool for others and the formatting is done while someone else uses the connection and whatever READ locks placed on the data rows/chunks aren't affecting others while formatting is occurring. Does it matter for small amounts of data? YES!!!!!!!! My site has SQLserver scripts that run like lightning. I once needed to fill a 9 item listbox from Access and got 90 sec script timeouts with movenext. Getstring never timed out. So in a real production situation it makes weak databases feasible and of course reduces the load on more industrial back-ends so maybe the SQLserver doesn't need as many indexes or RAM upgrades. http://www.learnASP.com/learn/aspscalability.asp by Charles M. Carroll Page 192 aspscalability Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/aspscalability.asp Send Listserver Questions to aspscalability@ls.asplists.com Related Links Microsoft Enterprise White Paper @ http://www.microsoft.com/NTServer/ntserverenterprise/techdetails/overview/NTSEE.asp L5: A Self Learning Layer-5 Switch @ http://www.research.ibm.com/people/d/debanjan/papers/l5.pdf Performance Of TCP Splcing For URL-Aware Redirection (requires membership) @ http://www.usenix.org/events/usits99/cohen.html Web switches open e-comm doors at Nettaxi @ http://www.nwfusion.com/archive/1999/82163_12-06-1999.html Server Farms, Port Density, Load-Balancing Switch @ http://www.techweb.com/se/directlink.cgi?INW19991018S0017 Enterprise Scaling Benchmarks @ http://www.devx.com/upload/free/features/entdev/1999/08aug99/cs0899/cs0899.asp Fitch & Mathers Intro @ http://www.fmcorp.com/ Radware - Excellent Cluster @ http://www.radware.com Developmentor Load Balancing @ http://www.develop.com/hp/ewald/lb/loadbalancing.htm -no name- @ http://www.level3.com -no name- @ http://www.timesten.com Scalability Resource Kit @ http://www.microsoft.com/siteserver/commerce/DeployAdmin/ResKit.asp Pure SSL acceleration @ http://www.ipivot.com/products/products-ca1000.html Faster SSL Acceleration, deals with AOL too @ http://www.ipivot.com/products/products-cd8000.html Endurance 400 @ http://www.marathontechnologies.com/productinfo/index.htm ArrowPoint Mother Nature Profile @ http://www.arrowpoint.com/solutions/profiles/mother_nature.html Commerce Accelerator 1000, claims 50X faster SSL @ http://www.ipivot.com Cisco's Local Director @ http://www.cisco.com/warp/public/cc/cisco/mkt/scale/locald/ Cisco's Distributed Director, multiple data centers @ http://www.cisco.com/warp/public/cc/cisco/mkt/scale/distr/ BIG IP by F5 @ http://www.bigIP.com Interview with Mother Nature Lead Engineer @ http://www.internetwk.com/story/INW19990416S0005 RSW Load Balance Analyzer @ http://www.rswsoftware.com/products/eload.html http://www.learnASP.com/learn/webcom.asp by Charles M. Carroll Page 193 Index Server via ADO (indexserver.asp) - Page 194 Commerce and ASP (commerce.asp) - Page 195 Server JavaScript: Resources (javascript.asp) - Page 196 Validation Resources (validationmore.asp) - Page 197 Listboxes: Linked Dynamically w/JavaScript (listdynamic.asp) - Page 198 Dynamic ListBox Online Examples (listdynamicmore.asp) - Page 199 Listboxes: Linked Dynamically from Database w/JavaScript (listdynamicdb.asp) - Page 200 Listboxes: Easy Choices by Bill Wilkinson (listdual.asp) - Page 201 Server Perlscript: Resources (perlscript.asp) - Page 202 Remote Scripting Simple Example (remotescripting.asp) - Page 203 Remote Scripting Microsoft Example (remotescriptingms.asp) - Page 204 RDS: Remote Data Services Intro (rds.asp) - Page 205 RDS Resources by Carl Prothman (prothman.asp) - Page 206 ADSI: Active Directory Services Interface Intro (ADSI.asp) - Page 207 MSMQ: Overview (MSMQ.asp) - Page 208 Usability: Resources (usability.asp) - Page 209 Usability: Safe Color Pallete (safecolors.asp) - Page 210 http://www.learnASP.com/learn/indexserver.asp by Charles M. Carroll Page 194 Index Server Access via ADO by Charles Carroll The script below demonstrates how Index Server can be accessed via ADO to do simple searches. 1 2 3 4 5 6 7 8 9 <html><head> <title>iskeyword.asp</title> </head><body bgcolor="#FFFFFF"> <Form action = "iskeywordRespond.asp" method="get"> Choose The Word You Want to Search For::<p> Search Word: <Input NAME="Keyword" size ="30"><br> <Input type="submit" value="Find The Documents!"> </form> </body></html> The iskeywordrespond.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <html><head> <title>iskeywordrespond.asp</title> </head> <body> <% Set objQuery = Server.CreateObject("ixsso.query") Set objUtil = Server.CreateObject("ixsso.util") my_keyword=request("keyword") objquery.catalog="" objQuery.Query = my_keyword objQuery.Columns = "Vpath, DocTitle, Filename, Characterization, Contents,DocKeyWords, Rank" objQuery.SortBy = "Rank [d]" objQuery.MaxRecords = 50 objUtil.AddScopeToQuery objQuery, "/", "DEEP" linebr="<br>" & vbcrlf Set rstemp = objQuery.CreateRecordSet("nonsequential") DO UNTIL rstemp.eof FOR EACH key in rstemp.fields keyname=lcase(key.name) SELECT CASE keyname CASE "vpath" response.write "<a href='" response.write key response.write "'>" & key & "</a>" & linebr CASE ELSE response.write "<b>" & keyname & ":</b>" & linebr response.write key & linebr END SELECT NEXT response.write "<br><hr>" rstemp.movenext LOOP ' clean up rstemp.close set rstemp=nothing Set objQuery = nothing Set objUtil = nothing 40 41 42 %> </body> </html> http://www.learnASP.com/learn/commerce.asp by Charles M. Carroll Page 195 ASP Commerce Active Server Pages is commonly used to setup Ecommerce web sites. We have a pretty thorough list of Ecommerce ASP components at: http://www.activeserverpages.com/components/ecommerce.asp People having trouble with ASP can sign up for the [ecommerce] listserv: ecommerce Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/commerce.asp Send Listserver Questions to ecommerce@ls.asplists.com Related Links UPS shipping Interface @ http://www.ups.com/bussol/solutions/index.html MOD10 Credit Card Validation @ http://www.15seconds.com/issue/970101.htm How do I setup https://,get a certificate @ http://www.learnasp.com/learn/FAQCommerceCertif.asp I want to process credit cards, where to start? @ http://www.learnasp.com/learn/FAQCommerceCharge.asp What ASP Components & Shopping Carts are available? @ http://www.learnasp.com/learn/FAQCommerceCarts.asp Banner Ad Rotation from Database @ http://www.4guysfromrolla.com/webtech/091299-1.shtml Install a SSL Certificate @ http://www.4guysfromrolla.com/webtech/062299-1.shtml E-Commerce Sites built with MS ASP @ http://www.microsoft.com/dns/ecommerce/default.htm http://www.learnASP.com/learn/javascript.asp by Charles M. Carroll Page 196 Jscript On the Server by Charles Carroll Jscript is an alternative language to VBscript that can be used to build ASP pages. It is a language preferred by a small percentage of ASP programmers, but most new programmers use VBScript as it is easier. If you have using Jscript to program your ASP sites, we run a listserv/newgroup called [Jscript] where that is the only topic allowed you can join to get help. jscript Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/javascript.asp Send Listserver Questions to jscript@ls.asplists.com Related Links Wise ASP Jscript Column @ http://www.aspalliance.com/wsk Closing Jscript Database Connections @ http://www.learnasp.com/learn/FAQJscriptCleanUp.asp JavaScript/Jscript Links @ http://www.learnasp.com/webbuilding/jscript.asp Phil Malones Jscript column @ http://www.aspalliance.com/philmalone VB functions converted to Jscript @ http://www.4GuysFromRolla.com/webtech/vb2java.shtml ListBox from DB using Jscript @ http://www.aspmagazine.com/aspmagazine/issue10jscript.asp Book: Danny Goodmans Jscript Bible @ http://www.learnasp.com/books/goodmanjscript.asp Book: Oreilly Definitive JavaScript @ http://www.learnasp.com/books/jscriptdefinitive.asp Listboxes Dynamically Linked w/Jscript @ http://www.learnasp.com/learn/listdynamic.asp Listboxes Dynamically Linked w/Jscript + Database @ http://www.learnasp.com/learn/listdynamicdb.asp Listboxes Dynamically Linked - Online Examples @ http://www.learnasp.com/learn/listdynamicmore.asp 10 Open Window Techniques @ http://www.builder.com/Programming/JSWinTips/?tag=st.cn.sr1.dir Client Jscript and ASP Mixed @ http://www.clearviewdesign.com/NEWBIE.asp http://www.learnASP.com/learn/validationmore.asp by Charles M. Carroll Page 197 Validation Resources Validation is handled in much more depth at other sites actually. One of my favorite sites www.4guysfromrolla.com has several validation articles that are excellent: Validate What? Using Regular Expressions to Validate Input http://www.4guysfromrolla.com/webtech/050399-2.shtml Client-side Form Validation Using JavaScript (contains an extensive library of validation functions) http://www.4guysfromrolla.com/webtech/091998-1.shtml The Importance of Server-Side Form Validation (explains why server-side form validation is important also) http://www.4guysfromrolla.com/webtech/120199-1.shtml Email Validation Routines (this article presents code for three ways to validate email: using client-side scripting, using server-side scripting w/VBScript, and using server-side scripting w/JScript) http://www.4guysfromrolla.com/webtech/validateemail.shtml AspToday.com has also written some great articles on validation. Advanced Client-Side Form Validation by Steve Smith http://www.asptoday.com/articles/19990611.htm Professional Form Validation by Jay McKinney http://www.asptoday.com/articles/19990303.htm Advanced Form Validation By Andrea Chiarelli http://www.asptoday.com/articles/19990708.htm A Library of regular Expressions for Form Validation By Alexander Nakhimovsk http://www.asptoday.com/articles/19990629.htm Persisting Form Control Values with ASP by Alex Homer http://www.asptoday.com/articles/19990331.htm http://www.learnASP.com/learn/listdynamic.asp by Charles M. Carroll Page 198 Dynamic Client Dependent Lists/JScript Sometimes you need a Listbox that changes in response to a value of another listbox. The most effective way is to use client-side Jscript as illustrated below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <HTML> <HEAD><TITLE>Dynamic Select Lists</Title></Head> <BODY OnLoad="BuildContacts(0);"> <FORM Name="myForm"> Salesperson: <SELECT Name="SalesNames" OnChange="BuildContacts(this.selectedIndex);"> <OPTION Value="Jeff">Jeff <OPTION Value="Charles">Charles <OPTION Value="Rick">Rick <OPTION Value="Kevin">Kevin </Select> <BR><BR> Contacts: <!-- We want to define at least one option so that the select tag is created with the correct dimensions--> <SELECT Name="SalesContacts"> <OPTION Value="">-------</Select> </Form> </Body> </Html> <SCRIPT Language="JavaScript"><!-//Build arrays for each person's contacts Contacts=new Array(4); Contacts[0]=new Array(3); Contacts[1]=new Array(2); Contacts[2]=new Array(5); Contacts[3]=new Array(4); //Charles Contacts[0][0]="Bill"; Contacts[0][1]="Bob"; Contacts[0][2]="Chuck"; 37 //Jeff 38 Contacts[1][0]="Vern"; 39 Contacts[1][1]="Matt"; 40 41 //Rick 42 Contacts[2][0]="Diana"; 43 Contacts[2][1]="Dave"; 44 Contacts[2][2]="Todd"; 45 Contacts[2][3]="Sherry"; 46 Contacts[2][4]="Sharon"; 47 48 //Kevin 49 Contacts[3][0]="Brian"; 50 Contacts[3][1]="Trisha"; 51 Contacts[3][2]="Greg"; 52 Contacts[3][3]="Troy"; 53 54 //Call this to build the Contact list for the specified Salesperson 55 function BuildContacts(num) 56 { 57 //Select the first Contact 58 document.myForm.SalesContacts.selectedIndex=0; 59 60 //For every contact in the array for this person, add a new option 61 for(ctr=0;ctr<Contacts[num].length;ctr++) 62 { 63 document.myForm.SalesContacts.options[ctr]=new Option(Contacts[num][ctr],Contacts[num][ctr]); 64 } 65 //Set the length of the select list 66 document.myForm.SalesContacts.length=Contacts[num].length; 67 } 68 //--></Script> http://www.learnASP.com/learn/listdynamicmore.asp by Charles M. Carroll Page 199 Dynamic Lists/JScript Resources There are actually many approaches to creating dynamic lists with Jscript where a change in one listbox affects what options appear in the other listbox that are explained on various websites: http://www.atgconsulting.com/doublelist.asp http://www.atgconsulting.com/triplelist.asp http://webreference.com/dev/menus/ http://www.amerirus.com/tutor.html http://n2.neoshop.com/ shows how to use remote scripting http://www.learnASP.com/learn/listdynamicdb.asp by Charles M. Carroll Page 200 Dynamic Dependent Lists/JScript generated from Relational Database This example shows how to tie a relational database together to form dependent list boxes with Client Jscript. We have made a generic subroutine to handle it, but be warned... The insides of it are one of the most complicated examples on this site. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <html><head> <title>listdynamicdb.asp</title>& <BODY OnLoad="StartMeUp();"> <FORM Name="myForm"> <% dim query myDSN="DSN=Student;uid=student;pwd=magic" mySQL= "SELECT Titles.Title, Publishers.Name " mySQL= mySQL & "FROM Publishers " mySQL= mySQL & "INNER JOIN Titles ON Publishers.PubID = Titles.PubID " call listmaker(myDSN, mySQL, _ pubnames,"publist",booknames,"booklist",_ pubevent,pubfun, "myForm") %> Publisher: <%response.write pubnames%><br> Books: <%response.write booknames%><br> </Form> </Body></Html> <SCRIPT Language="JavaScript"><!-function StartMeUp() { alert("All Books are Loaded Now. Thanks for waiting!"); } <%=pubevent%> <%=pubfun%> --></Script> <!--#include file="lib_listdynamicdb.asp"--> Here is the include file that defines the subroutine that does most of the work: 1 <% 2 SUB listmaker(myDSN,query,byref list1, listname1, byref list2, listname2, byref myevent, byref myfun, myform) 3 ' Build the INNER JOIN needed first 4 set conntemp=server.createobject("adodb.connection") 5 conntemp.open myDSN 6 set rstemp=conntemp.execute(query) 7 list1="<select name=""" & listname1 & """" 8 list1=list1 & " OnChange=""Build" & key 9 list1=list1 & "(this.selectedIndex);"">" 10 list2="<select name=""" & listname2 & """>" 11 loopcounter=0 12 lastvalue=rstemp(0) 13 redim tempArray(1) 14 thisgroupcount=0 15 howmanygroups=0 16 DO UNTIL rstemp.eof 17 loopcounter=loopcounter+1 18 thisvalue=rstemp(0) 19 thisvalue2=rstemp(1) 20 if thisvalue<>lastvalue then 21 tempSTR=key & "[" & howmanygroups & _ 22 "]=new Array(" & thisgroupcount & ");" & _ 23 vbcrlf & tempSTR 24 thisgroupcount=0 25 howmanygroups=howmanygroups+1 26 end if 27 if thisgroupcount=0 then 28 tempSTR=tempSTR & "// " & thisvalue & vbcrlf 29 list1 = list1 & "<option>" & thisvalue & "</option>" & vbcrlf 30 end if 31 tempSTR=TempSTR & key & "[" & howmanygroups & "][" & thisgroupcount & "]=""" & thisvalue2 & """;" & vbCRLF 32 thisgroupcount=thisgroupcount+1 33 if howmanygroups=0 then 34 list2 = list2 & "<option>" & thisvalue2 & "</option>" & vbcrlf 35 end if 36 lastvalue=thisvalue 37 rstemp.movenext 38 IF response.isclientconnected=false THEN 39 EXIT DO 40 END IF 41 LOOP 42 tempSTR=key & "[" & howmanygroups & _ 43 "]=new Array(" & thisgroupcount & ");" & _ 44 vbcrlf & tempSTR 45 list1=list1 & "</select>" 46 list2=list2 & "</select>" 47 myevent=vbcrlf & key & "=new Array(" & howmanygroups+1 48 myevent=myevent & ");" & vbcrlf & tempSTR 49 rstemp.close 50 set rstemp=nothing 51 conntemp.close 52 set conntemp=nothing 53 tempSTR =vbcrlf & "function Build" & Key & "(num)" & vbcrlf 54 tempSTR =tempSTR & "{" & vbcrlf 55 tempSTR =tempSTR & "document." & myForm & "." 56 tempSTR =tempSTR & listname2 & ".selectedIndex=0;" & vbcrlf 57 tempSTR =tempSTR & "for(ctr=0;ctr<" & key & "[num].length;ctr++)" & vbcrlf 58 tempSTR =tempSTR & "{" & vbcrlf 59 tempSTR =tempSTR & "document." & myform & "." & listname2 60 tempSTR =tempSTR & ".options[ctr]=new Option(" & key & "[num][ctr]," 61 tempSTR =tempSTR & key & "[num][ctr]);" & vbcrlf 62 tempSTR =tempSTR & "}" & vbcrlf 63 tempSTR =tempSTR & "document." & myForm & "." & listname2 64 tempSTR =tempSTR & ".length=" & key & "[num].length;" & vbcrlf 65 tempSTR =tempSTR & "}" & vbcrlf 66 myfun=tempSTR 67 END SUB 68 %> http://www.learnASP.com/learn/listdual.asp by Charles M. Carroll Page 201 Dual List Boxes by Bill Wilkinson (billw@chilisoft.com) One nice thing to do is allow users to use one list box and another to transfer elements elegantly. It makes for a friendly interface. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html> <body> <% Dim Available Dim Chosen If Session("BeenHere") <> "DoneThat" Then ' First time to this page! ' ' In "real life" you'd probably populate the ' "initialItems" array from a database query, ' but for demo purposes we'll do it this way: ' 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 initialItems = Array("Apples","Oranges","Grapes","Berries","Kiwis") ' Set Available = CreateObject("Scripting.Dictionary") For i = 0 To UBound( initialItems ) Available.add initialItems( i ), "no" ' no means not chosen Next ' ' save for next time here ' Set Session("Choices") = Available ' ' set the flag so we don't do this again ' Session("BeenHere") = "DoneThat" Else ' if BeenHere *DOES* equal "DoneThat"... ' ' Been here before...process requests... ' ' First, retrieve what we remembered from before... ' Set Available = Session("Choices") ' ' including any error message? ' Message = Session("Message") ' ' Then decide what to do ' ' We might be here because of "Add" button, ' "Remove" button, or just because user hit ' "BACK" in the browser. ' If Request.Form("AddFromAvailable") = "Add >>" Then ' user asked to add some value(s) For i = 1 To Request.Form("ItemsAvailable").Count item = Request.Form("ItemsAvailable")(i) If item <> "#" Then Available(item) = "yes" ' now chosen! End If Next ' End If If Request.Form("RemoveFromChosen") = "<< Remove" Then ' user asked to remove some previously chosen values For i = 1 To Request.Form("ItemsChosen").Count item = Request.Form("ItemsChosen")(i) If item <> "#" Then Available(item) = "no" ' no longer chosen End If Next ' End If ' ' save for next time here ' Set Session("Choices") = Available End If ' miscellany: iCount = Available.count + 1 %> 82 <center> 83 84 <font Size="+2"> 85 Dual List Query Demo: Page 1 86 </font> 87 88 <% 89 If Left( Message, 1 ) <> "#" Then 90 %> 91 <p> 92 <font Size="+1"><em> 93 <strong>Notice:</strong> <% = Message %> 94 </em></font> 95 <% 96 End If 97 %> 98 99 <p> <p> <p> 100 101 <form Name="ModifyLists" Action="listdual.asp" Method="POST"> 102 103 <table Border="2" CellSpacing="5" CellPadding="5"> 104 105 <tr> 106 <td>Available Items</td> 107 <td> </td> 108 <td>Items to Look For</td> 109 </tr> 110 <tr> 111 <td> 112 <select Name="ItemsAvailable" Multiple Size="<% = iCount %>" Width="150"> 113 <% 114 aKeys = Available.keys 115 For i = 0 To UBound( aKeys ) 116 item = aKeys( i ) 117 ' In this demo, we do NOT display already chosen 118 ' items in the "available" Select list...but 119 ' you could easily eliminate the following 120 ' If...Then test and always display all available 121 ' choices, if you preferred! 122 ' 123 If Available( item ) = "no" Then 124 %> 125 <option Value="<% = item %>"><%= item %></option> 126 <% 127 End If 128 Next 129 ' 130 ' Value="#" option is just to give a minimum 131 ' width to the Select list when it would 132 ' otherwise be empty: 133 %> 134 <option Value="#"> 135 136 137 138 </option> 139 </select> 140 </td> 141 142 <td> 143 <table Border="0"> 144 <tr><td> </td></tr> 145 <tr><td><input Type="Submit" Name="AddFromAvailable" Value="Add >>"></td></tr> 146 <tr><td> </td></tr> 147 <tr><td><input Type="Submit" Name="RemoveFromChosen" Value="<< Remove"></td></tr> 148 <tr><td> </td></tr> 149 </table> 150 </td> 151 152 <td> 153 <select Name="ItemsChosen" Multiple Size="<% = iCount %>" Width="150"> 154 <% 155 chosenCount = 0 156 aKeys = Available.keys 157 For i = 0 To UBound( aKeys ) 158 item = aKeys( i ) 159 ' 160 ' we only display chosen "yes" items here... 161 ' 162 If Available( item ) = "yes" Then 163 chosenCount = chosenCount + 1 164 %> 165 <option Value="<% = item %>"><%= item %></option> 166 <% 167 End If 168 Next 169 %> 170 <option Value="#"> 171 172 173 174 </option> 175 </select> 176 </td> 177 178 </tr> 179 180 </table> 181 182 </form> 183 184 <form Name="ProcessQuery" Action="listdualrespond.asp" Method="POST"> 185 <center> 186 <input Type="Submit" Name="Query" Value="Look in DB"> 187 </center> 188 </form> 189 190 <% 191 ' Clean up by setting appropriate flags! 192 ' 193 Session("ChosenCount") = chosenCount 194 Session("Message") = "#none" 195 %> 196 197 </body> 198 </html> 199 Here is the responder script. 1 2 3 4 5 6 7 8 9 10 11 12 <% ' ' Protection: You can't come here until ' you have set up the session variable ' with the list of choices. ' If Session("BeenHere") <> "DoneThat" Then Response.Redirect "DualList.asp" End If ' ' We don't try to process queries until 13 ' we have at least one item chosen... 14 ' Naturally, you could change this to 15 ' use some default instead! 16 ' 17 If Session("ChosenCount") = 0 Then 18 Session("Message") = "You must place at least one item in the right hand list before asking for a query." 19 Response.Redirect "DualList.asp" 20 End If 21 %> 22 23 <HTML> 24 <BODY> 25 26 <CENTER> 27 <FONT Size="+2"> 28 Dual List Query Demo: Page 2 29 </FONT> 30 <P> <P> 31 32 This page is a dummy.<br> 33 It just shows a list of the items chosen<br> 34 on the prior page. In a real application<br> 35 presumably these items would be processed<br> 36 by some sort of database query.<P> 37 38 <P><FONT Size="+1">The List:</FONT><P> 39 <OL> 40 41 <% 42 Set Chosen = Session("Choices") 43 aKeys = Chosen.keys 44 For i = 0 To UBound( aKeys ) 45 item = aKeys( i ) 46 If Chosen( item ) = "yes" Then 47 Response.Write "<LI>" & item & vbCrLf 48 End If 49 Next 50 %> 51 52 </OL> 53 54 </CENTER> 55 </BODY> 56 </HTML> 57 58 http://www.learnASP.com/learn/perlscript.asp by Charles M. Carroll Page 202 PerlScript on the Server by Charles Carroll Perlscript is an alternative server scripting language that is available for FREE from www.activestate.com It is a language preferred by a small percentage of ASP programmers, but most use VBScript as it is easier. If you have using Perlscript to program your ASP sites, we run a listserv/newgroup called [Perlscript] where that is the only topic allowed you can join to get help. aspperlscript Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/perlscript.asp Send Listserver Questions to aspperlscript@ls.asplists.com Related Links ActiveState - Perl Suppliers @ http://www.activestate.com Tobias Martinsson's Site @ http://www.perlscripters.com Matt's Perl Pages @ http://www.fastnetltd.ndirect.co.uk/Perl/ Roth Consulting @ http://www.roth.net/ O'Reilly's Perl Conference @ http://conference.oreilly.com/perl3/ Perl Reference Sites & Newsgroups @ http://www.activestate.com/reference/related_sites.htm http://www.learnASP.com/learn/remotescripting.asp by Charles M. Carroll Page 203 Remote Scripting Basics by Charles Carroll Remote Scripting is a magical, infinitely powerful Javascript client library that allows: ● Javascript in an HTML or ASP page to call an ASP subroutine on the server to fetch data ● dynamic page construction via Javascript that could be for example fetching database data for a page without reloading the page. The main limitations are ● ● the browser must be a 4.x browser It doesn't work on IE Mac (thanks to "Brad Rhoads" <brad@data-science.com> for that tip) The current version requires 3 files: rs.asp, rs.htm and rsprox.class which can be downloaded from http://msdn.microsoft.com/scripting on the server to work and their exact path must be set in the files (/learn/test/remote/ is the path in these samples). Our sample remote1.htm looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <HTML><HEAD><TITLE>remote1.htm</TITLE></HEAD> <BODY onload="handleRSExecute()"> <script language="JavaScript" src="/learn/test/remote/rs.htm"></script> <script language="JavaScript">RSEnableRemoteScripting("/learn/test/remote/");</script> <h2>Simple Remote Scripting Example</h2> <form name="remote1"> The Test <input type="text" name="test" value="none"><br> <SCRIPT LANGUAGE="javascript"> var serverURL = "remote1.asp"; function myCallBack(co) { // document.write (co.return_value); remote1.test.value=co.return_value; } 16 17 18 19 20 21 22 23 24 function handleRSExecute() { var co = RSExecute(serverURL,"Method3"); myCallBack(co); } </SCRIPT> </form> </HTML> Our sample remote1.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <%@ LANGUAGE=VBSCRIPT %> <% RSDispatch %> <!--#INCLUDE VIRTUAL="/learn/test/remote/rs.asp"--> <SCRIPT RUNAT=SERVER Language=javascript> function Description() { this.Method1 = Method1; this.Method2 = Method2; this.Method3 = Method3; } public_description = new Description(); function Method1() { return "method1"; } function Method2() { return "method2"; } function Method3() { return "method3"; } </script> http://www.learnASP.com/learn/remotescriptingms.asp by Charles M. Carroll Page 204 Remote Scripting MS Sample Microsoft created an obtuse, complex to read Remote Scripting sample that demonstrates all it's capabilities we will reproduce here in running form: remotems.htm looks like this: 1 2 3 4 5 6 7 8 9 10 <HTML> <HEAD> <TITLE>SIMPLE CLIENT</TITLE> </HEAD> <BODY> <script language="JavaScript" src="/learn/test/remote/rs.htm"></script> <script language="JavaScript">RSEnableRemoteScripting("/learn/test/remote/");</script> <h2>Simple Remote Scripting Example</h2> 11 12 <br> 13 The following buttons invoke remote scripting calls to an ASP server. 14 <br> 15 <form> 16 <br><br><input type=button name=btnRSExecute value="RSExecute Method1" onclick="handleRSExecute()" style="width:250;height:25"> 17 <br><br><input type=button name=btnRSExecuteAsynch value="RSExecute Method1 (async)" onclick="handleRSExecuteAsync()" style="width:250;height:25"> 18 <br><br><input type=button name=btnRSGetASPObject value="aspObject = RSGetASPObject" onclick="handleRSGetAspObject()" style="width:250;height:25"> 19 <br><br><input type=button name=btnASPObject value="aspObject.Method2 (async)" onclick="handleAspObject()" style="width:250;height:25"> 20 <br><br><input type=button name=btnInvalidCall value="RSExecute Invalid Method3" onclick="handleInvalidCall()" style="width:250;height:25"> 21 22 <SCRIPT LANGUAGE="javascript"> 23 24 var serverURL = "remotems.asp"; 25 var aspObject; 26 27 function myCallBack(co) 28 { 29 alert("CALLBACK\n\n" + 30 "status = " + co.status + "\n\n" + 31 "message = " + co.message + "\n\n" + 32 "context = " + co.context + "\n\n" + 33 "data = " + co.data + "\n\n" + 34 "return_value = " + co.return_value); 35 } 36 37 function errorCallBack(co) 38 { 39 alert("ERROR_CALLBACK\n\n" + 40 "status = " + co.status + "\n\n" + 41 "message = " + co.message + "\n\n" + 42 "context = " + co.context + "\n\n" + 43 "data = " + co.data); 44 } 45 46 function handleRSExecute() 47 { 48 var co = RSExecute(serverURL,"Method1"); 49 myCallBack(co); 50 } 51 52 function handleRSExecuteAsync() 53 { 54 RSExecute(serverURL,"Method1",myCallBack,"RSExecute"); 55 } 56 57 function handleRSGetAspObject() 58 { 59 aspObject = RSGetASPObject(serverURL); 60 var msg = "aspObject public_description\n"; 61 for (name in aspObject) 62 msg += " " + name + "\n"; 63 alert(msg); 64 } 65 66 function handleAspObject() 67 { 68 aspObject.Method2(myCallBack,errorCallBack,"aspObject"); 69 } 70 71 function handleInvalidCall() 72 { 73 74 75 76 77 78 79 80 81 82 var co = RSExecute(serverURL,"Method3",myCallBack,errorCallBack,"Invalid RSExecute"); } </SCRIPT> </form> </BODY> </HTML> remotems.asp looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <%@ LANGUAGE=VBSCRIPT %> <% RSDispatch %> <!--#INCLUDE VIRTUAL="/learn/test/remote/rs.asp"--> <SCRIPT RUNAT=SERVER Language=javascript> function Description() { this.Method1 = Method1; this.Method2 = Method2; } public_description = new Description(); function Method1() { return new Date; } function Method2() { return new Array("blue","red","green","yellow","orange","purple","cyan","magenta"); } </SCRIPT> http://www.learnASP.com/learn/rds.asp by Charles M. Carroll Page 205 Remote Data Services (RDS) by Charles Carroll RDS is limited to IE4 but it's power is astonishing as it transforms ADO into the same kind of technology used by Access and Visual Basic to connect databases to live forms but in a web context. If you have integrating RDS with your ASP sites, we run a listserv/newgroup called [aspRDS] where that is the only topic allowed you can join to get help. asprds Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/rds.asp Send Listserver Questions to asprds@ls.asplists.com Related Links RDS FAQ by Carl Prothman @ http://www.able-consulting.com/RDS_Faq.htm RDS Tutorial @ http://msdn.microsoft.com/library/psdk/dasdk/mdat2n8s.htm RDS Overview @ http://msdn.microsoft.com/library/psdk/dasdk/mdov17z9.htm RDS Developer's Guide @ http://msdn.microsoft.com/library/psdk/dasdk/mdad5lpz.htm ADO Sample Applications (includes RDS samples) @ http://msdn.microsoft.com/library/psdk/dasdk/mdas6c1f.htm ADO Code Examples (includes RDS examples) @ http://msdn.microsoft.com/library/psdk/dasdk/mdae550z.htm Carl Prothmans RDS Book List @ http://www.able-consulting.com/books_ado.htm On Creating a Recordset with RDS @ http://www.asptoday.com/articles/19990813.htm RDS Data Factory @ http://www.asptoday.com/articles/19990607.htm RDS & COM @ http://www.asptoday.com/articles/19990326.htm Web-Based DB Apps using RDS & ASP @ http://www.15seconds.com/issue/980527.htm Intro to RDS @ http://www.aspwatch.com/c/e/e179B1FBB2B7011D3BBF800A0CC3BDC77.asp Remote Data Access & ADO @ http://www.asp101.com/ado/18350701.asp http://www.learnASP.com/learn/prothman.asp by Charles M. Carroll Page 206 Carl Prothman's RDS Info http://www.able-consulting.com/tech.htm has all his technical articles which include ADO Connection strings @ http://www.able-consulting.com/ADO_Conn.htm ADO FAQ @ http://www.able-consulting.com/ADO_Faq.htm RDS FAQ @ : http://www.able-consulting.com/RDS_Faq.htm Konwledge Base Links @ http://www.able-consulting.com/KB_MDAC.htm http://www.learnASP.com/learn/ADSI.asp by Charles M. Carroll Page 207 ADSI and ASP by Charles Carroll ADSI stands for Active Directory Server Interface and it basically is a com object to allow ASP (or any language) to interogate and manipulate the types of objects that are managed by servers traditionally: domains, groups, users, passwords, directory listings. It is intended to be an integral part of NT5 and will also be extended to communicate with a variety of server architectures (Netscape Servers, Novell servers, LDAP servers) but it is available today in beta form for downloading. Here is a up-to-date list of where you can find out about this bleeding edge technology: http://www.15seconds.com/focus/ADSI.htm has everything about ADSI you would want to know and is running a well managed, low-noise list-serve devoted to ADSI. http://www.netfokus.dk/vbadmincode/ is a great source for FREE Visual Basic code to manage NT servers that easily adapts to ASP or can be used in a VB/ASP Component. ADSI listserv by 15seconds.com to: -> LISTSERV@LISTSERV.15SECONDS.COM body (not subject) -> SUBSCRIBE ADSI Your Name http://www.jfkdesigns.com/default.asp?go=ADSI has some FREE ADSI scripts http://www.learnASP.com/learn/MSMQ.asp by Charles M. Carroll Page 208 MSMQ -- Microsoft Message Que Overview by Charles Carroll Microsoft Message Que is a programming tool that simplifies building client-server applications that can be robust and reliable even when all the components of the architecture are not functioning perfectly 24 x 7. If your code currently requests that another server (be it the database back end or other services) perform a task and that server is down or overloaded, it is imperative that the request be eventually serviced or be able to continue without catastrophically failing. It should be able to send a request, and then await an answer, as opposed to request immediate fullfillment -- something that cannot be accomodated if the service being requested is temporaily unavailable. Traditional Approach Client => send request => Server => send result => Client The traditional approach fails catastrophically if the server is down or the client is down at the instance the communication occurs. And if either fails and restarts, the results are usually not coded for and the task is left inderminately resolved. MSMQ Approach Client => send request through MSMQ Client => check results through MSMQ Server => check for requests through MSMQ Server => send results through MSMQ In the MSMQ Approach, whether each side is up or down does not affect the other, though it may introduce delays. There is no direct communication. http://www.learnASP.com/learn/usability.asp by Charles M. Carroll Page 209 Usability Issues by Charles Carroll Usability is critical when making a sucessfull website. According to Web Guru, Jakob Neilsen, only 10% of the web sites achieve high usability. So people flock to those and spend little time at the 90% that do not. Jakob Neilsen's site is a treasure trove of usability information at: http://www.useit.com/ Alan Cooper was my favorite guru for building Desktop Applications and much of his wisdom becomes relevant if someone is using rich client technologies like browser scripting, dynamic HTML, etc. His website can be found at: http://www.cooper.com http://www.learnASP.com/learn/safecolors.asp by Charles M. Carroll Page 210 Safe Colors by Charles Carroll The script below demonstrates two things: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 ● how easy it is to mix Jscript and VBscript in the same file ● samples of web safe colors. These colors will appear the same on almost everybody's browser. Other colors may appear dramatically different from browser to browser. <html><head> <title>websafe.asp</title>& <body> <% spacer=" " response.write "<strong><font size='2'><table border=1>" for counter=1 to 6 safecolor1=websafe(counter) for counter2=1 to 6 safecolor2=websafe(counter2) for counter3= 1 to 6 safecolor3=websafe(counter3) hexcolor=convertToHex(safecolor1,safecolor2,safecolor3) response.write "<tr><td>" & hexcolor & "</td>" response.write "<td bgcolor='" & hexcolor & "'>" response.write "Black Text</td>" response.write "<td bgcolor='" & hexcolor & "'>" & spacer & "</td>" response.write "<td bgcolor='" & hexcolor & "'><font color='white'>" response.write "White Text</td>" response.write "<td bgcolor='" & white & "'><font color='" & hexcolor & "'>" response.write "Colored Text</font></td></tr>" next next next response.write "</strong></font></table>" %> </body></html> <% function websafe(mynumber) SELECT CASE mynumber CASE 1 websafe=0 CASE 2 websafe=51 CASE 3 websafe=102 CASE 4 websafe=153 CASE 5 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 websafe=204 CASE 6 websafe=255 END SELECT end function %> <script language=jscript runat=server> function convertToHex(R, G, B) { var n = B; n += G << 8; n += R << 16; return convertBase(n); } // turns decimal integer into hexadecimal string function convertBase(num) { var i = 0; var j = 20; var str = "#"; while(j >= 0) { i = (num >> j)%16; if(i >= 10) { if(i == 10) str += "A"; else if(i == 11) str += else if(i == 12) str += else if(i == 13) str += else if(i == 14) str += else str += "F"; } else str += i; j -= 4; } "B"; "C"; "D"; "E"; return str; } </script> http://www.learnASP.com/learn/research.asp by Charles M. Carroll Page 211 Must Buy Component Building Book (bookcomponents.asp) - Page 212 ASP101.com Scripts for your site (asp101.asp) - Page 213 4GuysFromRolla.com Tons of ASP Material (4guysfromrolla.asp) - Page 214 ASPToday.com from WROX (asptoday.asp) - Page 215 http://www.learnASP.com/learn/bookcomponents.asp by Charles M. Carroll Page 212 Developing ASP Components published by Oreilly written by Shelly Powers OUR SUMMARY: This is THE ASP Book of 1999. Lucid, detailed. Great for beginners, full of substance for experts. Component building in 3 languages: C++, Java and Visual Basic. Microsoft Transaction Server covered beautifully as well. Find out why Charles Carroll calls Shelly Powers the component goddess. BUY IT INFO ONLINE http://bn.bfast.com/booklink/click?sourceid=10446528&ISBN=1565924460 http://www.oreilly.com/catalog/devaspcom/ http://www.yasd.com http://www.learnASP.com/learn/asp101.asp by Charles M. Carroll Page 213 ASP101.com: A Script Resource A site with a lot of nice scripts is www.asp101.com. I will mention some of my favorite scripts here to provide you with a brief tour of the site. Look around, you may have totally different tastes; they have dozens of scripts I am not linking to which are quite clever. They also give away prizes as part of contests frequently there. Calendar @ http://www.asp101.com/samples/calendar.asp Universal Database Viewer @ http://www.asp101.com/samples/db_dsn.asp Shopping Cart @ http://www.asp101.com/samples/shopping.asp Hangman implemented in ASP @ http://www.asp101.com/samples/hangman.asp http://www.learnASP.com/learn/4guysfromrolla.asp by Charles M. Carroll Page 214 4GuysfromRolla.com: Huge, In-depth ASP Articles A site with some fairly in-depth material is www.4guysfromrolla.com.I will mention some of my favorite articles there that cover topics we do not touch on. Look around, you may have totally different tastes; they have dozens of scripts I am not linking to which are quite clever. They also give away prizes as part of contests frequently there. THIS SITE IS HUGE. YOU COULD SPEND WEEKS THERE!!! Master Article Index @ http://www.4guysfromrolla.com/webtech/index_asp.shtml CDO Emails with ASP @ http://www.4guysfromrolla.com/webtech/112298-1.shtml VBScript to JavaScript Function Index @ http://www.4guysfromrolla.com/webtech/vb2java.shtml A VBScrip implementation of QuickSort @ http://4guysfromrolla.com/webtech/012799-2.shtml http://www.learnASP.com/learn/asptoday.asp by Charles M. Carroll Page 215 ASPToday.com - Free Online ASP Magazine by WROX A site that is new and well, pretty deep is the WROX site www.ASPToday.com. Basically they pour some of the profits from their best selling ASP books into paying ASP writers to write some fairly in-depth articles. I will link to some of my favorite articles to give you a feel for the best articles on the site. Displaying Graphics from a Database @ http://www.asptoday.com/default.asp?art=19990524.htm Scaling VB COM with MTS @ http://www.asptoday.com/default.asp?art=19990422.htm Buffering, Proxies, Objects Moved Messages @ http://www.asptoday.com/default.asp?art=19990218.htm Creating an Editable Grid @ http://www.asptoday.com/default.asp?art=19990312.htm http://www.learnASP.com/learn/advice.asp by Charles M. Carroll Page 216 advice: Cache No More by Phil Paxton (cachenomore.asp) - Page 217 advice:Option Explicit (explicit.asp) - Page 218 advice: Encode with Redirects (encode.asp) - Page 219 advice: Write Your SQL (sqlwrite.asp) - Page 220 advice: Named constants for ADO are better (namedconstants.asp) - Page 221 advice: Clean Up Your Room, I mean Objects (cleanup.asp) - Page 222 advice: Server.MapPath is Good (pathmap.asp) - Page 223 advice: Just Say No to Session COM objects (nosessionobjects.asp) - Page 224 advice: Don't Read COM Properties Twice (propertyexpense.asp) - Page 225 advice: Secure Code and Data (securecode.asp) - Page 226 advice: Encaspulate Code! (encapsulate.asp) - Page 227 advice: CASE reads better than IF (caseisbetter.asp) - Page 228 advice: Error Trapping Strategies (errorstrategies.asp) - Page 229 advice: Error Trapping Secrets (errorsecrets.asp) - Page 230 advice: You Should... (shoulds.asp) - Page 231 http://www.learnASP.com/learn/cachenomore.asp by Charles M. Carroll Page 217 Cache No More by Phil Paxton (Phil@matchw.com) Here are the things dealing with the issue of caching in ASP: 1. Response.Expires = 0 2. Response.ExpiresAbsolute = Now() - 1 3. Response.AddHeader "cache-control", "private" 4. Response.AddHeader "pragma", "no-cache" 5. Adding a "cachebuster" by creating a unique URL. Notes: #1 is said to expire at 60 seconds, not 0. Also, Khin Zaw (from ActiveServerPages@ and ASPAdvanced@) has posted research from time spent with some IIS internals experts revealing this can be a very touchy parameter to rely upon and usually requires a rather "large" negative number or pedantically, that would be a very small number). #2 (my own creation) says "expire this page 24 hours ago", allowing for time differences, rather than specify a static date. #3, #4 from an MS KB article. The code is correct but there are some incorrect statements in the article itself. n.b. some related KB articles include: (INFO: Controlling the Caching of Web Pages with IIS 4.0) (PRB: Browser Doesn't Show Most Recent Versions of htm/asp Files) (How to Use Pragma: No-cache with IIS and IE) #5 my term, but not my technique. IE 5.0 can defeat #1-#4 used in conjunction but adding #5 will break it. I usually use something like "?NoCache=Rnd" after a statement. Bill Wilkinson (of Chili!Soft) has proposed an alternate of ?NoCache=Server.URLEncode(Now())". Another thing to remember: Netscape will continue to cache, even if you turn all caching off. This behavior persisted through 4.5 PR1, PR2, and now in the released version of 4.5. If you fear you might have to deal with caching later, you might want to build contingencies into your app as you go. Retrofitting #5 throughout even a medium-sized app would take a rather sizeable effort. You could retrofit #1-#4 (inclusive) rather quickly with a single pass through the application, but #5 takes a lot of extra effort. And to that end, I don't ever Response.Redirect anywhere in my code except sample code I post to the lists (then again, the only time I use Response.Write is to the list because I rely on my Utilities-Form.inc library for Display() and HTML()). Everything is Redirect(NewURL) where the Redirect function looks like this: Function Redirect( NewURL ) ' If Not IsEmpty( NewURL & "" ) Then Dim QuestionMark ' QuestionMark = Instr( NewURL, "?" ) ' If QuestionMark = 0 Then Response.Redirect NewURL & "?" & NoCacheURL() Response.End Else Response.Redirect NEWURL & "&" & NoCacheURL() Response.End End If End If ' End Function and NoCacheURL looks like this: Function NoCacheURL() ' On Error Resume Next ' Randomize ' Randomize not needed if you use Now() ' NoCacheURL = "NoCache=" & Server.URLEncode(rnd) ' ' or NoCacheURL = "NoCache=" & Server.URLEncode(Now()) ' per Bill ' End Function I've learned that I approach things a little differently (sometimes better, sometimes worse, but overall, just differently) and have gotten used to a bunch of tiny little routines scattered throughout my app with a bunch of #include statements. Some of this might seem like overkill, but you have to understand just how pervasive and frustrating caching can be in a scripted app environment. Caching is great for pure HTML because it reduces server overhead. But if you do much scripting against databases, or time-based functions, it's not unusual to see rather bizarre things happen. Shopping cart applications will suddenly "lose" items already purchased; they'll "regain" items previously deleted. Starting a new order with an assigned "OrderID" (to use as a temporary confirmation number for the sake of the user) will suddenly show items from a previous order. It can be maddening the first time you have to deal with it. And if you don't deal with it head-on in your code, your users may be dealing with it for you -- you can turn caching off for your application in IIS [itself], but what if you are behind a firewall or proxy server which does caching for you? Or, if the user has caching turned on in their browser or they could be behind one or more layers of firewalls or proxy servers, all of which have been sold under the premise of delivering better performance through caching? Unless and until you can control every layer of access to your app, telling your server not to cache isn't a solution because requests may not be making it back to said server. End-user magazines continue to extol the benefits of caching, demonstrating they are still thinking of an HTML-only world. Scripting and caching are rarely synergistic and are almost always like oil & water: both have a purpose, but rarely together. You're almost always better off to just turn all caching off and take the performance hit than to try & retrofit all of this into an app which "mysteriously" begins misbehaving. Should: Ought to, but not necessarily will. http://www.learnASP.com/learn/explicit.asp by Charles M. Carroll Page 218 ASP Commandment #1: Use Option Explicit use Option Explicit when writing VBScript. <% option explicit%> goes at the top of the script! http://www.learnASP.com/learn/encode.asp by Charles M. Carroll Page 219 ASP Commandment #2: Encode! When dynamically building a URL with your code, the URL may work fine in IE but Netscape presents this ERROR message: HTTP Error 400 400 Bad Request Due to malformed syntax, the request could not be understood by the server. The client should not repeat the request without modifications. Use Server.URLEncode when passing parameters so that characters within the data are encoded properly (spaces replaced with "+", etc.). This is bad: <% URL="wherever.asp" part1="fname=Joe" part2="&company=Bait Shop" part3="&fax=703-277-2233" response.redirect URL & "?" & part1 & part2 & part3 %> This is good: <% URL="wherever.asp" part1="fname=" & server.URLencode("Joe") part2="&company=" & server.URLencode("Bait Shop") part3="&fax=" & server.URLencode("703-277-2233") response.redirect URL & "?" & part1 & part2 & part3 %> http://www.learnASP.com/learn/sqlwrite.asp by Charles M. Carroll Page 220 ASP Commandment #3: write that SQL Command #3: use a string variable to build the SQL string so it can be displayed and debugged if there is a problem. This is bad: set rstemp=conntemp.execute("select * from publishers where state='NY') This is good: mySQL= ""select * " mySQL= mySQL & "from publishers" mySQL= mySQL & "where state='NY'" response.write mySQL set rstemp=conntemp.execute(mySQL) rstemp.close set rstemp=nothing http://www.learnASP.com/learn/namedconstants.asp by Charles M. Carroll Page 221 ASP Commandment #4: Named Constants Command #4: use named constants from adovbs.inc instead of numeric constants. (granted, adovbs.inc isn't complete and requires some add'l tweaking from time-to-time) This is good: <!--#INCLUDE VIRTUAL="/ADOVBS.INC" --> <% connectme="DSN=Student;uid=student;pwd=magic" sqltemp="select * from publishers where state='NY'" set rstemp=Server.CreateObject("adodb.Recordset") rstemp.open sqltemp, connectme, adopenstatic response.write rstemp.recordcount & " records in<br>" & sqltemp rstemp.close set rstemp=nothing %> This is bad: <% connectme="DSN=Student;uid=student;pwd=magic" sqltemp="select * from publishers where state='NY'" set rstemp=Server.CreateObject("adodb.Recordset") rstemp.open sqltemp, connectme, 3 response.write rstemp.recordcount & " records in<br>" & sqltemp rstemp.close set rstemp=nothing %> http://www.learnASP.com/learn/cleanup.asp by Charles M. Carroll Page 222 ASP Commandment #5: Clean Up Objects Close each object when done with them. This frees up the "handle" to the resource. This applies to objects that support close methods, especially connections and recordsets! Set each object variable to nothing when done with it. this frees up the memory devoted to the resource and/or returns it to the resource pool. The code sample below makes a list box from a database. Notice the close and set to nothing at the end of the code. NEVER forget it in your code. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html><head> <TITLE>dblist.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% myDSN="DSN=Student;uid=student;pwd=magic" mySQL="select author from authors where AU_ID<100" ' displays a database field as a listbox set conntemp=server.createobject("adodb.connection") conntemp.open myDSN set rstemp=conntemp.execute(mySQL) if rstemp.eof then response.write "no data for<br>" response.write mySQL conntemp.close set conntemp=nothing response.end end if %> <form action="dblistrespond.asp" method="post"> 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <Select name="authorname"> <% ' Now lets grab all the data do until rstemp.eof %> <option> <%=RStemp(0)%> </option> <% rstemp.movenext loop rstemp.close set rstemp=nothing conntemp.close set conntemp=nothing %> <input type="submit" value="Choose Author"> </Select></form> </body></html> http://www.learnASP.com/learn/pathmap.asp by Charles M. Carroll Page 223 ASP Commandment #6: Use Server.MapPath Use Server.MapPath() whenever referring to files stored locally on the server instead of a static path (except in the rare occasions where it's necessary). This is bad: <% whichfile="D:\inetpub\wwwroot\whatever\junk.txt" set fs = CreateObject("Scripting.FileSystemObject") Set thisfile = fs.OpenTextFile(whichfile, 1, False) tempSTR=thisfile.readall response.write tempSTR thisfile.Close set thisfile=nothing set fs=nothing %> This is good: <% whichfile=server.mappath("\whatever\junk.txt") set fs = CreateObject("Scripting.FileSystemObject") Set thisfile = fs.OpenTextFile(whichfile, 1, False) tempSTR=thisfile.readall response.write tempSTR thisfile.Close set thisfile=nothing set fs=nothing %> http://www.learnASP.com/learn/nosessionobjects.asp by Charles M. Carroll Page 224 ASP Commandment #7: No COM objects in Sessions Do not store any COM objects in a Session() variable because of memory waste and threading issues. Do not store any COM objects in an Application() variable unless the reasons are excellent because of concurrent access issues. For even more details: ● Read up on thread locking, Serialization and such at /advice/dbsessionapp.asp ● Session and application level data basics at /learn/globalproblems.asp. ● STA and Memory Model Issues at /learn/buildvbthreads.asp Memory Waste Scenarios Let us examine a typical usage pattern: + 100 people hit your site for a couple of pages and leave + 100 new people arrive in a couple of minutes + 200 people arrive after that and leave within a couple of minutes and then + 50 people arrive Scenario 1: object in session_onstart End Result: 450 sessions/objects in memory with 50 people on your site. And dozens or hundred of threads that can't be reclaimed for a while Scenario 2: objects created/destroyed on a page per page basis End Result: 50 objects in memory with 50 people on your site. No unused threads must be kept in memory. Connection pooling or MTX object caching may actually result in more than 50 objects in memory in the Scenario 2 and more than 450 objects in Scenario 1 for better performance. Basically set object=nothing may be ignored and the object placed in an "instant ready" pool to be used by the next server.createobject request. http://www.learnASP.com/learn/propertyexpense.asp by Charles M. Carroll Page 225 ASP Commandment #8: Property Reads are Expensive Do not fetch any values obtained via ASP/COM more than once. Store them and use the stored values. It speeds up code significantly. Typical examples people forget this include recordset values, request.form and request.querystring. This is bad (3 COM calls where 1 would accomplish same task): <% if rstemp("city")="Dallas" then ' do something end if if rstemp("city")="New York" then ' do something end if if rstemp("city")="New Orleans" then ' do something end if %> This is good: <% thecity=rstemp("city") if thecity="Dallas" then ' do something end if if thecity="New York" then ' do something end if if thecity="New Orleans" then ' do something end if %> http://www.learnASP.com/learn/securecode.asp by Charles M. Carroll Page 226 Secure Your Code and Data In addition to coding, you need to consider security from an ASP coders point of view.This means: NO .inc Extensions Do not name your include files with a .inc extension name them with a .asp extension. Be careful where you place .mdb files Do not place .mdb files inside your web structure where they can be downloaded. Place them in a directory on the machine but not within the web site folder structure. Then just establish a system DSN to it. We have a directory devoted to security links at www.activeserverpages.com/security and actually run a listserv devoted to ASP Security Topics: aspSecurity Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/securecode.asp Send Listserver Questions to aspSecurity@ls.asplists.com Related Links Security Issues from www.learnasp.com @ http://www.learnasp.com/security http://www.learnASP.com/learn/encapsulate.asp by Charles M. Carroll Page 227 Encapsulate Your Code in Reusable Libraries You should create many subroutines and functions and instead of placing them in each page just use the include facility to access them. The following scripts are very compact because they call SUBroutines that the include files contain. Here someone has encapsulated HTML coding into a high level ASP call: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <!--#include virtual="/learn/test/lib_htmlstuff.asp"--> <html><head> <title>libhtmldemo.asp by Phil Paxton</title>& <body> <form action="lib_htmldemorespond.asp"> <% Call Form_TextBox("first name","Fname",20,20,"") response.write "<br>" Call Form_TextBox("Last Name","Lname",20,20,"") response.write "<br>" Call Form_TextBox("City","cy",20,20,"") response.write "<br>" Call Form_TextBox("State","st",2,2,"") response.write "<br>" Call Form_TextBox("Zip Code","zp",10,10,"") response.write "<br>" Call Form_SubmitButton("Register Me","register") %> 19 20 21 </form> </body> </html> Here displaying a listbox from a database has been simplified by a subroutine: 1 2 3 4 5 6 7 8 9 10 11 12 13 <html><head> <TITLE>subdblist.asp</TITLE> </head><body bgcolor="#FFFFFF"> <form> <% theDSN="DSN=student;uid=student;pwd=magic" call query2list("select distinct city from publishers","cy",theDSN) call query2list("select distinct state from publishers","st",theDSN) call query2list("select distinct zip from publishers","zp",theDSN) %> </form> <!--#include virtual="/learn/test/subdblist.inc"--> </body></html> The library files/includes that make all these tasks one step are detailed at: /learn/qualitycode.asp http://www.learnASP.com/learn/caseisbetter.asp by Charles M. Carroll Page 228 Case is better than IF (for readabilty) Here are two code samples. One is built using IFs and the other with CASE. I think these drive the point home that readability, speed and code flow is clearer with CASEs. This is the IF example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <html><head> <title>suffixif.asp</title> </head> <body> <% ' ok test it For i = 1 TO 1000 n = i Response.Write n & AddSuffix(n) & ".<BR>" NEXT %> </body> </html> <% FUNCTION AddSuffix(num) temp=right(num,1) If temp= 1 Then AddSuffix = AddSuffix & "st" ElseIf temp = 2 Then AddSuffix = AddSuffix & "nd" ElseIf temp = 3 Then AddSuffix = AddSuffix & "rd" ElseIf temp<11 Then AddSuffix = AddSuffix & "th" End If END FUNCTION %> This is the CASE example: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <html><head> <title>suffixcase.asp by Dwaine Maltais rmaltais@wilmington.net</title> </head> <body> <% ' ok test it FOR i = 1 TO 1000 n = i Response.Write AddSuffix(n) & "<br>" NEXT %> </body> </html> <% Function AddSuffix(num) numpart = RIGHT(num,1) SELECT CASE numpart CASE "1" IF InStr(num,"11") THEN num = num & "th" ELSE num = num & "st" END IF CASE "2" IF InStr(num,"12") THEN num = num & "th" ELSE num = num & "nd" END IF CASE "3" IF InStr(num,"13") THEN num = num & "th" ELSE num = num & "rd" END IF CASE "4" num = num & "th" CASE ELSE num = num & "th" END SELECT AddSuffix = num END FUNCTION %> http://www.learnASP.com/learn/errorstrategies.asp by Charles M. Carroll Page 229 Error Trapping Strategies by Charles Carroll DRAFT - not ready yet! There are several ways to deal with errors. For example: ● write errors to custom log ● write errors to IIS log ● email someone when a page error occurs ● place errors in a custom dictionary/collection We will provide code for each scenario and discuss the pros and cons of each approach. http://www.learnASP.com/learn/errorsecrets.asp by Charles M. Carroll Page 230 Error Trapping Secrets by Charles Carroll DRAFT - Not Ready yet Blah, Blah, Blah. http://www.learnASP.com/learn/shoulds.asp by Charles M. Carroll Page 231 ASP Commandments: Shoulds Thou should: ● specify all of the parameters for their ADO command, connection, and recordset objects so defaults don't rear their ugly heads and give thou an error when thou tries to do something which isn't permitted by a default (e.g. .AddNew after using defaults, creating a read-only recordset, and the inevitable resulting error). ● make sure that ASP scripts that are dynamic in nature have caching turned off. Thou shalt find scripts and caching are like oil and water...they mix not well, except on salads. If caching isn't turned off by default, it should be possible to alter a single variable in each script file so caching can be switched on/off at will to avoid retrofitting scripts with the code required to break caching. /learn/cachenomore.asp has up to date guidelines on how to disable script caching. ● remember using .Execute to create an ADO recordset will result in a read-only recordset and thou can neither edit these records nor add new records. ● Use the correct cursortype or a SQL count to determine how many records are in a table or query, instead of a counting loop or a movelast. see /learn/dbcount.asp for an example. Should: Ought to, but not necessarily will. http://www.learnASP.com/learn/more.asp by Charles M. Carroll Page 232 Text Files: Reading Them off Server (txtread.asp) - Page 233 Text Files: Writing Them on Server (txtwrite.asp) - Page 234 Text Files: Meyers-Briggs parsing #1 (mb1.asp) - Page 235 Text Files: Meyers-Briggs parsing #2 (mb2.asp) - Page 236 Text Files: Meyers-Briggs parsing #3 (mb3.asp) - Page 237 Content Linker: Prev/Next Page (cl.asp) - Page 238 Content Linker: Table of Contents (cl2.asp) - Page 239 Content Linker: Listbox of contents (cl3.asp) - Page 240 File Objects: Read Directory (fileobjects.asp) - Page 241 File Objects: Display Directory as Links/Graphics (fileobjects2.asp) - Page 242 File Objects: Read Disk Drive by Steven Harper (fileobjects3.asp) - Page 243 File Objects: Show Dir List by Tim Foster (fileobjects4.asp) - Page 244 Graphic Size Detector (graphicdetect.asp) - Page 245 http://www.learnASP.com/learn/txtread.asp by Charles M. Carroll Page 233 Text File Reading 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html><head> <TITLE>txtread.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% whichfile=server.mappath("/aspheader.asp") Set fs = CreateObject("Scripting.FileSystemObject") Set thisfile = fs.OpenTextFile(whichfile, 1, False) counter=0 do while not thisfile.AtEndOfStream counter=counter+1 thisline=thisfile.readline response.write thisline & "<br>" loop thisfile.Close set thisfile=nothing set fs=nothing %> </body></html> http://www.learnASP.com/learn/txtwrite.asp by Charles M. Carroll Page 234 Text File Writing by Charles Carroll The following code snippets adds several lines to an ASCII file. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <html><head> <TITLE>txtwrite.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% whichFN=server.mappath("/upload/tests/tempfile.txt") ' first, create the file out of thin air Set fstemp = server.CreateObject("Scripting.FileSystemObject") Set filetemp = fstemp.CreateTextFile(whichFN, true) ' true = file can be over-written if it exists ' false = file CANNOT be over-written if it exists filetemp.WriteLine("This is a brand new file!!!!") filetemp.writeblanklines(3) filetemp.WriteLine("This is the last line of the file we created!") filetemp.Close ' Now open it and add some lines forappending =8 set filetemp=fstemp.OpentextFile(whichFN, forappending) filetemp.writeline "a line we added later" filetemp.writeline "another line we added later..." filetemp.close set filetemp=nothing set fstemp=nothing 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 If err.number=0 then response.write "File was appended sucessfully!" else response.write response.write response.write response.write response.write response.write response.write "VBScript Errors Occured!<br>" "Error Number=#<b>" & err.number & "</b><br>" "Error Desc. =<b>" & err.description & "</b><br>" "Help Path =<b>" & err.helppath & "</b><br>" "Native Error=<b>" & err.nativeerror & "</b><br>" "Error Source =<b>" & err.source & "</b><br>" "SQL State=#<b>" & err.sqlstate & "</b><br>" end if %> </body></html> This code displays the file we created: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <html><head> <TITLE>txtwritedisplay.asp</TITLE> </head><body bgcolor="#FFFFFF"> <% whichname="tempfile.txt" whichdir=Server.Mappath ("/upload/tests/") whichFN=whichdir & whichname forreading=1 Set fs = CreateObject("Scripting.FileSystemObject") Set thisfile = fs.OpenTextFile(whichFN, forreading, False) counter=0 do while not thisfile.AtEndOfStream counter=counter+1 thisline=thisfile.readline response.write thisline & "<br>" loop thisfile.Close set thisfile=nothing set fs=nothing %> </body></html> http://www.learnASP.com/learn/mb1.asp by Charles M. Carroll Page 235 Reading/Parsing an ASCII File by Charles Carroll Let us say you have an ASCII file of questions that you want to convert to HTML (listing below). The next page will show you the typical parsing code used for such a task. 1 EI to you 2 SN 3 SN 4 TF 5 TF 6 JP 7 JP 8 EI energy 9 SN At a party do you - interact with many, including strangers / interact with a few, known Are you more - realistic than speculative / speculative than realistic It is worse to - have your "head in the clouds" / be "in a rut" Are you more impressed by - principles / emotions Are you more drawn toward the - convincing / touching Do you prefer to work - to deadlines / just "whatever" Do you tend to choose - rather carefully / somewhat impulsively At parties do you - stay late, with increasing energy / leave early, with decreased Are you more attracted to - sensible people / imaginative people 10 SN Are you more interested in - what is actual / what is possible 11 TF In judging others are you more swayed by - laws than circumstances / circumstances than laws 12 TF In approaching others is your inclination to be - objective / personal 13 JP Are you more - punctual / leisurely 14 JP Does it bother you more having things - incomplete / completed 15 EI In your social groups do you - keep abreast of other's happenings / get behind on the news 16 SN In doing ordinary things are your more likely to - do it the usual way / do it your own way 17 SN Writers should - "say what they mean and mean what they say" / express things more by use of analogy 18 TF Which appeals to you more - consistency of thought / harmonious human relationships 19 TF Are you more comfortable in making - logical judgments / value judgmants 20 JP Do you want things - settled and decided / unsettled and undecided 21 JP Would you say you are more - serious and determined / easy-going 22 EI In phoning do you - rarely question that it will all be said / rehearse what you'll say 23 SN Facts - "speak for themselves" / illustrate principles 24 SN Are visinaries - somewhat annoying / rather fascinating 25 TF Are you more often - a cool-headed person / a warm-hearted person 26 TF Is it worse to be - unjust / merciless 27 JP Should one usually let events occur - by careful selection and choice / randomly and by chance 28 JP Do you feel better about - having purchased / having the option to buy 29 EI In company do you - initiate conversation / wait to be approached 30 SN Common sense is - rarely questionable / frequently questionable 31 SN Children often do not - make themselves useful enough / exercise their fantasy enough 32 TF In making decisions do you feel more comfortable with - standards / feelings 33 TF Are you more - firm than gentle / gentle than firm 34 JP Which is more admirable - the ability to organize and be methodical / the ability to adapt and make do 35 JP Do you put more value on the - definite / open-ended 36 EI Does new and non routine interaction with others - stimulate and energize you / tax your reserves 37 SN Are you more frequently - a practical sort of person / a fanciful sort of person 38 SN Are you more likely to - see how others are useful / see how others see 39 TF Which is more satisfying - to discuss an issue thoroughly / to arrive at agreement on an issue 40 TF Which rules you more - your head / your heart 41 JP Are you more comfortable with work that is - contracted / done on a casual basis 42 JP Do you tend to look for - the orderly / whatever turns up 43 EI Do you prefer - many friends with brief contact / a few friends with more lengthy contact 44 SN Do you go more by - facts / principles 45 SN Are you more interested in -production and distribution / design and research 46 TF Which is more of a compliment - "There is a very logical person." / "There is a very sentimental person." 47 TF Do you value in yourself more that you are - unwavering / devoted 48 JP Do you more often prefer the - final and unalterable statement / tentative and preliminary statement 49 JP Are you more comfortable - after a decision / before a decision 50 EI Do you - speak easily and length with strangers / find little to say to strangers 51 SN Are you more likely to trust your - experience / hunch 52 SN Do you feel - more practical than ingenious / more ingenious than practical 53 TF Which person is more to be complimented - one of clear reason / strong feeling 54 TF Are you inclined more to be - fair minded / sysmpathetic 55 JP Is it preferable mostly to -make sure things are arranged / just let things happen 56 JP In relationships should most things to - renegotiable / random and circumstantial 57 EI When the phone rings do you - hasten to get to it first / hope someone else will answer 58 SN Do you prize more in yourself - a strong sense of reality / a vivid imagination 59 SN Are you drawn more to - fundamentals / overtones 60 TF Which seems the greater error - to be too passionate / to be too objective 61 JP Do you see yourself as basically - the structured and scheduled / the unstructured and unscheduled 62 JP Are you a person that is more - routinized than whimsical / whimsical than routinized 63 EI Are you inclined to be - easy to approach / somewhat reserved 64 SN In writings do you prefer - the more literal / the more figurative 65 SN Is it harder for you to - identify with others / utilize others 66 67 68 69 TF TF EI JP Which do you wish more for yourself - clarity of reason / strength of compassion Which is the greater fault - being indiscriminate / being critical Do you prefer the - planned event / unplanned event Do you tend to be more - deliberate than spontaneous / spontaneous than deliberate http://www.learnASP.com/learn/mb2.asp by Charles M. Carroll Page 236 Reading/Parsing an ASCII File #2 by Charles Carroll Here is one implementation of parsing the file and converting it to on-the-fly HTML. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <%option explicit%> <html> <head> <title>mb.asp</title> </head> <body bgcolor="#FFFFFF"> <form method="post" action="mbrespond.asp"> <% dim answer1, answer2 dim char1, char2, counter Dim fs, findslash, findhyphen dim rest Dim thisfile, thisline dim question dim whichfile whichfile=server.mappath("mb.txt") Set fs = CreateObject("Scripting.FileSystemObject") Set thisfile = fs.OpenTextFile(whichfile, 1, False) counter=0 do while not thisfile.AtEndOfStream counter=counter+1 thisline=thisfile.readline char1=mid(thisline,1,1) char2=mid(thisline,2,1) rest=mid(thisline,3) findhyphen=instr(thisline,"-") question=mid(rest,1,findhyphen-2) rest=mid(rest,findhyphen) findslash=instr(rest,"/") answer1=mid(rest,1,findslash-1) answer2=mid(rest,findslash+1) 'response.write char1 & "<br>" 'response.write char2 & "<br>" 'response.write rest & "<p>" response.write question & "<br>" 'response.write answer1 & "<br>" 'response.write answer2 & "<p>" %> <p><input TYPE="radio" name="Q<%=counter%>" VALUE="U" CHECKED>Undecided<br> <input TYPE="radio" name="Q<%=counter%>" VALUE="<%=char1%>"><%=answer1%><br> <input TYPE="radio" name="Q<%=counter%>" VALUE="<%=char2%>"><%=answer2%></p> <p><% loop thisfile.Close set fs=nothing 52 53 54 55 %> <input type="submit"></p> </form> </body> </html> http://www.learnASP.com/learn/mb3.asp by Charles M. Carroll Page 237 Reading/Parsing an ASCII File #3 by Charles Carroll Here is one implementation of scoring the HTML file. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 <%option explicit%> <html> <head> <title>mbrespond.asp</title> </head> <% dim key dim ecount, icount dim scount, ncount dim tcount, fcount dim jcount, pcount dim ucount For Each Key in Request.Form SELECT CASE request.form(key) CASE "E" ecount=ecount+1 CASE "I" icount=icount+1 CASE "S" scount=scount+1 CASE "N" ncount=ncount+1 CASE "T" tcount=tcount+1 CASE "F" fcount=fcount+1 CASE "J" jcount=jcount+1 CASE "P" pcount=pcount+1 CASE "U" ucount=ucount+1 END SELECT Next Response.write "E=" & ecount & "<br>" Response.write "I=" & icount & "<br>" Response.write "S=" & scount & "<br>" Response.write "N=" & ncount & "<br>" Response.write "T=" & tcount & "<br>" Response.write "F=" & fcount & "<br>" Response.write "J=" & jcount & "<br>" Response.write "P=" & pcount & "<br>" Response.write "U=" & ucount & "<br>" %> <body bgcolor="#FFFFFF"> </body> </html> http://www.learnASP.com/learn/cl.asp by Charles M. Carroll Page 238 Content Linking Prev/Next 1 2 3 4 5 6 7 8 9 10 11 12 <% Set NL = Server.CreateObject ("MSWC.NextLink") tocname="/learn/learn.txt" nextref=NL.GetNextURL(tocname) nextdes=NL.GetNextDescription(tocname) If (NL.GetListIndex (tocname)>1) Then prevref=NL.GetPreviousURL(tocname) prevdes=NL.GetPreviousDescription(tocname) %> Prev:<a href="<%=prevref%>"><%=prevdes%></a> Next: <% End If %> <a href="<%=nextref%>"><%=nextdes%></a> http://www.learnASP.com/learn/cl2.asp by Charles M. Carroll Page 239 Content Linking TOC 1 2 3 4 5 6 7 8 9 10 11 12 <TITLE>cl2.asp</TITLE> <body bgcolor="#FFFFFF"> <% Set TL = Server.CreateObject ("MSWC.NextLink") for i=1 to cint(TL.GetListCount("/learn/learn.txt"))%> Description: <%=TL.GetNthDescription ("/learn/learn.txt",i)%>, (URL=<%=TL.GetNthURL ("/learn/learn.txt",i)%>). Page <%=i%>.<p> <% next%> </body> </html> http://www.learnASP.com/learn/cl3.asp by Charles M. Carroll Page 240 Content Linking List Box by Charles Carroll Here is a script that will turn the Content Linking elements into a pull-down list so people can arbitrarily jump from one topic to another.... 1 2 3 4 5 6 7 8 9 10 11 12 <HTML><HEAD><TITLE>cljump.asp</TITLE></HEAD> <body bgcolor="#FFFFFF"> <FORM ACTION="cljumprespond.asp"> <% Set TL = Server.CreateObject ("MSWC.NextLink") maxi= cint(TL.GetListCount("/learn/learn.txt")) %> <SELECT name="whichtopic"> <OPTION SELECTED VALUE="">Select a Topic... <%for i=1 to maxi%> <OPTION value= <%=TL.GetNthURL("/learn/learn.txt",i)%> 13 14 15 16 17 18 19 20 21 22 23 24 25 26 > <% desc=TL.GetNthDescription("/learn/learn.txt",i) if mid(desc,1,1)="*" then desc=mid(desc,2) else desc=" " & desc end if %> <%=desc%> <%next%> </SELECT> <INPUT VALUE="Jump to Lesson" TYPE=submit></FORM> </BODY> </HTML> The script named cljumprespond.asp that implements the jump looks like this: 1 2 3 <% response.redirect request.querystring("whichtopic") %> http://www.learnASP.com/learn/fileobjects.asp by Charles M. Carroll Page 241 FileObjects by Charles Carroll The file object is in newer versions of VBScript. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <html><head> <title>fileobjects.asp</title> </head><body> <% mypath="/learn/test" Set filesystem = CreateObject("Scripting.FileSystemObject") Set folder = filesystem.GetFolder(server.mappath(mypath)) Set filecollection = folder.Files For Each file in filecollection response.write file.name & "<br>" Next set filesystem=nothing set folder=nothing set filecollection=nothing %> </body></html> http://www.learnASP.com/learn/fileobjects2.asp by Charles M. Carroll Page 242 FileObjects Part 2 by Charles Carroll The file object is in newer versions of VBScript. Here we use it to walk a directory and make links. 1 2 3 4 <html><head> <title>fileobjectslinks.asp</title> </head><body> <% 5 6 7 8 9 10 11 12 13 14 15 16 17 dirtowalk="/learn/test" Set fs = CreateObject("Scripting.FileSystemObject") Set f = fs.GetFolder(server.mappath(dirtowalk)) Set fc = f.Files For Each whatever in fc response.write "<A HREF='" response.write whatever.name response.write "'>" response.write whatever.name response.write "</A><br>" Next %> </body></html> Now we will display graphics in a directory. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html><head> <title>fileobjectsgraphics.asp</title> </head><body> <% dirtowalk="/images" Set fs = CreateObject("Scripting.FileSystemObject") Set f = fs.GetFolder(server.mappath(dirtowalk)) Set fc = f.Files For Each whatever in fc response.write "<IMG SRC='/images/" response.write whatever.name response.write "'>" response.write whatever.name & "<br>" Next %> </body></html> http://www.learnASP.com/learn/fileobjects3.asp by Charles M. Carroll Page 243 FileObjects Part 3 by Steven Harper Steven Harper@ScapaSMD.com, Internet Developer The file object can be used to examine the disk as well as this cript submitted by a site viewer, demonstrates. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html><head> <title>fileobjectsinfo.asp</title> </head><body> <% disktoexamine="C:" set fs = Server.CreateObject("Scripting.FileSystemObject") set f = fs.GetDrive(disktoexamine) Response.Write(" Root Folder : ") Response.Write(f.RootFolder) Response.Write("<BR>") Response.Write(" Type of Drive : ") if f.DriveType=2 then Response.Write("Fixed") end if if f.DriveType=1 then Response.Write("Removable") end if Response.Write("<BR>") Response.Write(" File System : ") 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 Response.Write(f.FileSystem) Response.Write("<BR>") Response.Write(" Total Size on Server's C: ") Response.Write(f.TotalSize) Response.Write("<BR>") Response.Write(" Drive Space on Server's C: ") Response.Write(f.freespace) Response.Write("<BR>") Response.Write(" Serial Number : ") Response.Write(f.SerialNumber) set f=nothing set fs=nothing %> </body></html> http://www.learnASP.com/learn/fileobjects4.asp by Charles M. Carroll Page 244 FileObjects Part 4 by "Tim Foster" tfoster@pdxinc.com The file object examples was modified by one of our readers to support folders and clicking on them to see the contents beneath. Our readers always come up with some nice variations and new examples. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <html><head> <title>fileobjectsplusdir.asp</title> </head><body> <% additional = request.querystring("pathh") folderspec = "/learn/" if additional & "x" <> "x" then additional = additional & "/" folderspec = folderspec & additional end if Set fs = CreateObject("Scripting.FileSystemObject") Set f = fs.GetFolder(server.mappath(folderspec)) Set fd = f.subfolders response.write "<h2>FOLDERS</h2><blockquote>" For Each whatever in fd response.write "<A HREF='" response.write request.servervariables("script_name") response.write "?pathh=" & whatever.name response.write "'>" response.write whatever.name & " - " & whatever.datecreated response.write "</A><br>" Next response.write "</blockquote><hr>" response.write "<h2>FILES</h2><blockquote>" Set fc = f.files For Each whatever in fc response.write "<A HREF='" response.write folderspec & whatever.name response.write "'>" response.write whatever.name & " - " & whatever.datecreated 39 40 41 42 43 44 45 46 response.write "</A><br>" Next response.write "</blockquote><hr>" %> </body></html> http://www.learnASP.com/learn/graphicdetect.asp by Charles M. Carroll Page 245 Detect Graphic Type/Dimensions by Daniel Gorroño Daniel Gorroño Santurtzi danielgo@sarenet.es Bizkaia - Euskal Herria This ingenious piece of code demonstrates how to read a file using the file system object and extract bytes that contain the height and width. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!--#include virtual="/learn/test/lib_graphicdetect.asp"--> <html><head> <TITLE>dbtable.asp</TITLE> </head> <body bgcolor="#FFFFFF"> <% graphic="images/learnaspiconmain.gif" HW = ReadImg(graphic) Response.Write graphic & " Dimensions: " & HW(0) & "x" & HW(1) & "<br>" response.write "<img src=""/" & graphic & """" response.write height=""" & HW(0) & """ response.write width=""" & HW(0) & "">" %> </body></html> The library that is included is: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <% Dim HW Function AscAt(s, n) AscAt = Asc(Mid(s, n, 1)) End Function Function HexAt(s, n) HexAt = Hex(AscAt(s, n)) End Function Function isJPG(fichero) If inStr(uCase(fichero), ".JPG") <> 0 Then isJPG = true Else isJPG = false End If End Function Function isPNG(fichero) If inStr(uCase(fichero), ".PNG") <> 0 Then isPNG = true Else 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 isPNG = false End If End Function Function isGIF(fichero) If inStr(uCase(fichero), ".GIF") <> 0 Then isGIF = true Else isGIF = false End If End Function Function isBMP(fichero) If inStr(uCase(fichero), ".BMP") <> 0 Then isBMP = true Else isBMP = false End If End Function Function isWMF(fichero) If inStr(uCase(fichero), ".WMF") <> 0 Then isWMF = true Else isWMF = false End If End Function Function isWebImg(f) If isGIF(f) Or isJPG(f) Or isPNG(f) Or isBMP(f) Or isWMF(f) Then isWebImg = true Else isWebImg = true End If End Function Function ReadImg(fichero) If isGIF(fichero) Then ReadImg = ReadGIF(fichero) Else If isJPG(fichero) Then ReadImg = ReadJPG(fichero) Else If isPNG(fichero) Then ReadImg = ReadPNG(fichero) Else If isBMP(fichero) Then ReadImg = ReadPNG(fichero) Else If isWMF(fichero) Then ReadImg = ReadWMF(fichero) Else ReadImg = Array(0,0) End If End If End If End If End If End Function Function ReadJPG(fichero) 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 Dim fso, ts, s, HW, nbytes HW = Array("","") Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1) s = Right(ts.Read(167), 4) HW(0) = HexToDec(HexAt(s,3) & HexAt(s,4)) HW(1) = HexToDec(HexAt(s,1) & HexAt(s,2)) ts.Close ReadJPG = HW End Function Function ReadPNG(fichero) Dim fso, ts, s, HW, nbytes HW = Array("","") Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1) s = Right(ts.Read(24), 8) HW(0) = HexToDec(HexAt(s,3) & HexAt(s,4)) HW(1) = HexToDec(HexAt(s,7) & HexAt(s,8)) ts.Close ReadPNG = HW End Function Function ReadGIF(fichero) Dim fso, ts, s, HW, nbytes HW = Array("","") Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1) s = Right(ts.Read(10), 4) HW(0) = HexToDec(HexAt(s,2) & HexAt(s,1)) HW(1) = HexToDec(HexAt(s,4) & HexAt(s,3)) ts.Close ReadGIF = HW End Function Function ReadWMF(fichero) Dim fso, ts, s, HW, nbytes HW = Array("","") Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1) s = Right(ts.Read(14), 4) HW(0) = HexToDec(HexAt(s,2) & HexAt(s,1)) HW(1) = HexToDec(HexAt(s,4) & HexAt(s,3)) ts.Close ReadWMF = HW End Function Function ReadBMP(fichero) Dim fso, ts, s, HW, nbytes HW = Array("","") Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1) s = Right(ts.Read(24), 8) HW(0) = HexToDec(HexAt(s,4) & HexAt(s,3)) HW(1) = HexToDec(HexAt(s,8) & HexAt(s,7)) ts.Close ReadBMP = HW End Function Function isDigit(c) If inStr("0123456789", c) <> 0 Then isDigit = true 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 Else isDigit = false End If End Function Function isHex(c) If inStr("0123456789ABCDEFabcdef", c) <> 0 Then isHex = true Else ishex = false End If End Function Function HexToDec(cadhex) Dim n, i, ch, decimal decimal = 0 n = Len(cadhex) For i=1 To n ch = Mid(cadhex, i, 1) If isHex(ch) Then decimal = decimal * 16 If isDigit(c) Then decimal = decimal + ch Else decimal = decimal + Asc(uCase(ch)) - Asc("A") End If Else HexToDec = -1 End If Next HexToDec = decimal End Function %> http://www.learnASP.com/learn/buildcomponents.asp by Charles M. Carroll Page 246 VB Components: Simple Component (buildvbsimple.asp) - Page 247 VB Components: Registering Component (buildregister.asp) - Page 248 VB Components: ADO, Run It! (buildvbado.asp) - Page 249 VB Components: ADO, Build It! (buildvbado2.asp) - Page 250 VB Components: VB Warnings/Guidelines (buildvbguidelines.asp) - Page 251 VB Components: General Building Guidelines (buildvb.asp) - Page 252 VB Components: Installation Requirements (buildvb2.asp) - Page 253 VB Components: Threading Models (buildvbthreads.asp) - Page 254 http://www.learnASP.com/learn/buildvbsimple.asp by Charles M. Carroll Page 247 Simple VB Component by Charles Carroll This is a very simple component written in Visual Basic. You can create it by ● making a new "Active-X DLL" project ● under the Project; References menu, you must activate the "Microsoft Active Server Pages" library otherwise it won't recognize the response object and won't compile. ● The project name ==> charlescarroll The class name ==> simplecomponent Here is the Visual Basic source code for the component: 14 ' projectname =charlescarroll 15 ' classname =simplecomponent 16 Private ASPresponse As response 17 Public Sub onstartpage(sc As ScriptingContext) 18 Set ASPresponse = sc.response() 19 End Sub 20 Public Sub hello() 21 ASPresponse.Write "Hello" 22 End Sub 23 Public Sub goodbye() 24 ASPresponse.Write "Goodbye" 25 End Sub 26 Now it is invoked on an ASP page with the following code: 1 <html><head> 2 <title>simplevb.asp</title>& 3 <body bgcolor="#FFFFFF"> 4 <% 5 set parrot=server.createobject("charlescarroll.simplecomponent") 6 parrot.hello 7 response.write "<br>" 8 parrot.goodbye 9 %> 10 </body></html> http://www.learnASP.com/learn/buildregister.asp by Charles M. Carroll Page 248 Registering A Component The minimum recommended steps to register your C++/Visual Basic ASP component are: ● Copy your component to where your System DLLs are (probably \winnt\system32) ● DO NOT leave the component in the original directory!!!! Make sure the .DLL/component is only in the system directory and nowhere else. If regsvr32 is executed and it rgeisters a DLL that is not in the system directory your ASP pages may fail to instantiate the component with the dreaded message "Active X DLL cannot create object". ● from a command prompt regsvr32 <your component name> If you are updating a component (i.e. registering a component that replaces another component) instead: ● Copy your component to where your System DLLs are (probably \winnt\system32) ● DO NOT leave the component in the original directory!!!! Make sure the .DLL/component is only in the system directory and nowhere else. If regsvr32 is executed and it rgeisters a DLL that is not in the system directory your ASP pages may fail to instantiate the component with the dreaded message "Active X DLL cannot create object". ● from a command prompt regsvr32 <old component name> -u ● from a command prompt regsvr32 <your component name> ● start and stop web service to purge old component from memory http://www.learnASP.com/learn/buildvbado.asp by Charles M. Carroll Page 249 VB Component: DBHelper from Web Page Here is a call to a VB custom component we created: 1 <html><head> 2 <title>dbhelper.asp</title>& 3 <body> 4 <% 5 set mycomponent=server.createobject("charlescarroll.dbhelperver001") 6 mycomponent.connect ="DSN=student;uid=student;pwd=magic" 7 mycomponent.query = "select * from publishers" 8 mycomponent.maketable 9 set mycomponent=nothing 10 %> 11 </body></html> http://www.learnASP.com/learn/buildvbado2.asp by Charles M. Carroll Page 250 VB Component: DBHelper by Charles Carroll This page has the source code to the component. We have specified: project name=charlescarroll class name=dbhelperver001 Remember these are the names set in the property window, not neccesarily the filenames. This example will not compile unless you go to the "Project; References" menu and check/turn on the following libraries: ● Microsoft "Active Data Objects" object library ● 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Microsoft "Active Server Pages" object library ' projectname =charlescarroll ' classname =dbhelperver001 Private ASPresponse As Response Private ASPserver As Server Private htmlstart, htmlend, rowstart, rowend Private fieldstart, fieldend, namestart, nameend Public Sub onstartpage(sc As ScriptingContext) Set ASPresponse = sc.Response() Set ASPserver = sc.Server() End Sub Public Property Let connect(temp As Variant) myconnect = temp End Property Public Property Get connect() As Variant connectme = myconnect End Property Public Property Get fieldnames() As Variant fieldnames = myfieldnames End Property 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 Public Property Let fieldnames(temp As Variant) myfieldnames = temp End Property Public Property Let query(temp As Variant) myquery = temp End Property Public Property Get query() As Variant query = myquery End Property Public Property Let selectdefault(temp As Variant) myselectdefault = temp End Property Public Property Get selectdefault() As Variant selectdefault = myselectdefault End Property Public Property Let selectname(temp As Variant) myselectname = temp End Property Public Property Get selectname() As Variant selectname = myselectname End Property Public Sub query2list() htmlstart = "<select name='" & selectname & "'>" htmlend = "</select>" rowstart = "<option>" rowend = "</option>" fieldstart = "" fieldend = "" Call query2html End Sub Public Sub query2table() htmlstart = "<table border=1>" htmlend = "</table>" rowstart = "<tr>" rowend = "</tr>" fieldstart = "<td valign=top>" fieldend = "</td>" Call query2html End Sub Public Sub query2form() htmlstart = "" htmlend = "" rowstart = "" rowend = "<hr>" fieldstart = "" fieldend = "<br>" fieldnames = True namestart = "" nameend = " = " Call query2html End Sub Public Sub query2entryform() htmlstart = "" htmlend = "" rowstart = "" rowend = "" fieldstart = "%name% = <input type='text name='%name%' value='" fieldend = "' size='%size%'><br>" fieldnames = False namestart = "" nameend = " =" 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 Call query2html End Sub Public Sub CustomDisplay(PARMhtmlstart, PARMhtmlend, PARMrowstart, PARMrowend, _ PARMfieldstart, PARMfieldend, PARMfieldnames, _ PARMnamestart, PARMnameend) htmlstart = PARMhtmlstart htmlend = PARMhtmlend rowstart = PARMrowstart rowend = PARMrowend fieldstart = PARMfieldstart fieldend = PARMfieldend fieldnames = PARMfieldnames namestart = PARMnamestart nameend = PARMnameend Call query2html End Sub Private Sub query2html() On Error GoTo Badnews attempt = "creating connection" Set conntemp = ASPserver.CreateObject("adodb.connection") attempt = "opening connection" conntemp.Open myconnect attempt = "making recordset" Set rstemp = conntemp.Execute(myquery) howmanyfields = rstemp.Fields.Count - 1 ReDim fsa(howmanyfields) ReDim fea(howmanyfields) For i = 0 To howmanyfields tempstart = Replace(fieldstart, "%name%", rstemp(i).Name) tempend = Replace(fieldend, "%name%", rstemp(i).Name) tempstart = Replace(tempstart, "%size%", rstemp(i).ActualSize) tempend = Replace(tempend, "%size%", rstemp(i).ActualSize) fsa(i) = myfieldstart fea(i) = myfieldend Next ASPresponse.Write htmlstart & vbCrLf Counter = 0 Do While Not rstemp.EOF ASPresponse.Write rowstart & vbCrLf For i = 0 To howmanyfields If fieldnames = True Then ASPresponse.Write namestart & rstemp(i).Name & nameend End If ASPresponse.Write fsa(i) & rstemp(i) & fea(i) & vbCrLf Next ASPresponse.Write rowend & vbCrLf Counter = Counter + 1 rstemp.MoveNext Loop rstemp.Close Set rstemp = Nothing conntemp.Close Set conntemp = Nothing ASPresponse.Write htmlend Exit Sub Badnews: temp = "Error: " & attempt & "<br>" temp = temp & Err.Description & "<br>" temp = temp & Err.Number ASPresponse.Write temp End Sub http://www.learnASP.com/learn/buildvbguidelines.asp by Charles M. Carroll Page 251 VB ASP Component Building Guidelines by Charles Carroll Component written in Visual Basic can be written using programming techniques that will cause them to be unstable in a web server environment. Commands, Functions and Objects that are fine in most standalone or client/server VB programs may not be appropriate in a web server component. We offer the following major guidelines: ● Do not use DAO or RDO for data access. Use ADO only. DAO and RDO do not scale to the concurrency issues a website faces well. ● Do not use traditional file access methods (Open #, Close #). Instead use the scripting FileSystemObject. http://www.learnASP.com/learn/buildvb.asp by Charles M. Carroll Page 252 Generic VB Component Building Steps Making a VB ASP component is easy: ● Use File; New Project ● choose Active-X DLL ● You will now be in the editor and there will be a class open ● when you are done, the code to invoke it on a page will look like: set .... = server.createobject("projectname.classname") choose your project plus class names well. ● The project name and class name are set with the (name) property. They are NOT in anyway connected to the filename although you may make the filenames match the project and class names. ● If you need to use one of the five built-in ASP objects (collectively called the scripting context) you can add a special event to your class called OnStartPage. Anytime your component is created from an ASP script, ASP will call your OnStartPage if it exists within your class. OnStartPage allows you to assign the built-in ASP objects (response, request, server, application, session) to objects in your code: Public Function onstartpage(sc As Object) 'Set ... = sc.response() 'set ... = sc.server() 'set ... = sc.Request() 'set ... = sc.application() 'set ... = sc.session() End Function ● If needed, you can add this event: Public Function onendpage(sc As Object) End Function http://www.learnASP.com/learn/buildvb2.asp by Charles M. Carroll Page 253 VB Components: what you need... To make a VB ASP component you need the following on your machine: ● Visual Basic version 4 or version 5 (our instructions only cover version 5 though) ● A installation of "Active Server Pages" which can be obtained by installing IIS or Visual Interdev. This is because "Project; References" must include the "Active Server Pages" libary. People having trouble building components can sign up for our listserv: vbcomponents Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/buildvb2.asp Send Listserver Questions to vbcomponents@ls.asplists.com Related Links I want to build my first VB component! @ http://www.learnasp.com/learn/buildvbsimple.asp I get error overwriting DLL when updating component! @ http://www.learnasp.com/learn/FAQvbDLLoverwrite.asp ASP Component Building Book @ Http://www.learnasp.com/books/components.asp BulletProof VB Components by Charles Alexander @ http://www.microsoft.com/mind/0899/aspcomp/aspcomp.htm SafeArrays. Accessing from VB by Shelley Powers @ http://www.yasd.com/devaspcomp/bonus/arrays.htm Duwamish Books Sample @ http://msdn.microsoft.com/library/techart/dw1intro.htm Fitch and Mathers Application Sample @ http://msdn.microsoft.com/isapi/msdnlib.idc?theURL=/library/techart/fmstocks_web.htm http://www.learnASP.com/learn/buildvbthreads.asp by Charles M. Carroll Page 254 VB Component Threading Details by Charles Carroll special thanks to Jon Flanders, Stephen Martin and Juan Llibre Component written in Visual Basic are affected by some complex threading isses we will discuss here. The "bible" for all this is: Programming Distributed Applications with COM and Microsoft Visual Basic 6.0 by Ted Pattison, Published by Microsoft Press. Objects created and destroyed at the page level scale very well. Once a session level object is created it is attached to a specific, discrete thread. That thread can never be destroyed until all users assigned to that thread either <%session.abandon%> or their session times out. This is the internal workings of the ASP execution environment. Don Box wrote this fascinating detail up a couple of MSJs ago. Objects created with a session scope, i.e. set session("whatever")=server.creatobject("whatever.id") do not scale well and are affected by the threading issues in the following way: ● You tie the Session down to a particular thread ( instead of ASP being able to use any thread from the thread pool). ● If you place a object marked apartment into the SessionObject you have an object which can only live and be called from the Single-Threaded Apartment it was created in, ASP must run ALL request for that Session in that STA. ● If you don't do this (or only place Apartment Neutral Objects in the SessionObject ) ASP will run requests for that session on the first available thread. So imagine - you have a four processor machine running IIS/ASP - forty people come into your site, now each of those requests is now tied to a specific thread, now two requests stop (are not currently making requests) - one more comes in and gets dispatched to one of these two threads that are free, and one of the two that stopped comes back - but another Session is using that thread - there are now free threads that cannot be used - they are just sitting there doing nothing - while a user is waiting for its thread to be freed. This is just one example of what can go wrong (not to mention the additional work ASP must do to make sure this all works correctly). Overall placing object marked Apartment into the SessionObject is a very bad thing. You are way better off instantiating on every page. You are correct - that you cannot place an Apartment threaded object into the ApplicationObject - which is probably what they should have done with the SessionObject as well. All calls that involve objects conversing must be proxied. The proxy referring to is what the COM runtime creates in an Apartment when that Apartment receives an interface to a COM object which lives in another Apartment. For example - if you use a COM object which is marked "Free" in the registry - ASP will create that object and it will live in the Multi-Threaded Apartment (MTA), the page which is executing in a Single-Threaded Apartment (STA) will not get direct access to the object - but will talk to the object through what is called a proxy. The proxy looks just like the interface to the Page (has the same methods etc), but when the page calls a method, the proxy forwards the method call (parameters, name etc) to a COM provided channel. This channel calls what is refered to as a stub - which again looks just like the object - but lives in the same Apartment as the Object (in this case the MTA). Then finally the object gets called and then returns throught the same method. This is 1000xs slower that if the object lived in the same Apartment as the page (because of a thread switch - so switching threads you can see is very expensive). This is just how COM works. When a COM object is redesigned to be stateless and run under MTX, objects in the same package are not crossing process boundaries. Different packages are! Run the scenarios: Scenario 1: So if for example, + 100 people hit your site for a couple of pages and leave + 100 new people arrive in a couple of minutes + 200 people arrive after that and then + 50 people ===== 450 sessions/objects in memory with 50 !!! people on your site. And dozens or hundred of threads that can't be reclaimed for a while Scenario 2: + 100 people hit your site for a couple of pages and leave + 100 new people arrive in a couple of minutes + 200 people arrive after that and then + 50 people ===== 50 objects in memory because you destroyed all objects at the page level. No threads tied up. If it isn't Apartment Neutral (i.e. aggregates the Free-Threaded Marshaller) - you will tie the session down to that thread - so you have to ask yourself - is tying my sessions down to a specific thread a major performance hit - and that really depends on how many users are hitting your site and how often. In general I think it is a bad thing and should be avoided - unless there is no other way to accomplish what you want - and there almost always is a way - that isn't too much work and doesn't have any negative side-effects This is why I have <%@enablesessionstate=false%> and a blank global.asa. If I need an object, I create and destroy it at the page level. for almost every page on my site and with 10,000 sessions a day and 90,000 page views we still serve pages fast and don't get locked up very often. http://www.learnASP.com/learn/buildjava.asp by Charles M. Carroll Page 255 javacomponents Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/buildjava.asp Send Listserver Questions to javacomponents@ls.asplists.com Related Links Robert Zembowicz White Papers @ http://www.robertz.com/Papers/ Frank Leahy's Tutorial @ http://www.hotwired.com/webmonkey/99/29/index2a.html?tw=programming ASP Component Building w/Java Book @ Http://www.learnasp.com/books/components.asp Java COM discussion list @ http://discuss.microsoft.com/archives/java-com.html http://www.learnASP.com/learn/buildc.asp by Charles M. Carroll Page 256 C, C++, ATL ASP Component Building Building ASP components with C and/or C plus ATL is possible as well. The following links will explain the process and provide some valuable information on debugging, etc: Developing ASP Components with ATL by George Reilly: http://www.microsoft.com/workshop/server/asp/comp.asp This article is superb and concise. Active Server Components with VS 5.0: http://www.15seconds.com/issue/970422.htm Developer's Sample at: http://www.microsoft.com/windows/downloads/contents/AdminTools/IISDeveloperSample/default.asp?custarea=bus&site=nts&openmenu=&highlighteditem= If you have trouble building or running ASP components written in C/C++, we run a listserv/newgroup called [low-levelcomponents] where that is the only topic allowed you can join to get help. low-levelcomponents Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/buildc.asp Send Listserver Questions to low-levelcomponents@ls.asplists.com Related Links An Incredible High Quality Dcom List @ http://discuss.microsoft.com/archives/dcom.html The Best Collection of COM Articles @ http://www.sellsbrothers.com/tools/ Developmentor COM Tutorial @ http://beta.develop.com/com/ ASP C++/ATL Component Building Links @ http://www.learnasp.com/learn/buildc.asp ASP Component Building Book @ Http://www.learnasp.com/books/components.asp Busy ATL Listserve @ http://discuss.microsoft.com/archives/atl.html http://www.learnASP.com/learn/buildmtx.asp by Charles M. Carroll Page 257 MTS: Overview (buildmtxoverview.asp) - Page 258 MTS: Essentials (buildmtx2.asp) - Page 259 MTS: Transactional ASP pages (buildmtxasp.asp) - Page 260 MTS: Book (booksmtx.asp) - Page 261 MTS: Book (booksmtx2.asp) - Page 262 MTS: Registering Components (buildmtxregister.asp) - Page 263 http://www.learnASP.com/learn/buildmtxoverview.asp by Charles M. Carroll Page 258 MTX and Components Microsoft Transaction Server (MTX) is a tool included with IIS4 NT Option Pack. It is an essential long term ingredient to scalable, maintainable, reliable websites. It is necessary for commerce or mission critical websites, though it helps improve performance on all websites as well. Without involving MTX, every request to create an instance of a component (ala server.createobject) and destroy the instance of that component (ala set object=nothing) is sent directly to the component. IIS tends to cache objects so that when you destroy an instance, IIS probably will not remove it from memory so that the next creation attempt will be instant since it is already in memory. This is a direct violation of the DCOM rule that when there are zero instances of a component in memory, the component is automatically removed from memory. Any MTX aware component is now managed by MTX and the following benefits are available: ● MTX is managing the object so that it may unload or load instances as needed to improve performance. ● MTX objects need not run as the "standard ASP User". Components registered with MTX can impersonate a specific user. The typical segments of code that would be unique to components managed by MTX would look like this: Concept Code Capture Context shared by all MTX managed components private mycntxt as ObjectContext set mycntxt= GetObjectContext() Tell MTX your component has completed it's task sucessfully mycntxt.SetComplete Tell MTX your component has not completed it's task sucessfully mycntxt.SetAbort Tell MTX to create an instance of your component (don't use new, createobject, mycntxt.CreateInstance("... objectname ..") or server.createobject) http://www.learnASP.com/learn/buildmtx2.asp by Charles M. Carroll Page 259 MTX: Transaction Essentials Transaction Server is based on established client server paradigms of reliable transaction processing. The concepts are consistent regardless of the transaction engine involved. The traditional wisdom is that a robust transaction must pass the ACID test or the transaction procesing has flaws: Atomic: The transaction must execute completely or not at all. Consistent: The transaction must never leave any participant in an inconsistent state. Isolated: The effect of all individual transactions must have exactly the same effect whether run serially (in an ordered sequence) or parallel. Durable: All transactions must store their results on a permanent or durable device before reporting success. http://www.learnASP.com/learn/buildmtxasp.asp by Charles M. Carroll Page 260 MTX with ASP pages instead of Components ASP pages that need to take advantages of transactions can without being forced to move the ASP script into a component. First one of the following directives must be placed on the page: <%@ <%@ <%@ <%@ Transaction Transaction Transaction Transaction = = = = Required %> Requires_New %> Supported %> Not_Supported %> Of course the ASP page must include code to address both committing and aborting the transaction: <% SUB OnTransactionCommit() ... END SUB SUB OnTransactionAbort() ... END SUB %> http://www.learnASP.com/learn/booksmtx.asp by Charles M. Carroll Page 261 Database Workshop with Microsoft Transaction Server 2.0 written by Roger Jennings, Steven D. Grey, Rick A. Lievano published by Sams Publishing No writeup yet. Coming soon. BUY http://bn.bfast.com/booklink/click?sourceid=10446528&ISBN=0672311305 http://www.learnASP.com/learn/booksmtx2.asp by Charles M. Carroll Page 262 Not Ready Yet. Coming Soon! http://www.learnASP.com/learn/buildmtxregister.asp by Charles M. Carroll Page 263 Register Components with MTX Registering a Component with MTX requires that you specify how the component participates (or doesn't participate) in a transaction. The possibilties are: ● Requires a Transaction - run within a existing transaction, or if there is no existing transaction, MTX will create one. ● Requires a New Transaction - MTX starts a new transaction each time that component is activated. ● Support Transactions - run within a existing transaction, or if there is no existing transaction, MTX will run the component without a transaction. ● Does Not Support Transactions - This component will always run outside of existing transactions. http://www.learnASP.com/learn/components.asp by Charles M. Carroll Page 264 ASPMail: Simple Example (serverobjectsmail.asp) - Page 265 Upload: Simple Example (uploadsimple.asp) - Page 266 Upload: Multi-part form (uploadmultipart.asp) - Page 267 Upload: Limit Size (uploadlimitsize.asp) - Page 268 Upload: Many Files (uploadmanyfiles.asp) - Page 269 Perf Counters on ASP page (perfcounters.asp) - Page 270 http://www.learnASP.com/learn/serverobjectsmail.asp by Charles M. Carroll Page 265 ASPMail™ by Server Objects www.serverobjects.com is a great place to get a variety of components. Here we will give you a simple script utilizing genusa mail that e-mails me each time you run the page. http://www.activeserverpages.com/learn/test/serverobjectsmail.asp is the page you can test this at. 1 2 3 4 5 <html><head> <title>serverobjectsmail.asp</title> </head><body bgcolor="#FFFFFF"> <% ' ASPMail(tm) from www.serverobjects.com 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ' is not part of ASP per se, ' but a third party utility from serverobjects.com Set Mailer = Server.CreateObject("SMTPsvg.Mailer") Mailer.RemoteHost = "relay.datareturn.com" Mailer.FromName = "Some Student" Mailer.FromAddress = "somestudent@activeserverpages.com" Mailer.AddRecipient "Charles Carroll","cc@thebestweb.com" Mailer.AddBCC "Charles Carroll","charles@activeserverpages.com" Mailer.Subject = "ASPMail Tutorial" Mailer.BodyText = "Hi. Just trying the mail example" & vbCrLf Mailer.BodyText = "Line 2" Mailer.BodyText = "Line 3" If Mailer.SendMail then Msg = "mail sent sucessfully!" Else Msg = "mail was not sent sucessfully" End If response.write Msg %> </body></html> http://www.learnASP.com/learn/uploadsimple.asp by Charles M. Carroll Page 266 Upload File -- Simple Example by David Wihl utilizes file upload component from http://www.softartisans.com Uploading Files is easy using Active Server Pages and a great Active Server Component called SA-FileUp. This code sample allows you to use the Browse... button to select a file from your local hard disk. When you press the "Upload File" button, your browser will transmit the file to our web server. You are about to transmit a file from your local hard disk to the ActiveServerPages.Com web server. Please do not send confidential information. As you can see, no additional software was required on your client's computer: no ActiveX controls, no Java, just a simple HTML 3.2 form. On the server, you need ASP (for IIS version 3 or 4) and SA-FileUp - that's it. 1 <HTML><HEAD> 2 <TITLE>uploadsimple.asp by softwareartisans.com</TITLE> 3 </HEAD><body bgcolor="#FFFFFF"> 4 <form enctype="multipart/form-data" method="post" action="uploadsimplerespond.asp"> 5 <TABLE WIDTH="100%"> 6 <TR> 7 <TD ALIGN="RIGHT" VALIGN="TOP">Filename:</TD> 8 9 <TD ALIGN="LEFT"><INPUT TYPE="FILE" NAME="FILE1"> 10 </TD> 11 </TR> 12 <TR> 13 <TD ALIGN="RIGHT"> </TD> 14 <TD ALIGN="LEFT"><INPUT TYPE="SUBMIT" NAME="SUB1" VALUE="Upload File"></TD> 15 </TR> 16 <TR> 17 <TD ALIGN="RIGHT"> </TD> 18 <TD ALIGN="LEFT"> 19 <B><I><SMALL>Note: if a button labeled "Browse..." does not appear, then your 20 browser does not support File Upload. For Internet Explorer 3.02 users, a 21 free add-on is available from Microsoft. If you <b>do not see a Browse... button</b> 22 <A HREF="http://www.microsoft.com/msdownload/ieplatform/iewin95/iewin95.asp" TARGET="_new">click here to go to Microsoft's Site and get your free file upload add-on</A>. 23 Select "Internet Explorer 3.02 File Upload Add-On for Windows 95 & NT". 24 </SMALL></I></B> 25 26 27 28 29 </TD> </TR> </TABLE> </form> </BODY></HTML> The responder to the form will look like this: 1 2 3 4 5 6 7 8 9 <HTML><HEAD> <TITLE>Uploadsimplerespond.asp by softwareartisans.com</TITLE> </HEAD><BODY> Thank you for uploading your file.<br> <% Set upl = Server.CreateObject("SoftArtisans.FileUp") upl.Path = Server.Mappath ("/upload") & "/" & "tests" upl.SaveAs "upload.tst"%><BR> Total Bytes Written: <%=upl.TotalBytes%> </BODY></HTML> Let's walk through the sample and see what is going on. Look at the definition of the form. When using a form to upload files, the following items must be set: 1. 2. The FORM must have a tag of ENCTYPE="multipart/form-data". The <INPUT TYPE="FILE"> must have a tag of NAME= . This tells the browser to transmit the contents of the file when posting the form. Let's look at the form's processing (formresp.asp). The following line creates an instance of the SA-FileUp object: <% Set upl = Server.CreateObject("SoftArtisans.FileUp") %> The following line invokes the .SaveAs method and passes the name of the web server's destination file as a parameter. <% upl.SaveAs "C:\temp\upload.out" %><BR> In two lines you've uploaded a file! For bonus points, the following line retrieves the TotalBytes property and displays it to the user. Total Bytes Written: <%=upl.TotalBytes%> What did we learn? ● To upload files, there must be two elements on the form: ❍ <FORM ENCTYPE="multipart/form-data" ... > ❍ <INPUT TYPE="FILE" NAME="f1"> ● To process the form: ❍ First create an instance of the SA-FileUp component ❍ ● Second, invoke the .SaveAs method and specify a filename It is possible to retrieve other properties, such as total size of the upload. http://www.learnASP.com/learn/uploadmultipart.asp by Charles M. Carroll Page 267 Upload File -- Multi-Part Form by David Wihl utilizes file upload component from http://www.softartisans.com The previous example is fine if all you want is file uploads. However most people want to capture additional information on the form along with the file, such as a description. Normally, you can use ASP's Request.Form object to access these other elements on the form. However when uploading files, you must change the Encoding Type to "multipart/form-data". The ASP Request.Form object does not understand data transmitted using this encoding type. SA-FileUp provides a Form object that provides identical functionality to the ASP Request.Form object, but can understand the encoding type that is specific to file uploads. 1 2 3 4 5 6 7 8 9 <HTML><HEAD> <TITLE>uploadmultipart.asp by softwareartisans.com</TITLE> </HEAD><body bgcolor="#FFFFFF"> <form enctype="multipart/form-data" method="post" action="uploadmultipartrespond.asp"> Enter description: <input type="text" name="descrip"><br> Enter filename to upload: <input type="file" name="f1"><br> <input type="submit"> </form> </BODY></HTML> The responder to the form will look like this: 1 2 3 4 5 6 7 8 9 10 11 12 <HTML><HEAD> <TITLE>Uploadmultipartrespond.asp by softwareartisans.com</TITLE> </HEAD><BODY> Thank you for uploading your file.<br> <% Set upl = Server.CreateObject("SoftArtisans.FileUp") upl.Path = server.mappath("\upload") & "/tests" %> <% upl.SaveAs "upload.tst" %><BR> Your description is: '<%=upl.Form("descrip")%>'<BR> Total Bytes Written: <%=upl.TotalBytes%> <%set upl=nothing%> </BODY></HTML> In this case, the definition of the form still uses ENCTYPE="multipart/form-data", but now there is an additional form element containing a text box. Enter description: <input type="text" name="descrip"><br> Let's look at the form's processing (mformresp.asp). There is still the same creation of an instance. However, in this case we are referring to the form elements (description) explicitly by name. <% upl.SaveAs "C:\temp\upload.out" %><BR> Your description is: '<%=upl.Form("descrip")%>'<BR> Like the Request.Form syntax, we use upl.Form("name-of-the-form-element") to refer to the value of the form element. Since there is only a single file element, we do not have to explicitly specify which one we want to save. You can use this same mechanism to access all of your form elements, whether they be text boxes, radio buttons, checkboxes, selection boxes, etc. What did we learn? ● Even if there are multiple form elements, you must still use: ❍ ● ● <FORM ENCTYPE="multipart/form-data" ... > ASP's Request.Form object does not understand this encoding type. Instead use, SA-FileUp's Form object which offers identical functionality. To refer to elements on the form, use the name of the element on the form, i.e. upl.Form("descrip") http://www.learnASP.com/learn/uploadlimitsize.asp by Charles M. Carroll Page 268 Upload Limit File Size by David Wihl utilizes file upload component from http://www.softartisans.com The previous example showed how to upload multiple files and access each of their individual properties. Previously we've seen how to read properties of the file, such as the TotalBytes of the upload. There are several properties that can be set. One very useful property is called MaxBytes. MaxBytes allows you to set a firm limit on the size of the uploaded file, ensuring that malicious users do not fill up your server's hard disk with huge files. When you set the MaxBytes property (before saving the file!), SA-FileUp will write up to the number you specify and then stop. Any additional data will be discarded. You can set MaxBytes once and it will apply to all files in the current upload, limiting each of them to the value that you specify. The maximum file size that SA-FileUp can process is 2 GB. If set MaxBytes equal to zero (0), SA-FileUp will revert to the default maximum, which is 2 GB. Time for an example. We'll use the same simple form as in the very first upload: 1 2 3 4 5 6 7 8 <HTML><HEAD> <TITLE>uploadlimitsize.asp by softartisans.com</TITLE> </HEAD><body bgcolor="#FFFFFF"> <form enctype="multipart/form-data" method="post" action="uploadlimitsizerespond.asp"> Enter a big file to upload: <input type="file" name="f1"><br> <input type="submit"> </form> </BODY></HTML> The responder to the form will look like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <HTML><HEAD> <TITLE>Uploadlimitsizerespond.asp by softartisans.com</TITLE> </HEAD><BODY> Thank you for uploading your file.<br> <% Set upl = Server.CreateObject("SoftArtisans.FileUp") %> <% upl.MaxBytes = 1000 '--- limit the upload size to 1000 bytes %> The maximum size that you are permitted to upload is <%=upl.MaxBytes%> bytes per file.<br> <% upl.Path = server.mappath("\upload") & "/tests" upl.SaveAs "upload.out" %> Total Bytes Written: <%=upl.TotalBytes%><br> Server Filename: <%=upl.ServerName%><br> Total Bytes Transmitted by you: <%=Request.TotalBytes%> <%set upl=nothing%> </BODY></HTML> Let's look at the form's processing (formrespmax.asp). First, the MaxBytes: <% upl.MaxBytes = 1000 '--- limit the upload size to 1000 bytes %> The maximum size that you are permitted to upload is <%=upl.MaxBytes%> bytes per file.<br> We are setting MaxBytes as a limit for all files in this upload, even if there is more than one. MaxBytes is Read/Write property, meaning that it is possible to both set its value and retrieve its value. If you uploaded a file larger than 1000 bytes, you will have noticed that only the first 1000 bytes were written to disk. We also added a new property called ServerName. ServerName is the name of file as it is stored on the web server, including the full path. Server Filename: <%=upl.ServerName%><br> And finally we displayed an ASP intrinsic property that displays the precise total number of bytes transmitted by the browser. Total Bytes Transmitted by you: <%=Request.TotalBytes%> You may have noticed that the total bytes transmitted by you is larger than your original file's size on disk. This is normal, since the browser must add information such as headers and encoding information. Request.TotalBytes reports the total including the file, encoding information and other form elements that may be present. What did we learn? ● It is possible to limit the size of the upload by using the MaxBytes property. ● Some properties are Read Only such as TotalBytes, and some are Read/Write such as MaxBytes. ● The amount of information transmitted by the browser is always larger than the file because of addition encoding information and form elements. That completes our tutorial for now. Please see our many code samples for other examples of SA-FileUp functionality, including: ● Uploading to a Database ● Secure download from the server to the browser ● Saving the upload in binary format ● Manipulating files on the web server. Thank you for using our tutorial! Please visit the Software Artisans' web http://www.learnASP.com/learn/uploadmanyfiles.asp by Charles M. Carroll Page 269 Upload Many Files by David Wihl utilizes file upload component from http://www.softartisans.com The previous example showed how to upload a file and capture addition form elements. What if you wanted to transmit multiple files with a single form submit? To add a second (or other file), just add another <INPUT TYPE="FILE"> tag to your form. Even though the Internet Standard specification for HTTP Upload (RFC 1867) permits wildcarded filenames ("*.doc"), neither Netscape Navigator or Microsoft Internet Explorer support wildcarded names at this time. When they do, the current version of SA-FileUp will be able to process wildcarded filenames. For now, it is necessary to have an additional input tag for every file you want to upload. 1 2 3 4 5 6 7 8 9 <HTML><HEAD> <TITLE>uploadmanyfiles.asp by softartisans.com</TITLE> </HEAD><body bgcolor="#FFFFFF"> <form enctype="multipart/form-data" method="post" action="uploadmanyfilesrespond.asp"> Enter first filename: <input type="file" name="f1"><br> Enter second filename: <input type="file" name="f2"><br> <input type="submit"> </form> </BODY></HTML> The responder to the form will look like this: 1 2 3 4 5 6 7 <HTML><HEAD> <TITLE>Uploadmanyfilesrespond.asp by softartisans.com</TITLE> </HEAD><BODY> Thank you for uploading your files.<br> <% Set upl = Server.CreateObject("SoftArtisans.FileUp") upl.Path = server.mappath("\upload") & "/tests" %> 8 9 10 11 12 <% upl.Form("f1").SaveAs "upload1.out" %><BR> Total Bytes Written for file 1: <%=upl.Form("f1").TotalBytes%> <% upl.Form("f2").SaveAs "upload2.out" %><BR> Total Bytes Written for file 2: <%=upl.Form("f2").TotalBytes%> </BODY></HTML> Let's look at the form's processing (formmanyfilesrespond.asp). In this case we are referring to the file elements explicitly by name. <% upl.Form("f1").SaveAs "C:\temp\upload1.out" %><BR> <% upl.Form("f2").SaveAs "C:\temp\upload2.out" %><BR> Like the upl.Form syntax, we use upl.Form("name-of-the-form-element") to refer to the value of the file. The older method, upl.SaveAs, would still work, but would refer to the first file element that was found. This is ambiguous. So, when uploading multiple files, be explicit and use the .Form("file-element-name") syntax. All of the methods and properties, such as the TotalBytes are available when using this syntax. For example, Total Bytes Written for file 1: <%=upl.Form("f1").TotalBytes%> Internally, SA-FileUp has created an instance of another object to represent the uploaded file. This object is called the SAFile object. The SAFile object has properties and methods as well. See the Reference Section for details. What did we learn? ● If there are multiple file elements on the form, refer to them explicitly by name. ● For each uploaded file, SA-FileUp creates a new SAFile object to represent the uploaded file. Great - you've got lots of uploads working. http://www.learnASP.com/learn/perfcounters.asp by Charles M. Carroll Page 270 Performance Counter monitoring via a Web Page using PerfCounter component from www.softwing.com The following script monitors the officially undocumented error counters that were unofficially documented in: http://www.15seconds.com/Issue/981015.htm. The following code setup the monitor: 1 <html> 2 3 <head> 4 <title>perfcountersetup.asp</title> 5 </head><body> 6 <% 7 Set objQPerfCnt = CreateObject("Softwing.AspQPerfCounters") 8 bResult = objQPerfCnt.OpenQuery() 9 bResult = objQPerfCnt.AddCounter("\\.\Active Server Pages\Errors During Script Runtime") 10 bResult = objQPerfCnt.CollectQueryData() 11 varResult = objQPerfCnt.GetFormattedCounterVal(_ 12 "\\.\Active Server Pages\Errors During Script Runtime", 0) 13 bResult = objQPerfCnt.CloseQuery() 14 %> 15 </body> 16 </html> The following code displays that monitor: 1 <html><head> 2 <title>perfcounterswatcherror.asp</title> 3 </head><body> 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <% ' counters to watch Dim arrFriendlyName,arrCounterPath arrFriendlyName = Array("Total failed requests","Errors per second (current)",_ "Runtime errors (total)", "Script compiler errors (total)", _ "ASP preprocessor errors (total)") arrCounterPath = Array("\\.\Active Server Pages\Requests Failed Total", _ "\\.\Active Server Pages\Errors/Sec", _ "\\.\Active Server Pages\Errors During Script Runtime",_ "\\.\Active Server Pages\Errors From Script Compilers", _ "\\.\Active Server Pages\Errors From ASP Preprocessor") Dim objQPerfCnt, bResult, varResult, i Set objQPerfCnt = CreateObject("Softwing.AspQPerfCounters") bResult = objQPerfCnt.OpenQuery() for i = 0 to UBound(arrCounterPath) bResult = objQPerfCnt.AddCounter(arrCounterPath(i)) next bResult = objQPerfCnt.CollectQueryData() for i=0 to UBound(arrCounterPath) varResult = objQPerfCnt.GetFormattedCounterVal(arrCounterPath(i), 0) Response.Write "<b>" & arrFriendlyName(i) & "</b>: " Response.Write varResult & "<br>" & vbCrLf next %> </body> </html> Questions about this component can be directed to: aspsoftwing Listserver JOIN, QUIT or Search ARCHIVES: http://www.asplists.com/asplists/perfcounters.asp Send Listserver Questions to aspsoftwing@ls.asplists.com Related Links http://www.learnASP.com/learn/new.asp by Charles M. Carroll Page 271 New Lessons (new.asp) - Page 1 Global.asa Resources (globalmore.asp) - Page 2 Validation Resources (validationmore.asp) - Page 3 Graphic Size Detector (graphicdetect.asp) - Page 4 Database Display via GetRows (dbtablegetrows.asp) - Page 5 Database Display via GetString (dbtablegetstring.asp) - Page 6 ASPDB - Superb Database Component (aspdb.asp) - Page 7 Date/Time on ASP Pages by Tony Arguelles (datetime.asp) - Page 8 Time Tasks with Millisecond Accuracy (speedtimer.asp) - Page 9 Hidden Fields/Pass Data Among Pages (hidden.asp) - Page 10 Cookies/Pass Data Among Pages (cookies.asp) - Page 11 Remote Scripting Simple Example (remotescripting.asp) - Page 12 Remote Scripting/Microsoft Sample (remotescriptingms.asp) - Page 13 Database to ListBox Online Resources (dblistmore.asp) - Page 14 Dynamic ListBox Online Examples (listdynamicmore.asp) - Page 15 http://www.learnASP.com/learn/changed.asp by Charles M. Carroll Page 272 Recently Modified Lessons (changed.asp) - Page 1 Tips to Speed Up Pages (speedtips.asp) - Page 2 Time Tasks to Millisecond (speedtimer.asp) - Page 3 Just say NO to session objects (nosessionobjects.asp) - Page 4 ListBox: Online Resources (dblistmore.asp) - Page 5 Database Tables: Online Resources (dbtablemore.asp) - Page 6 Forms: Introduction (formintro.asp) - Page 7 Server Tuning Resources (speedserver.asp) - Page 8 Print All Pages (printout.asp) - Page 9 TreeView TOC updated (joust.asp) - Page 10 http://www.learnASP.com/learn/newbie.asp by Charles M. Carroll Page 273 Great Beginners Lessons (newbie.asp) - Page 1 Authentication Overview by Kevin Flicks (authenticate.asp) - Page 2 Display, Edit Database Data (dbfull1.asp) - Page 3 Database Display on Web Page (dbtable.asp) - Page 4 Paged (1 of x) Database displays (dbtablepaged.asp) - Page 5 Protecting Pages via Login (security.asp) - Page 6 Count Records Reliably (dbcount.asp) - Page 7 Simple Database Search (SQLwhereform1.asp) - Page 8 Advice for ASP Coding (advice.asp) - Page 9 Including/Reusing Content (inc.asp) - Page 10 Including Files Dynamically (includedynamic.asp) - Page 11 Display ListBox from Database (dblist.asp) - Page 12 Grab Server Variables (server.asp) - Page 13 Detect Browsers (bc.asp) - Page 14 Create, Process Forms (Form.asp) - Page 15 Easy Databases w/FREE GenericDB! (genericdb.asp) - Page 16 Linked Listboxes w/Jscript (listdynamic.asp) - Page 17 http://www.learnASP.com/learn/faqs.asp by Charles M. Carroll Page 274 Commerce: certificates, https:// (FAQCommerceCertif.asp) - Page 275 Commerce: online charging (FAQCommerceCharge.asp) - Page 276 Commerce: components, shopping carts (FAQCommerceCarts.asp) - Page 277 Jscript: closing DB Connections (FAQJscriptCleanUp.asp) - Page 278 Jscript: online references (FAQJscriptRefs.asp) - Page 279 Jscript: display databases (FAQJscriptDB.asp) - Page 280 Oracle: I can't connect (FAQOracleconnect.asp) - Page 281 Oracle: Know any good books? (FAQOraclebooks.asp) - Page 282 Oracle: Calling Stored Procs (FAQOraclestoredproc.asp) - Page 283 VB: DLL overwrite problems (FAQvbDLLoverwrite.asp) - Page 284 VB: Recommended books (FAQvbBooks.asp) - Page 285 http://www.learnASP.com/learn/FAQCommerceCertif.asp by Charles M. Carroll Page 275 [aspcommerce] listserv FAQ #1: How do I setup https:// and get a certificate? Two vendors offer this ● www.verisign.com ● www.thawte.com http://www.learnASP.com/learn/FAQCommerceCharge.asp by Charles M. Carroll Page 276 [aspcommerce] listserv FAQ #2: I want to process credit cards on my web site. Where do I start? Many sites offer credit card processing but here is a list (you can search the archives for opinions and rates, etc.) ● www.anacom.com ● www.cybercash.com ● www.charge.com ● ww.swreg.com ● http://www.authorizenet.com/ ● http://www.securetrading.co.uk (may do just the UK) ● http://www.worldpay.com ● http://www.merchantservices.com http://www.learnASP.com/learn/FAQCommerceCarts.asp by Charles M. Carroll Page 277 [aspcommerce] listserv FAQ #3: What ASP components and scripts work to charge online? ● ASPcharge from www.bluesquirell.com ● IPCharge from www.gosoftinc.com ● IISCart from http://www.iiscart.com ● PCAuthX used with Tellan's PCAuthorize*Hub at http://www.active4.com/default.asp?PI=PCAUTHX ● www.mercantec.com ● http://www.storefront.net ● http://www1.viaweb.com/softartisans/saxcheck.html ● ActiveShopper at http://www.active4.com http://www.learnASP.com/learn/FAQJscriptCleanUp.asp by Charles M. Carroll Page 278 [aspJscript] listserv FAQ #1: How do I close database connections? Question: In VBScript, after you would close the recordset and connection objects, you would insure that the objects are disposed of properly by adding: rs.close Set rs = Nothing conn.close Set conn = Nothing Can someone tell me if there is an equivalent in JavaScript? Answer: rs.close; rs=null; conn.close; conn=null; http://www.learnASP.com/learn/FAQJscriptRefs.asp by Charles M. Carroll Page 279 [aspJscript] listserv FAQ #2: Is there any online Jscript Tutorials? Scott Kallymer, author of the "Wise ASP" column at: http://www.aspalliance.com/wsk/ Phil Malone offers some "Jscript Tips" at: http://www.aspalliance.com/philmalone Scott Mitchell offers: http://www.4GuysFromRolla.com/webtech/vb2java.shtml http://www.learnASP.com/learn/FAQJscriptDB.asp by Charles M. Carroll Page 280 [aspJscript] listserv FAQ #3:How do I connect to a database with Jscript? There is some sample code to display a listbox from an ASP Database at: http://www.aspmagazine.com/aspmagazine/issue10jscript.asp http://www.learnASP.com/learn/FAQOracleconnect.asp by Charles M. Carroll Page 281 [asporacle] listserv FAQ #1: I cannot connect to Oracle via ASP.... contributed by Bret H. Grade bgrade@aris.com MCSE, MCP+Internet Senior Consultant, ARIS Corporation Inquire at http://www.aris.com What do I need for connectivity for Oracle from ASP: This question is a very valid question for most people beginning and experienced with Oracle from within ASP. Because of the variety of things that are needed, there can be many answers to this question. Here are the basics: ● SQL*Net needs to be loaded on the machine where IIS resides. ● A "System" DSN (Data Source Name) should be configured on the machine where IIS resides. Or you may use a "DSNless" connection. A connection of this type still requires you have the correct ODBC driver. See below. ● Your DSN connection consists of an ODBC driver. Here are your most utilized choices: ● Microsoft ODBC Driver for Oracle 2.00.00.6325 (Microsoft supplied driver) ● Microsoft ODBC for Oracle 2.573.3513.00 (Microsoft supplied driver) ● Oracle ODBC Driver 7.x or 8.x (Oracle supplied driver) Most people prefer to use the Microsoft ODBC Driver for Oracle 2.0 for the reason that is seems to be more stable than the 2.5 driver from MS. The Oracle ODBC Driver has a variety of incompatibility problems with ASP and it is not recommended to use this driver. ● Make sure you’ve tested the DSN before you implement. This will prevent you from having to deal with connectivity problems at this level while developing. The TNSNAMES.ORA file needs to have been configured on the machine where IIS resides. This file is located in you ORANT\NETWORK (or NET80)\ADMIN\ directory. An Example configuration is provided below: orcl.world = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (COMMUNITY = tcp.world) (PROTOCOL = TCP) (Host = THE IP ADDRESS OF YOUR HOST OR DNS NAME) (Port = 1521) ) (ADDRESS = (COMMUNITY = tcp.world) (PROTOCOL = TCP) (Host = THE IP ADDRESS OF YOUR HOST OR DNS NAME) (Port = 1526) ) ) (CONNECT_DATA = (SID = ORCL) ) ) Some things to note are the HOST, CONNECT_DATA, and PORT parameters. ● The host is the IP address or DNS name of the machine where the Oracle instance (database) you are trying to connect to resides. ● The CONNECT_DATA string is made up of the Oracle SID. The SID is the name of the Oracle Instance. ● The PORT parameter is defaulted to 1521 and 1526. These are the default installations where the listener listens for requests from the machine where Oracle is installed. What does a connection string to Oracle look like? Set AUM = Server.CreateObject("ADODB.Connection") AUM.Open Connect_String(DSN), USERNAME, PASSWORD How do you configure the Oracle ODBC Driver? To configure the ODBC driver, you will first need to : 1. open the "ODBC Data Sources" icon in the control panel applet. 2. Once opened, go to the "System DSN" tab and choose add. Select an ODBC driver (See "WHAT DO I NEED FOR CONNECTIVITY FOR ORACLE FROM ASP"). 3. Once selected, you will see the following screen minus everything below connect string. If you want the advanced configuration as shown below select options. * The above example is utilizing the "Microsoft ODBC Driver for Oracle 2.00.00.6325" driver. I’m getting an error with my SQL statement and I don’t know why! This problem seems to come up quite often. Rest assured, it is not just common to Oracle. Most of the time this problem is because the developer has not tested the SQL statement in question via a SQL tool (i.e. SQL Plus for Oracle or ISQL in SQL Server). Some of the steps you should take when debugging are: ● ALWAYS run your command through SQL*PLUS if your statement fails. This way you eliminate the fact that it could be a syntax problem with Oracle. ● If you have successfully tested the statement against the database outside of ASP, make sure your statement is syntactically correct with ADO. ● Make sure all concatenated statements have the correct spaces in them. sqlChk = "SELECT COUNT(NAME)" sqlChk = sqlChk & " FROM MYAPP_USERS" sqlChk = sqlChk & " WHERE NAME = UPPER('" & Request.Form("txtUserID") & "')" * Note: Although eliminating the number of lines for interpretation can optimize your code, some prefer readability to the slight performance increase. If you were to look closely, you would notice that the second and third line have a space between the start of the clause and the ". Another method to insure proper spaces between concatenated statements would be to put the space at the end of each line. ● Response.Write your sql statement to the screen. ● Make sure that you DO NOT have spaces in your table names. I keep getting a TNS error while trying to connect. Check the following: ● Insure that you can connect via SQL*PLUS. This will confirm that your TNSNAMES.ORA file is configured properly. If not, check the following: ● Verify the instance is running (i.e. Oracle is up). ● Make sure you have a TNSNAMES.ORA entry. See "WHAT DO I NEED FOR CONNECTIVITY FOR ORACLE FROM ASP". ● Check to see that the "TNS listener" service is running on the machine where Oracle resides. ● Check to make sure that you have the correct ODBC driver. See "WHAT DO I NEED FOR CONNECTIVITY FOR ORACLE FROM ASP". ● If you can connect via SQL*PLUS, check the following: ● Check to make sure that you have the correct ODBC driver. See "WHAT DO I NEED FOR CONNECTIVITY FOR ORACLE FROM ASP". http://www.learnASP.com/learn/FAQOraclebooks.asp by Charles M. Carroll Page 282 [asporacle] listserv FAQ #2: I need some good books on Oracle. Can you recommend any? ADO 2.0 Programmers Reference written by David Sussman & Alex Homer published by WROX book @ http://www.activeserverpages.com/books/wroxadoref.asp ASP and RDS Database Programming written by Matt Brown, David Sussman, Peter DeBetta, John Pappa, Eric Wilson published by WROX Press book @ http://www.activeserverpages.com/books/wroxadords.asp Oracle Programming with Visual Basic written by Nick Snowdon, published by Sybex According to "Bryan P.O'Neil" bponeil@sourceinformation.com: Not really about ASP... but... this is an excellent book and is a very good all around Oracle text. It includes detailed info on RDO, ODBC Direct, ADO and Oracle Objects for OLE. http://www.learnASP.com/learn/FAQOraclestoredproc.asp by Charles M. Carroll Page 283 [asporacle] listserv FAQ #3: How do I call an Oracle Stored Procedure by Surya Rao HOW TO CALL A STORED PROCEDURE FROM AN ASP PAGE: ================================================= Folks, contrary to popular belief there are many ways to call stored procedures from an ASP page. I've tried it with Oracle (the only REAL RDBMS ;-) and it works. If this bit below, is useful, it can be archived for future use by the LISTMASTER, with any changes. Assume you have a procedure like this one below, and that it has been already created on the Oracle database. This procedure doesn't return anything, but that doesn't change anything! STEP #1: +++++++++ /******STORED PROCEDURE ON ORACLE DATABASE************/ /*====================================================*/ create or replace procedure test_me is w_count integer; begin insert into TEST values ('Surya was here'); --commit it commit; end; /*****END OF STORED PROCEDURE****/ STEP # 2: +++++++++ I assume you have tested it from sql*plus by running the following statements: /************TEST THE STORED PROCEDURE FROM SQL*PLUS******/ SQL> execute test_me PL/SQL procedure successfully completed. SQL> /***************END OF TESTING THE STORED PROC************/ STEP# 3: ++++++++ /*****CALLING A STORED PROCEDURE FROM ASP******************/ 1. USING THE CONNECTION OBJECT You can execute stored procedures which perform Oracle Server side tasks and return you a recordset. You can only use this method if your stored procedure doesn't return any OUTPUT values. <% Set Conn = Server.CreateObject("ADODB.Connection") Conn.execute "test_me",-1,4 %> Note that -1 means no count of total number of records is required. If you want to get the count, substitute count with some integer variable Note that 4 means it is a stored procedure. By using the actual number -1 and 4, you don't need the server side include ADOVBS.INC ;-) The above would do the job on the database and return back to you without returning any recordsets. Alternatively, you could: <% Set rs = conn.execute("test_me",w_count,4) %> W_count is the number of records affected. If your stored procedure were to return a query result, it is returned within your recordset (rs). This method is useful with Stored procs which return results of an SQL query 2. USING THE COMMAND OBJECT <% Set Conn = Server.CreateObject("ADODB.Connection") Set Comm = Server.CreateObject("ADODB.Command") Set comm.ActiveConnection = conn comm.commandtype=4 '(or use adCmdStoredProc instead of 4, but then you would have to 'include the ADOVBS.INC. Its upto you comm.commandtext = "test_me" comm.execute 'or Set rs = comm.execute() %> STEP# 4 +++++++++ /************PASSING INPUT/OUTPUT PARAMETERS**************************/ <% 'If your stored procedure accepts IN parameters and returns OUT parameters 'here's how to go about it set param = comm.Parameters param.append comm.createparameter("Input",3,1) param.append comm.createparameter("Output",3,2) 'Note that 3 = adInteger for the datatype 'Note that 1=adParamInput and 2=adParamOutput for parameter direction 'Pass the input value comm("Input") = "...." OR set param = comm.createparameter("InPut",3,1) set param = comm.createparameter("OutPut",3,2) comm.parameters.append param 'Pass the input value comm("Input") = "...." 'Execute after setting the parameters comm.execute() 'If your stored procedure returns OUT parameters, here's how to get it Out_1 = comm("Output") 'and so on... %> Thats it! http://www.learnASP.com/learn/FAQvbDLLoverwrite.asp by Charles M. Carroll Page 284 [aspVBComponents] listserv FAQ #1:I cannot overwrite a DLL I want to update.... writeup thanks to Michiel van Otegem <michiel@itcomposer.nl> This happens when the DLL is loaded in memory because it is in use or has been used by an application. The DLL needs to be unloaded before it can be overwritten. The solution depends on the version of Internet Information Server (IIS) and if Microsoft Transaction Server (MTX) is being used or not. IIS version 3 (no MTX) In order to unload the DLL, you need to stop the webservice. This can be done through Control Panel->Services or with the Internet Service Manager. After the webservice has stopped, the DLL can be overwritten. When the webservice restarts the new DLL is in place and will be used for subsequent calls. IIS version 4 If the DLL is not registered as an MTX package and the website(s) using the DLL do not run in a separate memory space (check this with the Internet Service Manager), the same course of action as with IIS 3 is to be taken. Because of the complexity of the webservice in IIS 4, the easiest way to shutdown the webservice is through Control Panel->Services. If the DLL is not registered as an MTX package and the website(s) using the DLL all run in a separate memory space, stopping those websites will suffice. The DLL can then be overwritten en the sites can be restarted. If the DLL is registered as an MTX package, the DLL will be unloaded after the amount of minutes set with the Transaction Server Explorer for that package, after which you can overwrite the DLL. If the DLL hasn’t been unloaded yet, you can force it to unload with the Transaction Server Explorer by choosing Shutdown (right click on a package). After the new DLL is in place choose Refresh All Components (right click on the computer with the DLL). There’s a catch however… the new DLL needs to be compiled with binary compatibility with the old DLL. If you don’t do this, you have to unregister and remove the old DLL, place the new DLL, register it and import it into the right package again. http://www.learnASP.com/learn/FAQvbBooks.asp by Charles M. Carroll Page 285 [asp VB Components] listserv FAQ #2: How Do I make my first VB Component? see: ● http://www.activeserverpages.com/learn/buildvbsimple.asp ● http://www.activeserverpages.com/learn/buildregister.asp That should get you started. http://www.learnASP.com/learn/overview.asp by Charles M. Carroll Page 286 ASP Objects: Built In (aspobjects.asp) - Page 287 ASP Objects: Created when Needed (aspobjects2.asp) - Page 288 http://www.learnASP.com/learn/aspobjects.asp by Charles M. Carroll Page 287 Built-In ASP Objects Response Object Send text, data and cookies to the browser and control each stage of transmitting the page. Its methods can be used to send text, data and cookies to the browser and control each stage of transmitting the page. Server Object create COM objects, some conversion facilities and overall scripting control. Request Object Read submitted form data, cookies and server variables. Session Object allows you to attach data to a specific user browsing your site that is isolated and invisible to other users. Application Object Allows you to manipulate global data in your script that will be visible to all users browsing the site or your script code. methods: lock, unlock http://www.learnASP.com/learn/aspobjects2.asp by Charles M. Carroll Page 288 Other ASP Objects Some objects will not be needed for all web pages. Those objects are included with ASP but are created explicity by the page when needed so they are not always in memory: BrowserCap object - this can simplify detecting browsers and aid in writing one page that reacts to all browsers instead of having to write separate pages for each browser. FileSystem object - this object provides a script with tools to manipulate files and directories. ADO Objects - The connection, recordsets, command and field objects make programming high concurrency database reads and updates possible. Dictionary object - provides an alternative to arrays that can be accessed/keyed by names instead of numbers and elements can be added or removed in any sequence. Misc. Objects - Content Linker, Permission Checker, Ad Rotator, Page Counter, etc. http://www.learnASP.com/learn/alphaindex.asp by Charles M. Carroll Page 289 A ADO (Active Data Objects) Features ToC (/learn/ado.asp) - Page 106 ASPDB - Displaying A Table (/learn/aspdb1.asp) - Page 104 ASPDB - Editing A Table (/learn/aspdb2.asp) - Page 105 Add Record w/SQL #1 (/learn/dbnewrec.asp) - Page 114 Add Record w/SQL #2 (/learn/dbnewSQL.asp) - Page 115 Add Record with .AddNew Method (/learn/dbnewADO.asp) - Page 116 ADSI: Active Directory Services Interface Intro (/learn/ADSI.asp) - Page 207 Advice For Better Coding! (/learn/advice.asp) - Page 216 Application Data (/learn/sessionsapps.asp) - Page 171 Application Data: Worlds Fastest ListBox (/learn/speedappdata.asp) - Page 172 ASPExpress - HOT ASP Editor (/learn/aspexpress.asp) - Page 168 Authentication/Security TOC (/learn/authenticate.asp) - Page 137 Arrays TOC (/learn/subjectArrays.asp) - Page 0 Arrays: Basics (/learn/arrays.asp) - Page 153 Arrays: Variable Size (/learn/arrays2.asp) - Page 154 Arrays: Best Way To Load (/learn/arrays3.asp) - Page 155 Authentication TOC (/learn/subjectAuthenticate.asp) - Page 0 Authenticate: Overview by Kevin Flick (/learn/authenticateoverview.asp) - Page 138 Authenticate: Comparison by Kevin Flick (/learn/authenticatecomparisons.asp) - Page 139 Authenticate: NT Challenge/Response by Kevin Flick (/learn/authenticatentcr.asp) - Page 140 Authenticate: Basic Authentication by Kevin Flick (/learn/authenticatebasic.asp) - Page 141 Authenticate: Cookies by Kevin Flick (/learn/authenticatecookies.asp) - Page 142 Authenticate: Certificates by Kevin Flick (/learn/authenticatecertificate.asp) - Page 143 Authenticate: Build Your Own by Kevin Flick (/learn/authenticatebuild.asp) - Page 144 Authenticate: Protect Pages via Login #1 (/learn/security.asp) - Page 145 Authenticate: Protect Pages via Login #2 (/learn/security2.asp) - Page 146 Authenticate: 3rd Party by Kevin Flick (/learn/authenticate3rdparty.asp) - Page 147 B Books & Online Resources (/learn/research.asp) - Page 211 Browscap: Basics (/learn/bc.asp) - Page 27 Browscap: Intricate Details (/learn/bcdetails.asp) - Page 28 BrowserHawk: Determing Browser Type (/learn/bhbrowtype.asp) - Page 29 BrowserHawk: older AOL browsers (/learn/bhaol.asp) - Page 30 Browserhawk: MS-Wallet (/learn/bhwallet.asp) - Page 31 BrowserHawk - Reverse DNS lookups (/learn/bhresolveip.asp) - Page 32 BrowserHawk - Frame support (/learn/bhframes.asp) - Page 33 C C++/ATL ASP Component Building (/learn/buildc.asp) - Page 256 CASE syntax #1 (/learn/case.asp) - Page 58 CASE syntax #2 (/learn/case2.asp) - Page 59 Checkbboxes in Forms (/learn/formcheckbox.asp) - Page 55 Content Linker: Prev/Next Page (/learn/cl.asp) - Page 238 Content Linker: TOC (/learn/cl2.asp) - Page 239 Content Linker: Listbox of contents (/learn/cl3.asp) - Page 240 Commerce: certificates, https:// (/learn/FAQCommerceCertif.asp) - Page 275 Commerce: online charging (/learn/FAQCommerceCharge.asp) - Page 276 Commerce: components, shopping carts (/learn/FAQCommerceCarts.asp) - Page 277 Converting a DB to a Comma-Delimited file (/learn/dbconvert.asp) - Page 99 Count Records in Query (/learn/dbcount.asp) - Page 112 Cookies: Reading Them (/learn/cookiesform.asp) - Page 66 Cookies: Writing Them (/learn/cookiesformrespond.asp) - Page 67 Cookies: Deleting Them (/learn/cookiesforget.asp) - Page 68 Cookies: Simplified by Paul Rigor (/learn/cookiesub.asp) - Page 69 Cache No More by Phil Paxton (/learn/cachenomore.asp) - Page 217 CASE reads better than IF (/learn/caseisbetter.asp) - Page 228 advice: Close objects, set to Nothing (/learn/cleanup.asp) - Page 222 Commerce and ASP (/learn/commerce.asp) - Page 195 Components from 3rd Party (/learn/components.asp) - Page 264 Component Checker (/learn/componentchecker.asp) - Page 48 Core Ideas TOC (/learn/core.asp) - Page 3 Credits & Instructions (/learn/credits.asp) - Page 2 D Date/Time on ASP Pages by Tony Arguelles (/learn/datetime.asp) - Page 18 Databases TOC (/learn/database.asp) - Page 80 DB: Access vs. SQL Server (/learn/accessSQLserver.asp) - Page 101 DB: Converting a DB to a Comma-Delimited file (/learn/dbconvert.asp) - Page 99 DB: Count Records in Query (/learn/dbcount.asp) - Page 112 DB: Deleting a Record w/SQL (/learn/dbSQLdelete.asp) - Page 100 DB: Cursor Types by Phil Paxton (/learn/adocursortypes.asp) - Page 113 DB: Generic DB by Eli Robillard (/learn/genericdb.asp) - Page 87 DB: GetString function (/learn/dbgetstring.asp) - Page 117 DB: Input Form (/learn/dbnewrec.asp) - Page 114 DB: Input Form, added w/SQL (/learn/dbnewSQL.asp) - Page 115 DB: Input Form, Added w/ADO .addnew (/learn/dbnewADO.asp) - Page 116 DB: Limiting Number of Records (/learn/dbmaxrecs.asp) - Page 110 DB: List Box Display (/learn/dblist.asp) - Page 85 DB: Paging Records (/learn/dbtablepaged.asp) - Page 111 ADO: Schemas to access table lists (/learn/dbschemas.asp) - Page 119 ADO: Schemas to access All Data (/learn/dbschemasall.asp) - Page 120 DB: SQL Mistakes (/learn/dbtroubleshoot2.asp) - Page 121 DB: Table Display w/Simple Code (/learn/dbsimple.asp) - Page 83 DB: Table Display for any Table (/learn/dbtable.asp) - Page 84 DB: Table Display,1 param (/learn/db1parm.asp) - Page 122 DB: Table Listings from Databases (/learn/dbtablelists.asp) - Page 118 DB: Table Display: More ways... (/learn/dbtablemore.asp) - Page 88 DB: Table Show-Edit Record #1 (/learn/dbfull1.asp) - Page 96 DB: Table Show-Edit Record #2 (/learn/dbfull2.asp) - Page 97 DB: Table Show-Edit Record #3 (/learn/dbfull3.asp) - Page 98 DB: Troubleshooting Part 1 (/learn/dbtroubles.asp) - Page 81 DB: Troubleshooting Part 2 (/learn/dbtroubles2.asp) - Page 82 DB: Update/Edit Record (/learn/dbupdate.asp) - Page 123 Dictionary Objects (/learn/dictionary.asp) - Page 156 Documentation, free from Microsoft (/learn/docs.asp) - Page 6 DSN: DSNLess Connections (/learn/dbopen.asp) - Page 89 DSN: DSN Setup #1 by Rob Martinson (/learn/dsn1.asp) - Page 90 DSN: DSN Setup #2 by Rob Martinson (/learn/dsn2.asp) - Page 91 DSN: DSN Setup #3 by Rob Martinson (/learn/dsn3.asp) - Page 92 DSN: DSN Setup #4 by Rob Martinson (/learn/dsn4.asp) - Page 93 DSN: DSN Setup #5 by Rob Martinson (/learn/dsn5.asp) - Page 94 DSN: DSN Setup #6 by Rob Martinson (/learn/dsn6.asp) - Page 95 e Editor: ASPExpress - HOT ASP Editor (/learn/aspexpress.asp) - Page 168 Encaspulate Code! (/learn/encapsulate.asp) - Page 227 Encode with Redirects (/learn/encode.asp) - Page 219 advice: Error Trapping Strategies (/learn/errorstrategies.asp) - Page 229 advice: Error Trapping Secrets (/learn/errorsecrets.asp) - Page 230 F File Objects: Read Directory (/learn/fileobjects.asp) - Page 241 File Objects: Display Directory as Links/Graphics (/learn/fileobjects2.asp) - Page 242 File Objects: Read Disk Drive by Steven Harper (/learn/fileobjects3.asp) - Page 243 File Objects: Show Dir List by Tim Foster (/learn/fileobjects4.asp) - Page 244 File Upload: Simple Example (/learn/uploadsimple.asp) - Page 266 File Upload: Multi-part form (/learn/uploadmultipart.asp) - Page 267 File Upload: Limit Size (/learn/uploadlimitsize.asp) - Page 268 File Upload: Many Files (/learn/uploadmanyfiles.asp) - Page 269 Forms/Decisions Table of Contents (/learn/Form.asp) - Page 51 Forms: For Each Iteration (/learn/formforeach.asp) - Page 64 Forms: mailing w/ASPMail (/learn/formsendmail.asp) - Page 65 Format: Numbers #1 (/learn/formatnumbers.asp) - Page 15 Format: Numbers #2 (/learn/formatnumbers2.asp) - Page 16 Format: Dates #1 (/learn/formatdates.asp) - Page 17 Forms: Introduction (/learn/formintro.asp) - Page 52 Forms: Check Box (/learn/formcheckbox.asp) - Page 55 Forms: ListBox (/learn/formlistbox.asp) - Page 57 Form: Listbox Linked Dynamically w/JavaScript (/learn/listdynamic.asp) - Page 198 Form: ListBox Linked Dynamically from Database w/JavaScript (/learn/listdynamicdb.asp) - Page 200 Form: Listboxes Easy Choices by Bill Wilkinson (/learn/listdual.asp) - Page 201 Forms: Radio Buttons (/learn/formradio.asp) - Page 56 Forms: Text Box (/learn/formtextbox.asp) - Page 53 Forms: Text Area (/learn/formtextarea.asp) - Page 54 Frequently Asked Questions (/learn/faqs.asp) - Page 274 Function: Working Days (/learn/functionworkingdays.asp) - Page 164 G Generic DB by Eli Robillard (/learn/genericdb.asp) - Page 87 Getstring method (/learn/dbgetstring.asp) - Page 117 Getstring to display database table (/learn/dbtablegetstring.asp) - Page 107 getrows to display database table (/learn/dbtablegetrows.asp) - Page 108 Sessions: Global.asa Events (/learn/global.asp) - Page 174 Global.asa and Scalability (/learn/globalproblems.asp) - Page 176 H HTMLencode / server.htlmencode (/learn/res5.asp) - Page 11 Hidden Fields/Pass Data Between Pages (/learn/hidden.asp) - Page 74 Homesite/HTML Editor w/ASP Support (/learn/homesite.asp) - Page 169 I If reads worse than CASE (/learn/caseisbetter.asp) - Page 228 IF syntax #1 (/learn/if.asp) - Page 60 IF syntax #2 (/learn/if2.asp) - Page 61 IF syntax #3 (/learn/if3.asp) - Page 62 IF syntax #4 (/learn/if4.asp) - Page 63 Include: Basics (/learn/inc.asp) - Page 12 Include: Dynamic FileName (/learn/includedynamic.asp) - Page 13 Include: Sample Exercise (/learn/booksample.asp) - Page 14 Index Server w/ADO (/learn/indexserver.asp) - Page 194 IsClientConnected & Stray Tasks (/learn/isclientconnected.asp) - Page 185 J Java ASP Components Building (/learn/buildjava.asp) - Page 255 Jscript: closing DB Connections (/learn/FAQJscriptCleanUp.asp) - Page 278 Jscript: online references (/learn/FAQJscriptRefs.asp) - Page 279 Jscript: display databases (/learn/FAQJscriptDB.asp) - Page 280 JScript ServerSide: Resources (/learn/javascript.asp) - Page 196 Joins in SQL by Aaron Alexander (/learn/dbjoins.asp) - Page 0 L Loops: DO WHILE/UNTIL #1 (/learn/DoLoop.asp) - Page 19 Loops: Timeouts #2 (/learn/DoLoop2.asp) - Page 20 Loops: Intercepting Timeouts #3 (/learn/DoLoop3.asp) - Page 21 Limiting database Records (/learn/dbmaxrecs.asp) - Page 110 Listbox Display from database (/learn/dblist.asp) - Page 85 Listbox from Database Online Resources (/learn/dblistmore.asp) - Page 86 ListBox in forms (/learn/formlistbox.asp) - Page 57 Listbox linked Dynamically w/JavaScript (/learn/listdynamic.asp) - Page 198 ListBox Linked Dynamically from Database w/JavaScript (/learn/listdynamicdb.asp) - Page 200 Listbox Dynamic Online Examples (/learn/listdynamicmore.asp) - Page 199 Listbox Easy Choices by Bill Wilkinson (/learn/listdual.asp) - Page 201 M Mailing Form w/ASPMail (/learn/formsendmail.asp) - Page 65 Mail: Simple Example (/learn/serverobjectsmail.asp) - Page 265 MSMQ: Overview (/learn/MSMQ.asp) - Page 208 Microsoft Transaction Server (MTS) (/learn/buildmtx.asp) - Page 257 MTS: Overview (/learn/buildmtxoverview.asp) - Page 258 MTS: Essentials (/learn/buildmtx2.asp) - Page 259 MTS: Transactional ASP pages (/learn/buildmtxasp.asp) - Page 260 MTS: Books (/learn/booksmtx.asp) - Page 261 MTS: Registering Components (/learn/buildmtxregister.asp) - Page 263 N New Lessons TOC (/learn/new.asp) - Page 271 Nothing and Scalability (/learn/nothing.asp) - Page 186 New Record w/SQL #1 (/learn/dbnewrec.asp) - Page 114 New Record w/SQL #2 (/learn/dbnewSQL.asp) - Page 115 New Record with .AddNew Method (/learn/dbnewADO.asp) - Page 116 O Option Explicit (/learn/explicit.asp) - Page 218 DB: Oracle and ASP (/learn/oracle.asp) - Page 102 Oracle: I can't connect (/learn/FAQOracleconnect.asp) - Page 281 Oracle: Know any good books? (/learn/FAQOraclebooks.asp) - Page 282 Oracle: Calling Stored Procs (/learn/FAQOraclestoredproc.asp) - Page 283 P Paging Records in Database Display (/learn/dbtablepaged.asp) - Page 111 Perf Counters on ASP page (/learn/perfcounters.asp) - Page 270 Perlscript ServerSide: Resources (/learn/perlscript.asp) - Page 202 PWS: Personal Web Server Introduction (/learn/PWS.asp) - Page 50 Prpoerties of COM objects: onl read once (/learn/propertyexpense.asp) - Page 225 Q Quality, Re-Usable Code TOC (/learn/qualitycode.asp) - Page 148 R Radio Buttons in Forms (/learn/formradio.asp) - Page 56 RDS: Remote Data Services Intro (/learn/rds.asp) - Page 205 RDS Resources: RDS Expert Carl Prothman (/learn/prothman.asp) - Page 206 Remote Scripting: Simple Example (/learn/remotescripting.asp) - Page 203 Resource: Must Buy Component Building Book (/learn/bookcomponents.asp) - Page 212 Resource: ASP101.com Scripts for your site (/learn/asp101.asp) - Page 213 Resource: 4GuysFromRolla.com Tons of ASP Material (/learn/4guysfromrolla.asp) - Page 214 Resource: ASPToday.com from WROX (/learn/asptoday.asp) - Page 215 Response: Basics (/learn/res.asp) - Page 7 Response: Buffer Control (/learn/res2.asp) - Page 8 Response: Redirection (/learn/res3.asp) - Page 9 Response: Quotes & Special Characters (/learn/res4.asp) - Page 10 Response: Encoding URLs, HTML (/learn/res5.asp) - Page 11 S Safe Color Pallete (/learn/safecolors.asp) - Page 210 Schemas to access table lists (/learn/dbschemas.asp) - Page 119 Schemas to access All Data (/learn/dbschemasall.asp) - Page 120 Searching a Database Example (/learn/SQLandor.asp) - Page 132 advice: Secure Code and Data (/learn/securecode.asp) - Page 226 advice: Server.MapPath is Good (/learn/pathmap.asp) - Page 223 Server Variables: Popular Ones (/learn/server.asp) - Page 22 Server Variables: Domain/Host Name (/learn/server2.asp) - Page 23 Server Variables: Displaying All (/learn/serverall.asp) - Page 24 Sessions: What are they? (/learn/sessionswhat.asp) - Page 72 Session COM objects are wasteful (/learn/nosessionobjects.asp) - Page 224 Speed: Research Online (/learn/speedresearch.asp) - Page 179 Speed: Coding Tips (/learn/speedtips.asp) - Page 181 Speed: Database Percieved Speed (/learn/speedtables.asp) - Page 182 Speed: Database Retrieval Speed (/learn/speedtablesall.asp) - Page 183 Speed: OLEDB & ODBC Drivers differences (/learn/speedtablesdrivers.asp) - Page 184 Speed: Time Tasks w/VB Component by Sunny Yu #1 (/learn/asptime.asp) - Page 306 Speed: Time Tasks w/VB Component by Sunny Yu #2 (/learn/asptimer.asp) - Page 307 Speed, Scalability TOC (/learn/speedscale.asp) - Page 170 Speedup Your Server (/learn/speedserver.asp) - Page 178 SQL statements: Write to Browser (/learn/sqlwrite.asp) - Page 220 SQL Table of Contents (/learn/SQL.asp) - Page 124 SQL Troubles (/learn/SQLtroubles.asp) - Page 125 SQL: Example Tables (/learn/SQLexamples.asp) - Page 126 SQL: Where Clause Basics (/learn/SQLwhere.asp) - Page 127 SQL: Where Clause Examples (/learn/SQLwhere2.asp) - Page 128 SQL: Search Forms #1 (/learn/SQLwhereform1.asp) - Page 129 SQL: Search Forms #2 (/learn/SQLwhereform2.asp) - Page 130 SQL: Search Forms #3 (/learn/SQLwhereform3.asp) - Page 131 SQL: Search AND/OR Operators (/learn/SQLandor.asp) - Page 132 SQL: Search AND/OR Examples (/learn/SQLandor2.asp) - Page 133 SQL: COUNT, GROUPBY (/learn/SQLcount.asp) - Page 134 SQL: SUM, MIN, AVE, MAX (/learn/SQLaggregate.asp) - Page 135 SQL Joins by Aaron Alexander (/learn/dbjoin.asp) - Page 136 Strings: Core Functions (/learn/strings.asp) - Page 149 Strings: SPLIT Function (/learn/stringsplit.asp) - Page 150 Strings: REPLACE Function (/learn/stringreplace.asp) - Page 151 Strings: JOIN Function (/learn/stringjoin.asp) - Page 152 Subroutine: Working with Dates #1 (/learn/subdates.asp) - Page 157 Subroutine: Working with Dates #2 (/learn/subdates2.asp) - Page 158 Subroutine: Query2Table (/learn/subdbtable.asp) - Page 159 Subroutine: Query2List (/learn/subdblist.asp) - Page 160 Subroutine: Highly Reusable (/learn/subreusable.asp) - Page 161 Subroutine: List Box w/optional params (/learn/subDBlistbest.asp) - Page 162 Subroutine: Abstract HTML by Phil Paxton (/learn/libhtml.asp) - Page 163 T Table Display from database w/Simple Code (/learn/dbsimple.asp) - Page 83 Table Display from database (/learn/dbtable.asp) - Page 84 Table Display from database,1 param (/learn/db1parm.asp) - Page 122 Table Listings from Databases (/learn/dbtablelists.asp) - Page 118 TextBoxes in Forms (/learn/formtextbox.asp) - Page 53 TextAreas in Forms (/learn/formtextarea.asp) - Page 54 Text Files: Reading Them off Server (/learn/txtread.asp) - Page 233 Text Files: Writing Them on Server (/learn/txtwrite.asp) - Page 234 Text Files: Meyers-Briggs parsing #1 (/learn/mb1.asp) - Page 235 Text Files: Meyers-Briggs parsing #2 (/learn/mb2.asp) - Page 236 Text Files: Meyers-Briggs parsing #3 (/learn/mb3.asp) - Page 237 Time Tasks with Millisecond Accuracy (/learn/speedtimer.asp) - Page 180 Troubleshooting: Basics (/learn/errors1.asp) - Page 35 Troubleshoot: Component Problems (/learn/componentchecker.asp) - Page 48 Troubleshoot: Drivers Versions/Info by Christophe Wille (/learn/connectioninfo.asp) - Page 49 Troubleshoot: Error Msg - Operation must use Updatable Query (/learn/FAQdbUpdate.asp) - Page 38 Troubleshoot: Error Msg - User Entered ' in field (/learn/FAQdbSinglequote.asp) - Page 39 Troubleshoot: Error Msg - LIKE operator * not working (/learn/FAQdbLIKE.asp) - Page 40 Troubleshoot: Error Msg - retrieving MEMO/BLOBs generates error (/learn/FAQdbMEMO.asp) - Page 41 Troubleshoot: Error Msg - Syntax Error in SQL Statement (/learn/FAQdbSQLSyntax.asp) - Page 42 Troubleshoot: List serves to Help! (/learn/asptroubles.asp) - Page 44 Troubleshoot: List serves Worldwide (/learn/asptroubles2.asp) - Page 45 Troubleshoot: List serves Specialized (/learn/asptroubles3.asp) - Page 46 Troubleshoot: Trapping EVERY Error (/learn/dbtablewitherrortrap.asp) - Page 36 Troubleshoot: Trapping Every DB Error (/learn/dbtroubleshoot.asp) - Page 37 Troubleshoot: Trapping Open Connections (/learn/dbtroubleshootopen.asp) - Page 43 Troubleshoot: Version of ASP Sofware (/learn/versioncheck.asp) - Page 47 Troubleshooting, Error Trapping TOC (/learn/troubles.asp) - Page 34 U Usability: Resources (/learn/usability.asp) - Page 209 Usability: Safe Color Pallete (/learn/safecolors.asp) - Page 210 V VB ASP Components Building TOC (/learn/buildcomponents.asp) - Page 246 VB Components: Simple Component (/learn/buildvbsimple.asp) - Page 247 VB Components: Registering Component (/learn/buildregister.asp) - Page 248 VB Components: ADO, Run It! (/learn/buildvbado.asp) - Page 249 VB Components: ADO, Build It! (/learn/buildvbado2.asp) - Page 250 VB Components: VB Warnings/Guidelines (/learn/buildvbguidelines.asp) - Page 251 VB Components: General Building Guidelines (/learn/buildvb.asp) - Page 252 VB Components: Installation Requirements (/learn/buildvb2.asp) - Page 253 VB Components: Threading Models (/learn/buildvbthreads.asp) - Page 254 VB: DLL overwrite problems (/learn/FAQvbDLLoverwrite.asp) - Page 284 VB: Recommended books (/learn/FAQvbBooks.asp) - Page 285 Visual Interdev Resource: VI King Michael Admunsen (/learn/admunsen.asp) - Page 167 VBScript version5 Feature (/learn/vbs5.asp) - Page 165 Version Check of Database Drivers (/learn/connectioninfo.asp) - Page 49 Version Check of Server Software (/learn/versioncheck.asp) - Page 47 http://www.learnASP.com/learn/comingsoon.asp by Charles M. Carroll Page 290 Data Types: VBScript (types.asp) - Page 291 Data Types: Conversion (convert.asp) - Page 292 Loops: FOR NEXT #1 (ForNext.asp) - Page 293 Loops: FOR NEXT #2 (ForNext2.asp) - Page 294 Ad Rotator (ad.asp) - Page 295 Content Rotator (cr.asp) - Page 296 DB: Command Object (command.asp) - Page 297 DB: Command Object/Queries (commandquery.asp) - Page 298 DB: Command Object/Create Tables (commandcreate.asp) - Page 299 Reporting: Simple Example (reportsimple.asp) - Page 300 Reporting: Powerful Example (reportpowerful.asp) - Page 301 Dictionaries: Different Approach #1 By Paul Rigor (dictionaryadvanced.asp) - Page 302 Dictionaries: Different Approach #2 by Paul Rigor (dictionaryadvanced2.asp) - Page 303 Validate data (validate.asp) - Page 304 3rd Party: WebJam (webjam.asp) - Page 305 Time Tasks: VB Component by Sunny Yu #1 (asptime.asp) - Page 306 Time Tasks: VB Component by Sunny Yu #2 (asptimer.asp) - Page 307