/learn Table of Contents
ASP Quick Lessons - Table of Contents (/learn/index.asp) - Page 1
Credits (/learn/credits.asp) - Page 2
Core Ideas (/learn/core.asp) - Page 3
What is ASP? Obtaining The Software (/learn/whatis.asp) - Page 4
AspInstall listserver (/learn/aspinstall.asp) - Page 5
Simple ASP Page, Server Scripting (/learn/whatisexample.asp) - Page 6
MS Online Documentation (/learn/docs.asp) - Page 7
Response: Basics (/learn/res.asp) - Page 8
Response: Buffers, Redirect (/learn/res2.asp) - Page 9
Response: Redirection (/learn/res3.asp) - Page 10
Response: Quotes & Special Characters (/learn/res4.asp) - Page 11
Response: Encoding URLs, HTML (/learn/res5.asp) - Page 12
Include: Basics (/learn/inc.asp) - Page 13
Include: Dynamic FileName (/learn/includedynamic.asp) - Page 14
Includes: Other Sites, Dynamic FileNames (/learn/includeasphttp.asp) - Page 15
Include/Redirects: New Win2k Commands (/learn/incwin2k.asp) - Page 16
Include: Books Sample Exercise (/learn/booksample.asp) - Page 17
More Book Sample Exercises (/learn/booksample2.asp) - Page 18
Format: Numbers #1 (/learn/formatnumbers.asp) - Page 19
Format: Numbers #2 (/learn/formatnumbers2.asp) - Page 20
Format: Dates #1 (/learn/formatdates.asp) - Page 21
Date/Time on ASP Pages by Tony Arguelles (/learn/datetime.asp) - Page 22
Loops: DO WHILE/UNTIL #1 (/learn/DoLoop.asp) - Page 23
Loops: Timeouts #2 (/learn/DoLoop2.asp) - Page 24
Loops: Intercepting Timeouts #3 (/learn/DoLoop3.asp) - Page 25
Server Variables: Popular Ones (/learn/server.asp) - Page 26
Server Variables: Domain/Host Name (/learn/server2.asp) - Page 27
Server Variables: Displaying All (/learn/serverall.asp) - Page 28
Random Content/Rotating Info (/learn/randomadvice.asp) - Page 29
Browscap: Basics (/learn/bc.asp) - Page 30
Browscap: Intricate Details (/learn/bcdetails.asp) - Page 31
Listserver for Browser Problems (/learn/aspbrowserheck.asp) - Page 32
State Management (/learn/statemanagement.asp) - Page 33
State Management Introduction (/learn/stateintro.asp) - Page 34
What are ASP Sessions? (/learn/sessionswhat.asp) - Page 35
Application Data (/learn/sessionsapps.asp) - Page 36
Application Data: Worlds Fastest ListBox (/learn/speedappdata.asp) - Page 37
XML, Database Caches - Fast Retrieval (/learn/xmlfastlist.asp) - Page 38
Say No To Databases w/Sessions or Application scope (/learn/nodbsession.asp) - Page 39
Session Overview & Myths (/learn/sessionoverview.asp) - Page 40
Sessions: Global.asa and Scalability (/learn/globalproblems.asp) - Page 41
Sessions: Global.asa Events (/learn/global.asp) - Page 42
Global.asa, Sessions, Custom Stats Resources (/learn/statemore.asp) - Page 43
State Methods: Pros and Cons (/learn/stateproscons.asp) - Page 44
Pass Data w/Hidden Fields (/learn/hidden.asp) - Page 45
Pass Data w/Cookies (/learn/cookies.asp) - Page 46
Pass Data w/Session Vars (/learn/statesessions.asp) - Page 47
Pass Data w/ID tied to database (/learn/statedb.asp) - Page 48
[aspStateManagement] Listserver (/learn/aspstatemanagement.asp) - Page 49
Forms/Decisions (/learn/Form.asp) - Page 50
Forms: Introduction (/learn/formintro.asp) - Page 51
Forms: Text Box (/learn/formtextbox.asp) - Page 52
Forms: Text Area (/learn/formtextarea.asp) - Page 53
Forms: Check Box (/learn/formcheckbox.asp) - Page 54
Forms: Radio Buttons (/learn/formradio.asp) - Page 55
Forms: List Box (/learn/formlistbox.asp) - Page 56
Forms: CASE syntax #1 (/learn/case.asp) - Page 57
Forms: CASE syntax #2 (/learn/case2.asp) - Page 58
Forms: IF syntax #1 (/learn/if.asp) - Page 59
Forms: IF syntax #2 (/learn/if2.asp) - Page 60
Forms: IF syntax #3 (/learn/if3.asp) - Page 61
Forms: IF syntax #4 (/learn/if4.asp) - Page 62
Forms: For Each Iteration (/learn/formforeach.asp) - Page 63
Form - Submit To Self' (/learn/formsubmitself.asp) - Page 64
Form - Change Action on Fly (/learn/formactionchange.asp) - Page 65
Databases (/learn/database.asp) - Page 66
Displaying Table w/Simple Code (/learn/dbsimple.asp) - Page 67
List Box Displayed Generically (/learn/dblist.asp) - Page 68
Database to ListBox Online Resources (/learn/dblistmore.asp) - Page 69
DSNLess Connections (/learn/dbopen.asp) - Page 70
DSN Setup #1 by Rob Martinson (/learn/dsn1.asp) - Page 71
DSN Setup #2 by Rob Martinson (/learn/dsn2.asp) - Page 72
DSN Setup #3 by Rob Martinson (/learn/dsn3.asp) - Page 73
DSN Setup #4 by Rob Martinson (/learn/dsn4.asp) - Page 74
DSN Setup #5 by Rob Martinson (/learn/dsn5.asp) - Page 75
DSN Setup #6 by Rob Martinson (/learn/dsn6.asp) - Page 76
Full Cycle #1 Show/Edit/Update (/learn/dbfull1.asp) - Page 77
Full Cycle #2 Show/Edit/Update (/learn/dbfull2.asp) - Page 78
Full Cycle #3 Show/Edit/Update (/learn/dbfull3.asp) - Page 79
SQL Mistakes Everyone Makes (/learn/dbtroubleshoot2.asp) - Page 80
DB: Table Displayed Generically (/learn/dbtable.asp) - Page 81
Getstring to display database table (/learn/dbtablegetstring.asp) - Page 82
Getrows to display database table (/learn/dbtablegetrows.asp) - Page 83
GetRows w/no Numbers (/learn/dbtablegetrowsnonum.asp) - Page 84
Disconnected Recordsets, Display Table (/learn/dbtabledisconnected.asp) - Page 85
DB: More ways To Display Tables (/learn/dbtablemore.asp) - Page 86
DB: Generic DB by Eli Robillard (/learn/genericdb.asp) - Page 87
Generic DB Listserver (/learn/aspgenericdb.asp) - Page 88
DB: Converting a DB to a Comma-Delimited file (/learn/dbconvert.asp) - Page 89
DB: Deleting a Record w/SQL (/learn/dbSQLdelete.asp) - Page 90
DB: Access Scalability (/learn/accesstest.asp) - Page 91
ADO: Paging Records (/learn/dbtablepaged.asp) - Page 92
ADO: Limiting Number of Records (/learn/dbmaxrecs.asp) - Page 93
ADO: Count Records in Query (/learn/dbcount.asp) - Page 94
ADO: Cursor Types by Phil Paxton (/learn/adocursortypes.asp) - Page 95
ADO: Input Form (/learn/dbnewrec.asp) - Page 96
ADO: Input Form, added w/SQL (/learn/dbnewSQL.asp) - Page 97
ADO: Input Form, Added w/ADO .addnew (/learn/dbnewADO.asp) - Page 98
ADO: Tables within Databases (/learn/dbtablelists.asp) - Page 99
ADO: Schemas to access table lists (/learn/dbschemas.asp) - Page 100
ADO: Schemas to access All Data (/learn/dbschemasall.asp) - Page 101
ADO: Show Table,1 param (/learn/db1parm.asp) - Page 102
ADO: Update/edit Record (/learn/dbupdate.asp) - Page 103
DB: Troubleshooting Part 1 (/learn/dbtroubles.asp) - Page 104
DB: Troubleshooting Part 2 (/learn/dbtroubles2.asp) - Page 105
SQL Basics, Searching Databases (/learn/SQL.asp) - Page 106
SQL Troubles (/learn/SQLtroubles.asp) - Page 107
SQL: Example Tables (/learn/SQLexamples.asp) - Page 108
SQL: Where Clause Basics (/learn/SQLwhere.asp) - Page 109
SQL: Where Clause Examples (/learn/SQLwhere2.asp) - Page 110
SQL: Search Forms #1 (/learn/SQLwhereform1.asp) - Page 111
SQL: Search Forms #2 (/learn/SQLwhereform2.asp) - Page 112
SQL: Search Forms #3 (/learn/SQLwhereform3.asp) - Page 113
SQL: Search AND/OR Operators (/learn/SQLandor.asp) - Page 114
SQL: Search AND/OR Examples (/learn/SQLandor2.asp) - Page 115
SQL: COUNT, GROUPBY (/learn/SQLcount.asp) - Page 116
SQL: SUM, MIN, AVE, MAX (/learn/SQLaggregate.asp) - Page 117
SQL Joins by Aaron Alexander (/learn/dbjoin.asp) - Page 118
RSFAST: Lightning Fast Database Library (/learn/rsfast.asp) - Page 119
RSFast Library Introduction (/learn/rsfast-intro.asp) - Page 120
Table Display Fast (/learn/rsfast-table.asp) - Page 121
Table Display Fast + Caching (/learn/rsfast-table-cached.asp) - Page 122
Listbox Display Fast (/learn/rsfast-lists.asp) - Page 123
Listbox Display Fast + Caching (/learn/rsfast-lists-cached.asp) - Page 124
Templates for any look Fast (/learn/rsfast-templates.asp) - Page 125
Debug Info helps troubleshoot (/learn/rsfast-lists-debug.asp) - Page 126
Library Source Code (/learn/rsfast-lib.asp) - Page 127
caching Method Explained (/learn/rsfast-cache.asp) - Page 128
New Features for Future Versions (/learn/rsfast-newfeatures.asp) - Page 129
Editors Used With ASP (/learn/editors.asp) - Page 130
ASPExpress: HOT ASP Editor (/learn/aspexpress.asp) - Page 131
Visual Interdev + Admunsen Resources (/learn/admunsen.asp) - Page 132
Visual Interdev Listserver (/learn/aspvisualinterdev.asp) - Page 133
Homesite: HTML editor (/learn/homesite.asp) - Page 134
DreamWeaver: HTML and Script Editor (/learn/dreamweaver.asp) - Page 135
Essential Commercial Components (/learn/components.asp) - Page 136
ASPDB: Displaying Data (/learn/aspdb1.asp) - Page 137
ASPDB: Editing, Adding Data (/learn/aspdb2.asp) - Page 138
BrowserHawk: Determing Browser Type (/learn/bhbrowtype.asp) - Page 139
AOL detection w/BrowserHawk (/learn/bhaol.asp) - Page 140
MS-Wallet w/BrowserHawk (/learn/bhwallet.asp) - Page 141
Reverse DNS lookups w/BrowserHawk (/learn/bhresolveip.asp) - Page 142
BrowserHawk - Frame support (/learn/bhframes.asp) - Page 143
Flash Detection w/BrowserHawk (/learn/bhflash.asp) - Page 144
ServerObject Mail: Simple Example (/learn/serverobjectsmail.asp) - Page 145
ServerObject: Mailing Form w/ASPMail (/learn/formsendmail.asp) - Page 146
3rd Party Mail, CDO/CDONTS Listserver (/learn/aspmail.asp) - Page 147
SA: File Upload, Simple Example (/learn/uploadsimple.asp) - Page 148
SA: File Upload, Multi-part form (/learn/uploadmultipart.asp) - Page 149
SA: File Upload, Limit Size (/learn/uploadlimitsize.asp) - Page 150
SA: File Upload, Many Files (/learn/uploadmanyfiles.asp) - Page 151
Upload/Soft-Artisans Listserver (/learn/aspsoftartisans.asp) - Page 152
Perf Counters on ASP page (/learn/perfcounters.asp) - Page 153
Authentication & Security (/learn/authenticate.asp) - Page 154
Authenticate: Overview by Kevin Flick (/learn/authenticateoverview.asp) - Page 155
Authenticate: Comparison by Kevin Flick (/learn/authenticatecomparisons.asp) - Page 156
Authenticate: NT Challenge/Response by Kevin Flick (/learn/authenticatentcr.asp) - Page 157
Authenticate: Basic Authentication by Kevin Flick (/learn/authenticatebasic.asp) - Page 158
Authenticate: Cookies by Kevin Flick (/learn/authenticatecookies.asp) - Page 159
Authenticate: Certificates by Kevin Flick (/learn/authenticatecertificate.asp) - Page 160
Authenticate: Build Your Own by Kevin Flick (/learn/authenticatebuild.asp) - Page 161
Authenticate: Protect Pages via Login #1 (/learn/security.asp) - Page 162
Authenticate: Protect Pages via Login #2 (/learn/security2.asp) - Page 163
Authenticate: 3rd Party by Kevin Flick (/learn/authenticate3rdparty.asp) - Page 164
Authentix Flicks Support Listserver (/learn/aspflicks.asp) - Page 165
Troubleshooting, Error Trapping (/learn/troubles.asp) - Page 166
Errors: Basics (/learn/errors1.asp) - Page 167
Errors: More Ways To Trap (/learn/errors2.asp) - Page 168
Errors: Resources Online (/learn/errormore.asp) - Page 169
Errors: Trapping EVERY Error (/learn/dbtablewitherrortrap.asp) - Page 170
Debug variables Easy Way (/learn/debug1.asp) - Page 171
Errors: DB Error Information Trapping (/learn/dbtroubleshoot.asp) - Page 172
DBFAQ: Operation must use Updatable Query (/learn/FAQdbUpdate.asp) - Page 173
DBFAQ: User Entered ' in field (/learn/FAQdbSinglequote.asp) - Page 174
DBFAQ: LIKE operator * not working (/learn/FAQdbLIKE.asp) - Page 175
DBFAQ: retrieving MEMO/BLOBs generates error (/learn/FAQdbMEMO.asp) - Page 176
DBFAQ: Syntax Error in SQL Statement (/learn/FAQdbSQLSyntax.asp) - Page 177
SQL Debugging Made Easy (/learn/debug2.asp) - Page 178
Errors: Trapping Open Connections (/learn/dbtroubleshootopen.asp) - Page 179
Troubleshoot: Getting Help from Lists! (/learn/asptroubles.asp) - Page 180
Troubleshoot: Worldwide (/learn/asptroubles2.asp) - Page 181
Troubleshoot: Specialized (/learn/asptroubles3.asp) - Page 182
Troubleshoot: Version of ASP Sofware (/learn/versioncheck.asp) - Page 183
Troubleshoot: Registered Components (/learn/componentchecker.asp) - Page 184
Troubleshoot: DB Drivers by Christophe Wille (/learn/connectioninfo.asp) - Page 185
PWS: Personal Web Server Introduction (/learn/PWS.asp) - Page 186
Code w/all ASP Features. Quality, Re-usable Code (/learn/qualitycode.asp) - Page 187
Strings: Core Functions (/learn/strings.asp) - Page 188
Strings: SPLIT Function (/learn/stringsplit.asp) - Page 189
Strings: REPLACE Function (/learn/stringreplace.asp) - Page 190
Strings: JOIN Function (/learn/stringjoin.asp) - Page 191
Arrays: Basics (/learn/arrays.asp) - Page 192
Arrays: Variable Size (/learn/arrays2.asp) - Page 193
Arrays: Best Way To Load (/learn/arrays3.asp) - Page 194
Arrays: Resources Online (/learn/arraysmore.asp) - Page 195
Dictionary Objects (/learn/dictionary.asp) - Page 196
Getrows Ultimate! (/learn/getrowsultimate.asp) - Page 197
Subroutine: Working with Dates #1 (/learn/subdates.asp) - Page 198
Subroutine: Working with Dates #2 (/learn/subdates2.asp) - Page 199
Subroutine: Query2Table (/learn/subdbtable.asp) - Page 200
Subroutine: Query2List (/learn/subdblist.asp) - Page 201
Subroutine: Highly Reusable (/learn/subreusable.asp) - Page 202
Subroutines w/Dictionary Objects (/learn/subdictionary.asp) - Page 203
Getrows Ultimate! (/learn/getrowsultimate.asp) - Page 204
Subroutine: List Box w/optional params (/learn/subDBlistbest.asp) - Page 205
Subroutine: Abstract HTML by Phil Paxton (/learn/libhtml.asp) - Page 206
Function: Working Days (/learn/functionworkingdays.asp) - Page 207
New Features in VBScript version5 (/learn/vbs5.asp) - Page 208
Text Files: Reading Them off Server (/learn/txtread.asp) - Page 209
Text Files: Writing Them on Server (/learn/txtwrite.asp) - Page 210
Text Files: Meyers-Briggs parsing #1 (/learn/mb1.asp) - Page 211
Text Files: Meyers-Briggs parsing #2 (/learn/mb2.asp) - Page 212
Text Files: Meyers-Briggs parsing #3 (/learn/mb3.asp) - Page 213
XML/XLST Myers-Briggs example (/learn/xmlmb.asp) - Page 214
Content Linker: Prev/Next Page (/learn/cl.asp) - Page 215
Content Linker: Table of Contents (/learn/cl2.asp) - Page 216
Content Linker: Listbox of contents (/learn/cl3.asp) - Page 217
Content Linker Library (/learn/contentlinker.asp) - Page 218
File Objects: Read Directory (/learn/fileobjects.asp) - Page 219
File Objects: Display Directory as Links/Graphics (/learn/fileobjects2.asp) - Page 220
File Objects: Read Disk Drive by Steven Harper (/learn/fileobjects3.asp) - Page 221
File Objects: Show Dir List by Tim Foster (/learn/fileobjects4.asp) - Page 222
Graphic Size Detector (/learn/graphicdetect.asp) - Page 223
High Speed Code, Scalable Code... (/learn/speedscale.asp) - Page 224
Time Tasks with Millisecond Accuracy (/learn/speedtimer.asp) - Page 225
Speed: Coding Tips (/learn/speedtips.asp) - Page 226
Why Buffer? (/learn/whybuffer.asp) - Page 227
Why GetRows or Getstring to get Data (/learn/whygetrows.asp) - Page 228
Speed: Server Optimization (/learn/speedserver.asp) - Page 229
Speed/Optimize Resources (/learn/speedmore.asp) - Page 230
Speed: [aspfastcode] listserver (/learn/speedresearch.asp) - Page 231
Speed: Database Percieved Speed (/learn/speedtables.asp) - Page 232
Database Retrieval Speed (/learn/speedtablesall.asp) - Page 233
OLEDB & ODBC Drivers differences (/learn/speedtablesdrivers.asp) - Page 234
IsClientConnected & Stray Tasks (/learn/isclientconnected.asp) - Page 235
Scale: Virtues of Nothing (/learn/nothing.asp) - Page 236
Scale: Connection Pooling (/learn/dbpooling.asp) - Page 237
Thread Basics: What is a Thread? (/learn/threads.asp) - Page 238
Thread Safety Issues (/learn/threadsafe.asp) - Page 239
Round-Robin Code Execution (/learn/roundrobin.asp) - Page 240
ASP Scalability Listserver (/learn/aspscalability.asp) - Page 241
ASP Components Building (/learn/buildcomponents.asp) - Page 242
C++/ATL: Component Building (/learn/buildc.asp) - Page 243
Java ASP Components Building (/learn/buildjava.asp) - Page 244
VB: Simple Component (/learn/buildvbsimple.asp) - Page 245
VB: Registering Component (/learn/buildregister.asp) - Page 246
VB: DLL overwrite problems (/learn/FAQvbDLLoverwrite.asp) - Page 247
VB: ADO, Run It! (/learn/buildvbado.asp) - Page 248
VB: ADO, Build It! (/learn/buildvbado2.asp) - Page 249
VB: Warnings/Guidelines (/learn/buildvbguidelines.asp) - Page 250
VB: General Building Guidelines (/learn/buildvb.asp) - Page 251
VB: Installation Requirements (/learn/buildvb2.asp) - Page 252
VB: Threading Models (/learn/buildvbthreads.asp) - Page 253
MTS - Microsoft Transaction Server (/learn/buildmtx.asp) - Page 254
MTS: Overview (/learn/buildmtxoverview.asp) - Page 255
MTS: Essentials (/learn/buildmtx2.asp) - Page 256
MTS: Transactional ASP pages (/learn/buildmtxasp.asp) - Page 257
MTS: Book (/learn/booksmtx.asp) - Page 258
MTS: Book (/learn/booksmtx2.asp) - Page 259
MTS: Registering Components (/learn/buildmtxregister.asp) - Page 260
Advice For Better Coding! (/learn/advice.asp) - Page 261
Database in Session or App. Say NO! (/learn/dbsessionapp.asp) - Page 262
advice: Cache No More by Phil Paxton (/learn/cachenomore.asp) - Page 263
advice:Option Explicit (/learn/explicit.asp) - Page 264
advice: Encode with Redirects (/learn/encode.asp) - Page 265
advice: Write Your SQL (/learn/sqlwrite.asp) - Page 266
advice: Named constants for ADO are better (/learn/namedconstants.asp) - Page 267
advice: Clean Up Your Room, I mean Objects (/learn/cleanup.asp) - Page 268
advice: Server.MapPath is Good (/learn/pathmap.asp) - Page 269
advice: Just Say No to Session COM objects (/learn/nosessionobjects.asp) - Page 270
advice: Don't Read COM Properties Twice (/learn/propertyexpense.asp) - Page 271
advice: Secure Code and Data (/learn/securecode.asp) - Page 272
advice: Encaspulate Code! (/learn/encapsulate.asp) - Page 273
advice: CASE reads better than IF (/learn/caseisbetter.asp) - Page 274
advice: Error Trapping Strategies (/learn/errorstrategies.asp) - Page 275
advice: Error Trapping Secrets (/learn/errorsecrets.asp) - Page 276
advice: You Should... (/learn/shoulds.asp) - Page 277
Appendix A: Overview of ASP Objects (/learn/overview.asp) - Page 278
ASP Objects: Built In (/learn/aspobjects.asp) - Page 279
ASP Objects: Created when Needed (/learn/aspobjects2.asp) - Page 280
Appendix B: Related Web/Com Technologies (/learn/webcom.asp) - Page 281
Index Server via ADO (/learn/indexserver.asp) - Page 282
Commerce and ASP (/learn/commerce.asp) - Page 283
Server JavaScript: Resources (/learn/javascript.asp) - Page 284
Validation Resources (/learn/validationmore.asp) - Page 285
Listboxes: Linked Dynamically w/JavaScript (/learn/listdynamic.asp) - Page 286
Dynamic ListBox Online Examples (/learn/listdynamicmore.asp) - Page 287
Listboxes: Linked Dynamically from Database w/JavaScript (/learn/listdynamicdb.asp) - Page 288
Listboxes: Easy Choices by Bill Wilkinson (/learn/listdual.asp) - Page 289
Server Perlscript: Resources (/learn/perlscript.asp) - Page 290
Remote Scripting Simple Example (/learn/remotescripting.asp) - Page 291
Remote Scripting Listbox (/learn/remotescriptinglist.asp) - Page 292
Remote Scripting Microsoft Example (/learn/remotescriptingms.asp) - Page 293
[aspRemoteScript] list (/learn/aspremotescripting.asp) - Page 294
RDS: Remote Data Services Intro (/learn/rds.asp) - Page 295
RDS Resources by Carl Prothman (/learn/prothman.asp) - Page 296
ADSI: Active Directory Services Interface Intro (/learn/ADSI.asp) - Page 297
MSMQ: Overview (/learn/MSMQ.asp) - Page 298
Usability: Resources (/learn/usability.asp) - Page 299
Usability: Safe Color Pallete (/learn/safecolors.asp) - Page 300
Appendix C: Oracle and ASP (/learn/oracle.asp) - Page 301
Oracle: I can't connect (/learn/FAQOracleconnect.asp) - Page 302
Oracle: Getting Help from Listserver (/learn/asporacle.asp) - Page 303
Oracle: Calling Stored Procs (/learn/FAQOraclestoredproc.asp) - Page 304
Oracle: OLEDB Resource(Session) Pooling (/learn/oracleoledbpooling.asp) - Page 305
Oracle: Recordsets from Stored Procedures using REF CURSORs (/learn/oraclerecordsetsfromsp.asp) - Page 306
Oracle: Returning Recordsets via ADO (/learn/oraclerecordsetsado.asp) - Page 307
Oracle: Know any good books? (/learn/FAQOraclebooks.asp) - Page 308
Appendix D: ASP Books & Online Resources (/learn/research.asp) - Page 309
Must Buy Component Building Book (/learn/bookcomponents.asp) - Page 310
ASP101.com Scripts for your site (/learn/asp101.asp) - Page 311
4GuysFromRolla.com Tons of ASP Material (/learn/4guysfromrolla.asp) - Page 312
ASPToday.com from WROX (/learn/asptoday.asp) - Page 313
Appendix E: Frequently Asked Questions (/learn/faqs.asp) - Page 314
Commerce: certificates, https:// (/learn/FAQCommerceCertif.asp) - Page 315
Commerce: online charging (/learn/FAQCommerceCharge.asp) - Page 316
Commerce: components, shopping carts (/learn/FAQCommerceCarts.asp) - Page 317
Jscript: closing DB Connections (/learn/FAQJscriptCleanUp.asp) - Page 318
Jscript: online references (/learn/FAQJscriptRefs.asp) - Page 319
Jscript: display databases (/learn/FAQJscriptDB.asp) - Page 320
VB: Recommended books (/learn/FAQvbBooks.asp) - Page 321
Alphabetical Index (/learn/alphaindex.asp) - Page 322
Coming Soon/Very Rough Drafts! (/learn/comingsoon.asp) - Page 323
Data Types: VBScript (/learn/types.asp) - Page 324
Data Types: Conversion (/learn/convert.asp) - Page 325
Loops: FOR NEXT #1 (/learn/ForNext.asp) - Page 326
Loops: FOR NEXT #2 (/learn/ForNext2.asp) - Page 327
Ad Rotator (/learn/ad.asp) - Page 328
Content Rotator (/learn/cr.asp) - Page 329
DB: Command Object (/learn/command.asp) - Page 330
DB: Command Object/Queries (/learn/commandquery.asp) - Page 331
DB: Command Object/Create Tables (/learn/commandcreate.asp) - Page 332
Reporting: Simple Example (/learn/reportsimple.asp) - Page 333
Reporting: Powerful Example (/learn/reportpowerful.asp) - Page 334
Dictionaries: Different Approach #1 By Paul Rigor (/learn/dictionaryadvanced.asp) - Page 335
Dictionaries: Different Approach #2 by Paul Rigor (/learn/dictionaryadvanced2.asp) - Page 336
Validate data (/learn/validate.asp) - Page 337
3rd Party: WebJam (/learn/webjam.asp) - Page 338
Time Tasks: VB Component by Sunny Yu #1 (/learn/asptime.asp) - Page 339
Time Tasks: VB Component by Sunny Yu #2 (/learn/asptimer.asp) - Page 340
Cookies: Reading Them (/learn/cookiesform.asp) - Page 341
Cookies: Writing Them (/learn/cookiesformrespond.asp) - Page 342
Cookies: Deleting Them (/learn/cookiesforget.asp) - Page 343
Cookies: Simplified by Paul Rigor (/learn/cookiesub.asp) - Page 344
All material is ©1998-2000 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/Site Programming:
Business
Manager: Inspiration, Assistance,
Motivation: |
![]() |
Additional
Writers/Contributors:
Aaron
Alexander, Kevin Flick, Steve Genusa, Steven Harper, John Kauffman. Andrew Laken,
Juan Llibre, Rob Martinson, Phil Paxton, George Reilly, Paul Rigor,
Christophe Wille, David Wihl, and Sunny Yu.
thanks for feedback,
support:
Joao
Oliveira contato123@zipmail.com.br
Scott Mitchell www.4guysfromrolla.com
ASP Quick Lessons is a on-line
book published @
http://www.learnasp.com
Core Ideas
What is ASP? Obtaining The Software (whatis.asp) - Page 4
AspInstall listserver (aspinstall.asp) - Page 5
Simple ASP Page, Server Scripting (whatisexample.asp) - Page 6
MS Online Documentation (docs.asp) - Page 7
Response: Basics (res.asp) - Page 8
Response: Buffers, Redirect (res2.asp) - Page 9
Response: Redirection (res3.asp) - Page 10
Response: Quotes & Special Characters (res4.asp) - Page 11
Response: Encoding URLs, HTML (res5.asp) - Page 12
Include: Basics (inc.asp) - Page 13
Include: Dynamic FileName (includedynamic.asp) - Page 14
Includes: Other Sites, Dynamic FileNames (includeasphttp.asp) - Page 15
Include/Redirects: New Win2k Commands (incwin2k.asp) - Page 16
Include: Books Sample Exercise (booksample.asp) - Page 17
More Book Sample Exercises (booksample2.asp) - Page 18
Format: Numbers #1 (formatnumbers.asp) - Page 19
Format: Numbers #2 (formatnumbers2.asp) - Page 20
Format: Dates #1 (formatdates.asp) - Page 21
Date/Time on ASP Pages by Tony Arguelles (datetime.asp) - Page 22
Loops: DO WHILE/UNTIL #1 (DoLoop.asp) - Page 23
Loops: Timeouts #2 (DoLoop2.asp) - Page 24
Loops: Intercepting Timeouts #3 (DoLoop3.asp) - Page 25
Server Variables: Popular Ones (server.asp) - Page 26
Server Variables: Domain/Host Name (server2.asp) - Page 27
Server Variables: Displaying All (serverall.asp) - Page 28
Random Content/Rotating Info (randomadvice.asp) - Page 29
Browscap: Basics (bc.asp) - Page 30
Browscap: Intricate Details (bcdetails.asp) - Page 31
Listserver for Browser Problems (aspbrowserheck.asp) - Page 32
(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:
Tip: Trouble/Errors installing PWS? Here is the answer(s):
http://www.acceleratedcomputers.com/pws4.htm
has the answer to several annoying error messages!http://rwebs.net/webdesign/pwsmore.htm
also has some excellent info about how and whether to install PWS.
Tip: Trouble/Errors installing IIS5?
When IIS5 does not start:
http://www.iisfaq.com/Articles/134/
More ASP facts:
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!
Related Links:
Excellent info about how and whether to install PWS @
http://rwebs.net/webdesign/pwsmore.htm
The answer to several annoying error messages @
http://www.acceleratedcomputers.com/pws4.htm
PWS NT Otion Pack4 WILL Install on Win9x @
http://www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/default.asp
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
Now let us go over the essential mechanisms that are ASP:
| <html><head> <TITLE>hi.asp</TITLE> </head> <body bgcolor="#FFFFFF"> Today is <%=now%> and all is well<br> <%if hour(now())>12 THEN%> Good Evening <%ELSE%> Good Morning! <%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> |
Before 12pm
the user at the browser receives
<<<<<<< |
|
|
|
| <html><head> <TITLE>hi.asp</TITLE> </head> <body bgcolor="#FFFFFF"> Today is Tue 02:00pm and all is well<br> Good Day! </body></html> |
After 12pm
the user at the browser receives
<<<<<<< |
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 | |
| NT4 Option Pak | /iishelp |
| ASP objects reference | /iishelp/iis/htm/asp/intr1orp.htm |
| Ex Air | /IISSamples/ExAir/default.asp |
| Installable Components for ASP | /iishelp/iis/htm/asp/comp275c.htm |
| JScript Language Reference | /iishelp/JScript/htm/JStoc.htm |
| VBScript Language Reference | /iishelp/VBScript/htm/VBStoc.htm |
| Server Side Include Reference | /iishelp/iis/htm/asp/iissiref.htm |
| ASP Quick reference card | /iishelp/iis/htm/asp/iiwaref.htm |
| ASP Tutorial* | click here |
| IIS3 Docs | |
| Roadmap / Official IIS3 Docs | /iasdocs/aspdocs/roadmap.asp |
| IIS3 Code Samples | /aspsamp/samples/samples.htm |
| AdventureWorks | /AdvWorks/default.asp |
* ASP Tutorial resides at this ridiculously
long URL:
/iishelp/iis/htm/asp/iiselect.asp?LessonFile=%2Fiishelp%2Fiis%2Fhtm%2Fasp%2Fiiatmd1%
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:
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 <html><head>Here is a script utilizing response.end to prematurely end a page:
1 <html><head>
Response Object Part2 - Buffer Explanation
Does this error message plague you?The Simple Fix....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.
One 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. If a page
takes 20 seconds to render, the browser user sees nothing until the 20th second!
In that situation to avoid appearing as the page is dead, a well-placed
<%response.flush%> tell server to send HEADER + whatever
text so far so lets readers see the portions of the page being built. Increasing
percieved speed of database displays is explained at http://www.learnasp.com/learn/speedtables.asp
by judicous use of flushing buffer.
NT4 and Win 2000 differences
NT4 <%buffer=false%> by default which hurts overall server speed (http://www.learnasp.com/advice/whybuffer.asp). Win 2000 <%buffer=true%> by default. A clever administrator can change NT4 registry so buffer=true for all scripts and will see major server performance improvements (see http://www.learnasp.com/learn/speedserver.asp for other ones).
Here is a non-working page that will display the error:
1 <%response.buffer=false%>
2 <html><head>
3 <title>dailystuff.asp</title>
4 </head>
5 <body>
6 <%
7 whatweekday=Weekday(now())
8 select case whatweekday
9 case vbSunday
10 response.redirect "http://www.cnn.com"
11 case vbMonday
12 response.redirect "http://www.activeserverpages.com"
13 case vbTuesday
14 response.redirect "http://www.aspalliance.com"
15 case vbWednesday
16 response.redirect "http://www.aspconvention.com"
17 case vbThursday
18 response.redirect "http://www.aspmagazine.com"
19 case vbFriday
20 response.redirect "http://www.dilbert.com"
21 case vbSaturday
22 response.redirect "http://www.movielink.com"
23 end select
24 %>
25 </body>
26 </html>
Here is the fixed page that will NOT display the error:
1 <%response.buffer=true%>
2 <html><head>
3 <title>dailystuff.asp</title>
4 </head>
5 <body>
6 <%
7 whatweekday=Weekday(now())
8 select case whatweekday
9 case vbSunday
10 response.redirect "http://www.cnn.com"
11 case vbMonday
12 response.redirect "http://www.activeserverpages.com"
13 case vbTuesday
14 response.redirect "http://www.aspalliance.com"
15 case vbWednesday
16 response.redirect "http://www.aspconvention.com"
17 case vbThursday
18 response.redirect "http://www.aspmagazine.com"
19 case vbFriday
20 response.redirect "http://www.dilbert.com"
21 case vbSaturday
22 response.redirect "http://www.movielink.com"
23 end select
24 %>
25 </body>
26 </html>
Why? (The Tough Answer with Gory Details)
...first of all thanks to Ken Schaefer of Adopenstatic.com for pointing out huge flaws and misleading information in this page as it was written before 1/10/2001. Its revision on 1/10 was prompted by Ken. He wrote an article on this too at http://www.adopenstatic.com/faq/headererror.asp...
That line will do away
with all "headers are already sent" messages. It essentially tells the
server don't write
anything at all to browser 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 (provided no content or text has been
sent with response.flush)
An ASP page must be sent to browser in a specific strict order: first the header, and then the content. The header could contain cookies (see http://www.learnasp.com/learn/cookies.asp), redirects, other headers inserted by the response.addheader command and other header information. If your page mixes content (any text) and mixes in header info this is not following the strict rules. If the browser writes any data that is page content, and then headers cannot be sent -- it is "too late" -- it can't change "horses in midstream" -- that is header info cannot come inside or after data. Buffering does not send the page content and headers in exact order they appear in script. Even if headers and content is mixed the header and content are sent in correct order when buffer is flushed (either by explicit response.flush or script completes).
Response Object - Redirects
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 <html><head>
2 <TITLE>FormJump.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="FormJumpRespond.asp" method="get">
5 <SELECT NAME="wheretogo">
6 <OPTION SELECTED VALUE="fun">Fun</OPTION>
7 <OPTION value="news">Daily News</OPTION>
8 <OPTION value="docs">ASP IIS3 Roadmap/Docs</OPTION>
9 <OPTION value="main">MainPage of ActiveServerPages.com</OPTION>
10 <OPTION value="sample">IIS 3 Sample ASP scripts</OPTION>
11 </SELECT>
12 <input type=submit value="Choose Destination">
13 </form>
14 </body></html>
The responder that reacts to this form is:
1 <%response.buffer=true%>
2 <html><head>
3 <title>formjumprespond.asp</title>&
4 <body bgcolor="#FFFFFF">
5 <%
6 ' My ASP program that redirects to URL
7 thisURL="http://www.activeserverpages.com"
8 where=Request.QueryString("Wheretogo")
9 Select Case where
10 case "main"
11 response.redirect thisURL & "/"
12 case "samples"
13 response.redirect thisURL & "/aspsamp/samples/samples.htm"
14 case "docs"
15 response.redirect thisURL & "/iasdocs/aspdocs/roadmap.asp"
16 case "news"
17 response.redirect "http://www.cnn.com"
18 case "fun"
19 response.redirect "http://www.dilbert.com"
20 End Select
21 response.write "All dressed up and I don't know where to go<br>"
22 response.write "I recommend --> " & "<br>"
23 response.write server.htmlencode(thisURL & "/learn/test/res2.asp?where=fun") & "<br>"
24 response.write "for a good laugh!" & "<P>"
25 %>
26 </body></html>
Response Object and Quotes
The response object is often used with a variety of syntax variations which we will detail here.
1 <html><head>
2 <title>res4.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 ' The response object can be used to write text a variety of ways
6 ' 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>
Response Object and HTML Encoding
The response object is often used in conjunction with various kinds of coding 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 <html><head>
2 <title>res5.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 ' The response object can be used to write text
6 ' but sometimes some functions must be used to transform
7 ' the text instead of sending as is to the browser
8
9 response.write "<B>Hyperion</b> by <I>Dan Simmons</i> is a great novel"
10 response.write "<p>"
11 response.write server.htmlencode("<B>Hyperion</b> by <I>Dan Simmons</i> is a great novel")
12 response.write "<p>"
13
14
15 response.write "Joe Smith & Hilda = a team"
16 response.write "<p>"
17 response.write server.URLencode("Joe Smith & Hilda = a team")
18 %>
19
20 </body></html>
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.
Includes Files Dynamically
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"-->
We however have coded a workaround that is FREE you may find useful. The workaround is:
1 <html><head>
2 <TITLE>includedynamic.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 whichfile="bookscifi.asp"
6 Call ReadDisplayFile(whichfile)
7 response.write "<hr>"
8
9 whichfile="bookhorror.asp"
10 Call ReadDisplayFile(whichfile)
11 response.write "<hr>"
12
13
14 whichfile="/learn/test/bookmarketing.asp"
15 Call ReadDisplayFile(whichfile)
16 response.write "<hr>"
17 %>
18
19 </body></html>
20 <%
21 SUB ReadDisplayFile(FileToRead)
22 whichfile=server.mappath(FileToRead)
23 Set fs = CreateObject("Scripting.FileSystemObject")
24 Set thisfile = fs.OpenTextFile(whichfile, 1, False)
25 tempSTR=thisfile.readall
26 response.write tempSTR
27 thisfile.Close
28 set thisfile=nothing
29 set fs=nothing
30 END SUB
31 %>
The only downside to this method is no ASP Code ( i.e.
anything in <% %> ) will be parsed or executed in the included file. If
you must execute ASP code the Win2k server.execute @
/learn/incwin2k.asp
or the 3rd party components like ASPHTTP must be employed @
/learn/include/asphttp.asp
Includes - Other Sites/Dynamic FileNames
3rd party components like ASPHTTP can grab the HTML contents of a specific URL into an ASP string. Supports GET/POST/HEAD documents via the HTTP protocol, examining response headers, transfering requests to a file (including binary transfers) and password authentication support. They can also be used on YOUR OWN SITE to make dynamic includes possible.
available at http://www.serverobjects.com/products.htm
Microsoft includes WinInet which seems to be
ideally suited for this EXCEPT is currently not thread safe, see:
http://www.learnasp.com/advice/threadsafe.asp
so Tools like ASPHTTP are a necessity.
Here is a sample where ASPHTTP is used to grab contents from another site.
1 <html><head>
2 <title>asphttpother.asp</title>
3 </head>
4 <body>
5 <%
6 Set HttpObj = Server.CreateObject("AspHTTP.Conn")
7
8 HttpObj.Url = "http://www.funinspace.com"
9 strResult = HttpObj.GetURL
10
11 STRresult=server.htmlencode(STRresult)
12 response.write STRresult
13
14 SET HTTPobj = nothing
15 %>
16 </body>
17 </html>
18
19
Here is a sample where ASPHTTP is used to allow a string to decide which page on our site is executed.
1 <html><head>Include/redirect Goodies from Win2000
Win 2000 introduces two new ways to deal with redirects and includes:
server.transfer
which unlike redirect, does not interact with the browser. The server switches
to a different page/site without any browser interaction or headers.
server.execute
which can take a dynamically generated string and execute the code in the asp
script named by the string.
Book Sample by Charles Carroll
The Recommend Book Sample Files provides you with several files that when created, prepare you for applying several powerful content management tools and session examples in the following pages. The features detailed will include:
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 <html><head>
2 <title>bookfuture.asp</title>&
3 <!--#include file="bookheader.asp"-->
4 <body>
5 <h1>Future Books</h1>
6 <ul>
7 <li><b><i>Visions</b></i><br>Michio Kaku</li>
8 <li><b><i>Future Magic</b></i><br>Robert Forward</li>
9 </ul>
10 <!--#include file="bookfooter.asp"-->
11 </body></html>
Here is the code for bookhorror.asp:
1 <html><head>
2 <title>bookhorror.asp</title>&
3 <!--#include file="bookheader.asp"-->
4 <body>
5 <h1>Horror Books</h1>
6 <ul>
7 <li><b><i>Carrion Comfort</b></i><br>Dan Simmons</li>
8 <li><b><i>The Stand</b></i><br>Steven King</li>
9 <li><b><i>Children of Darkness</b></i><br>Dan Simmons</li>
10 <li><b><i>Thinner</b></i><br>Steven King</li>
11 <li><b>Fires of Eden<i></b></i><br>Dan Simmons</li>
12 </ul>
13 <!--#include file="bookfooter.asp"-->
14 </body></html>
Here is the code for bookmarketing.asp:
1 <html><head>
2 <title>bookMarketing.asp</title>&
3 <!--#include file="bookheader.asp"-->
4 <body>
5 <h1>Marketing Books</h1>
6 <ul>
7 <li><b><i>22 Immutable Laws of Branding</b></i><br>Reiss and Reiss</li>
8 <li><b><i>22 Immutable Laws of Marketing</b></i><br>Reiss and Trout</li>
9 <li><b><i>Marketing Warfare</b></i><br>Reiss and Trout</li>
10 <li><b><i>Horse Sense</b></i><br>Reiss and Trout</li>
11 <li><b><i>Words That Sell</b></i><br>by ??</li>
12 </ul>
13 <!--#include file="bookfooter.asp"-->
14 </body></html>
Here is the code for booknovels.asp:
1 <html><head>
2 <title>booknovels.asp</title>&
3 <!--#include file="bookheader.asp"-->
4 <body>
5 <h1>Recommended Novels</h1>
6 <ul>
7 <li><b><i>A Prayer for Owen Meaney</b></i><br>John Irving</li>
8 <li><b><i>Cider House Rules</b></i><br>John Irving</li>
9 <li><b><i>Heart of the Country</b></i><br>Greg Mathhews</li>
10 <li><b><i>All That Remains</b></i><br>Patricia Cornwell</li>
11 <li><b><i>Presumed Innocent</b></i><br>Scott Turrow</li>
12 <li><b><i>Time to Kill</b></i><br>John Grisham</li>
13 <li><b><i>Disclosure</b></i><br>Michael Chrichton</li>
14 <li><b><i>Mount Dragon</b></i><br>Lincoln and Childs</li>
15 </ul>
16 <!--#include file="bookfooter.asp"-->
17 </body></html>
Here is the code for bookscifi.asp:
1 <html><head>
2 <title>bookscifi.asp</title>&
3 <!--#include file="bookheader.asp"-->
4 <body>
5 <h1>Science Fiction Recommended Books</h1>
6 <ul>
7 <li><b><i>Ender's Game</b></i><br>Orson Scott Card</li>
8 <li><b><i>Hyperion</b></i><br>Dan Simmons</li>
9 <li><b><i>Childhood's End</b></i><br>Arthur Clarke</li>
10 <li><b><i>TommyKnockers</b></i><br>Steven King</li>
11 </ul>
12 <!--#include file="bookfooter.asp"-->
13 </body></html>
Here is the code for bookselfhelp.asp:
1 <html><head>
2 <title>bookselfhelp.asp</title>&
3 <!--#include file="bookheader.asp"-->
4 <body>
5 <h1>Self Help Books</h1>
6 <ul>
7 <li><b><i>Road Less Travelled</b></i><br>Scott Peck</li>
8 <li><b><i>The Seven Habits of Highly Effective People</b></i><br>Steven Covey</li>
9 <li><b><i>First Things First</b></i><br>Steven Covey</li>
10 </ul>
11 <!--#include file="bookfooter.asp"-->
12 </body></html>
Book Sample Exercises
Not Ready Yet.
Will tie into the content linker and session login/abandon examples.
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 | meaning |
| expression | the variable holding the raw number |
| iDigits | number of digits to right of decimal point |
| bleadingDigit | 1 for leading zeros 0 for no leading zeros |
| bParen | 1 for parenthesis around negative numbers 0 for no parenthesis around negative numbers |
| bGroupDigits | 1 to display numbers as per regional settings in the Control
Panel 0 to over-ride settings in the Control Panel |
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 <html><head>
2 <TITLE>formatnumbers2.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 ' My ASP formatting number sample
6 mynumber=123.4567
7 response.write "<hr>" & mynumber & "<br>"
8 response.write "formatnumber(mynumber,0)" & "<br>"
9 response.write formatnumber(mynumber,0) & "<hr>"
10 response.write "formatnumber(mynumber,2)" & "<br>"
11 response.write formatnumber(mynumber,2) & "<hr>"
12 response.write "formatnumber(mynumber,6)" & "<br>"
13 response.write formatnumber(mynumber,6) & "<hr>"
14
15 mynumber=.4567
16 response.write mynumber & "<br>"
17 '0 means means no leading zeroes
18 response.write "formatnumber(mynumber,2,0)" & "<br>"
19 response.write formatnumber(mynumber,2,0) & "<hr>"
20 '1 means means pad with leading zeroes
21 'response.write "formatnumber(mynumber,2,1)" & "<br>"
22 'response.write formatnumber(mynumber,2,1) & "<hr>"
23
24 'mynumber=-123.4567
25 'response.write mynumber & "<br>"
26 '0 means means no parentheses for negative numbers
27 'response.write "formatnumber(mynumber,2,0,0)" & "<br>"
28 'response.write formatnumber(mynumber,2,0,0) & "<hr>"
29 '1 means means yes parentheses for negative numbers
30 'response.write "formatnumber(mynumber,2,0,1)" & "<br>"
31 'response.write formatnumber(mynumber,2,0,1) & "<hr>"
32 %>
33 </body></html>
Format Dates by Charles Carroll
The built-in date functions (described
in next paragraph) are pretty lame. The holy grail of data formatting is at:
http://www.4guysfromrolla.com/webtech/112098-2.shtml
http://www.learnasp.com/iishelp/VBScript/htm/vbs109.htm are the official online docs for the FormatDateTime function. The easiest way to demonstrate formatting dates is just have some sample code that tries every permutation of the command.
1 <html><head>
2 <title>formatdates.asp</title>
3 </head><body bgcolor="#FFFFFF"><html>
4 <%'My ASP program that formats dates
5 response.write "<hr>"
6 for counter=0 to 4
7 currentdate=now()
8 response.write "today is..." & "<br>"
9 response.write currentdate & "<P>"
10 select case counter
11 case 0
12 whichformat="vbgeneraldate"
13 case 1
14 whichformat="vblongdate"
15 case 2
16 whichformat="vbshortdate"
17 case 3
18 whichformat="vblongtime"
19 case 4
20 whichformat="vbshorttime"
21 end select
22 response.write "FormatDate(now()," & whichformat & ")="
23 response.write Formatdatetime(currentdate,counter) & "<P><HR>"
24 next%>
25 </body></html>
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.
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 | Argument Description | ||||||||||||||||||
| date | 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.
|
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:
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: 3/11/2001
(You would get the same result by coding this: <%= FormatDateTime(Date, 0) %>)<%= FormatDateTime(Date, 1) %> returns: Sunday, March 11, 2001
<%= FormatDateTime(Date, 2)%> returns: 3/11/2001
If you would like to return the current time, here are a couple of ways to do that:
<%= FormatDateTime(Now, 3)%> returns: 10:39:25 AM
<%= FormatDateTime(Now, 4)%> returns: 10:39
If you would like to return the current date and time together, here's how to do just that:
<%= FormatDateTime(Now) %> returns: 3/11/2001 10:39:25 AM
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:
Sunday, March 11, 2001 10:39:25 AM
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>
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:
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.
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: Sunday, March 11, 2001
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 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.
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
Do Loop Part #1 by Charles Carroll
To execute a code sequence more than once ASP provides:
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
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 <%response.buffer=true%>
2 <TITLE>doloop1.asp</TITLE>
3 <body bgcolor="#FFFFFF">
4 <HTML>
5 <%
6 DO
7 counter=counter+1
8 response.write counter & "<br>"
9 response.flush
10 LOOP
11 %>
12 </BODY>
13 </HTML>
14
Here is an infinite loop that we explicitly set a timeout for:
1 <%
2 response.buffer=true
3 server.scripttimeout=20
4 %>
5 <TITLE>loop2.asp</TITLE>
6 <body bgcolor="#FFFFFF">
7 <HTML>
8 <%
9 DO
10 counter=counter+1
11 response.write counter & "<br>"
12 response.flush
13 LOOP
14 %>
15 </BODY>
16 </HTML>
17
18
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.
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:
loop4.asp succeeds and does not trigger the trap:
1 <%@ TRANSACTION=Required%>
2 <%
3 response.buffer=true
4 server.scripttimeout=40
5 %>
6 <HTML>
7 <TITLE>loop4.asp</TITLE>
8 <body bgcolor="#FFFFFF">
9 </BODY>
10 <%
11 DO UNTIL counter=400
12 counter=counter+1
13 response.write counter & "<br>"
14 LOOP
15 response.flush
16 response.write "Script Exexuted without incident!"
17 %>
18 </HTML>
19 <%
20 Sub OnTransactionAbort()
21 response.clear
22 Response.Write "The Script Timed Out"
23 end sub
24 %>
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") | name of script, i.e./learn/server.asp in this case |
| ref=request.servervariables("http_referer") | name of site page (unless they just typed the URL) they clicked on to get here. |
| br=request.servervariables("http_user_agent") | Identification string emitted by browser. |
| lan=request.servervariables("http_accept_language") | en for english. Basically indicates language the browser is targetted to. |
| user=request.servervariables("logon_user") | 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>
Server Variables To Determine Domain
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 CASE "www.asptraining.com"
8 response.write "Welcome Training Customer!"
9 CASE "www.activeserverpages.com"
10 response.write "Welcome To Our Reference Site!"
11 CASE "www.learnasp.com"
12 response.write "Welcome To Our Tutorial!"
13 CASE "www.aspeuro.com"
14 response.write "Welcome To Our European Site!"
15 CASE "www.asplists.com","www.asplist.com"
16 response.write "Welcome To Our ASP listservers!"
17 CASE "www.aspconventions.com","www.aspconvention.com"
18 response.write "Welcome To Our ASP convention site!"
19 CASE ELSE
20 response.write "Welcome!"
21 END SELECT
22 %>
23 </body></html>
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 for each thing in request.servervariables
3 tempvalue=request.servervariables(thing)
4 response.write thing & "=" & tempvalue & "<br>"
5 next
6 %>
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
1 <html><head>
2 <TITLE>serverall.asp</TITLE>&
3 <body bgcolor="#FFFFFF">
4 <%
5 Response.Write("<P><B>Server Variables</b><br>")
6 BlankVars="<P><B>Blank Server Variables</b><br>" & vbcrlf
7 quote=chr(34)
8 For Each Key in Request.ServerVariables
9 If instr(Key,"_ALL")+instr(key,"ALL_")=0 then
10 tempvalue=trim(request.servervariables(Key))
11 If len(tempvalue)=0 then
12 BlankVars=BlankVars & Key & ", "
13 Else
14 response.write "request.servervariables(" & quote
15 response.write Key & quote & ") "
16 response.write " =<br><B>" & tempvalue & "</b><p>" & vbcrlf
17 End If
18 end if
19 Next
20 response.write mid(BlankVars,1,len(BlankVars)-2)
21 %>
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
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 <html><head>
2 <TITLE>randomadvice.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <%
6 ' generate a random number 1-6
7 randomize
8 randomnum=int(rnd*6)+1
9 SELECT CASE randomnum
10 CASE 1,2,3%>
11 Plant your crops early this year<br>
12 No frost expected<br>
13 <%CASE 4%>
14 Never play cards<br>with a man named after a city<br>
15 <%CASE 5%>
16 You can never be too rich, too thin or backup too often<br>
17 <%CASE 6%>
18 A swallow keeps away the stork<br>
19 <%END SELECT%>
20 </body></html>
Browser Capabilites
The script below demonstrates the most commonly used property of the Browser Capabilites component.
1 <html><head>
2 <TITLE>bc.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <% Set bc = Server.CreateObject("MSWC.BrowserType") %>
5 Browser Name: <%=bc.browser %><p>
6 Browser Version: <%=bc.version%><p>
7 <% if (bc.frames = TRUE) then %>
8 I noticed you do frames<p>
9 <% else %>
10 I noticed you are frame challenged<p>
11 <% end if %>
12 <% if (bc.tables = TRUE) then %>
13 I noticed you do tables<p>
14 <% else %>
15 I noticed you can't do tables<p>
16 <% end if %>
17 <% if (bc.BackgroundSounds = TRUE)then %>
18 I noticed you allow me to play music<p>
19 <% else %>
20 I noticed you aren't a music listener<p>
21 <% end if %>
22
23 <% if (bc.vbscript = TRUE) then %>
24 I noticed you are VBscript capable<p>
25 <% else %>
26 I noticed you can't understand VB Script<p>
27 <% end if %>
28
29 <% if (bc.javascript = TRUE) then %>
30 I noticed you understand JScript<p>
31 <% else %>
32 I noticed you don't understand JScript<p>
33 <%
34 end if
35 set bc=nothing
36 %>
37 </body></html>
Browser Capability Details (by Charles Carroll)
Any ASP script attempting to detect a browser needs to realize the following:
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
Related Links:
Validate HTML @
http://validator.w3.org
Obtaining Your Users Browser Information @
http://www.4guysfromrolla.com/webtech/121400-1.shtml
Detect Browser @
http://www.learnasp.com/learn/bc.asp
Fix HTML browser problems @
http://www.w3.org/People/Raggett/tidy/
HTML Validator @
http://www.htmlvalidator.com/
AOL Coding @
http://webmaster.info.aol.com/
the BEST browser detection component @
http://www.browserhawk.com
AOL Coding @
http://www.aolserver.com/
Update Browscap.ini @
http://www.learnasp.com/learn/bcdetails.asp
Dynamic Duo Cross-Browser DHTML/Jscript @
http://www.dansteinman.com/dynduo/
Recommended Books:
BrowserHawk detects:
- disabled cookies
- disabled JavaScript
- Flash / plugins
- screen size, more!
FREE download![]()
![]()
![]()
Related Lists:
Evolt.org lists @
http://lists.evolt.org/
Good Javascript List @
http://www.mountaindragon.com/javascript/
[aspClient] - DHTML, frames, active-x, etc. @
http://www.asplists.com/asplists/aspclient.asp
Flash + ASP @
http://www.asplists.com/asplists/aspflash.asp
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
State Management
State Management Introduction (stateintro.asp) - Page 34
What are ASP Sessions? (sessionswhat.asp) - Page 35
Application Data (sessionsapps.asp) - Page 36
Application Data: Worlds Fastest ListBox (speedappdata.asp) - Page 37
XML, Database Caches - Fast Retrieval (xmlfastlist.asp) - Page 38
Say No To Databases w/Sessions or Application scope (nodbsession.asp) - Page 39
Session Overview & Myths (sessionoverview.asp) - Page 40
Sessions: Global.asa and Scalability (globalproblems.asp) - Page 41
Sessions: Global.asa Events (global.asp) - Page 42
Global.asa, Sessions, Custom Stats Resources (statemore.asp) - Page 43
State Methods: Pros and Cons (stateproscons.asp) - Page 44
Pass Data w/Hidden Fields (hidden.asp) - Page 45
Pass Data w/Cookies (cookies.asp) - Page 46
Pass Data w/Session Vars (statesessions.asp) - Page 47
Pass Data w/ID tied to database (statedb.asp) - Page 48
[aspStateManagement] Listserver (aspstatemanagement.asp) - Page 49
State Management Intro by Charles Carroll
Anyone using a browser is accessing the web via HTTP. HTTP is a stateless protocol. What that means is every page fetched from the website has NO MEMORY of the last page fetched.
Whenever we devise some "tricks" so that a web page seems to remember some previous information we call that maintaining state with the user.
Keep in mind no matter how we do this there are limits. Each method may not work in some narrow situation.
A listserver exists where this is the ONLY topic
discussed, see:
http://www.asplists.com/asplists/aspstatemanagement.asp
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 response.write "Coin Tossed!<br>"
3 randomize
4 randomnum=int(rnd*2)+1
5 IF randomnum=1 THEN
6 session("heads")=session("heads")+1
7 ELSE
8 session("tails")=session("tails")+1
9 END IF
10 response.write "Heads= " & session("heads") & "<br>"
11 response.write "Tails= " & session("tails") & "<br>"
12 %>
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.
http://msdn.microsoft.com/workshop/server/toolbox/cookie.asp
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 appblackjacklook.asp that displays how many people are at the table.
1 <%
2 response.write "Over at the BlackJack Table<br>"
3 response.write "There are " & application("bjplayers") & " players there!<br>"
4 %>
Here is a file called appblackjackarrive.asp that could be included in any script where someone arrived at the blackjack table!
1 <%
2 response.write "Welcome to the BlackJack Table<br>"
3 application.lock
4 application("bjplayers")=application("bjplayers")+1
5 application.unlock
6 response.write "There are " & application("bjplayers") & " players here!<br>"
7 %>
Here is a file called appblackjackleave.asp that could be included in any script where someone left the blackjack table!
1 <%
2 response.write "Thanks for playing BlackJack!<br>"
3 application.lock
4 application("bjplayers")=application("bjplayers")-1
5 IF application("bjplayers")<0 THEN
6 application("bjplayers")=0
7 END IF
8 application.unlock
9 response.write "There are " & application("bjplayers") & " players still at the table!<br>"
10 %>
Worlds Fastest Listbox
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 unnecessary. The database it is drawn from is not changing thousands of times a day.
In the following example any page that displays the list boxes 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 be added to sense data changes and only rebuild the list box if records were added or changed. Here is a demo script that displays the listboxes without re-querying the database.
ListMakedemo.asp is the main script. Simple enough.
1 <HTML>
2 <TITLE>listmakedemo.asp</TITLE>
3 <body bgcolor="#FFFFFF">
4 <br>
5 City: <!--#include virtual="/learn/test/listcity.asp"-->
6 <br>
7 State: <!--#include virtual="/learn/test/liststate.asp"-->
8 <br>
9 Zip: <!--#include virtual="/learn/test/listzip.asp"-->
10 </BODY></html>
11
12
13
14
ListCity.asp displays listbox of cities.
1 <!--#include virtual="/learn/test/lib_listmake.asp"-->
2 <%
3 IF application("list_city")="" THEN
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select distinct city from publishers"
6 application("list_city")=query2htmlist(mySQL,"cities",myDSN)
7 END IF
8 response.write application("list_city")
9 %>
ListState.asp displays listbox of states
1 <!--#include virtual="/learn/test/lib_listmake.asp"-->
2 <%
3 IF application("list_states")="" THEN
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select distinct state from publishers"
6 application("list_states")=query2htmlist(mySQL,"state",myDSN)
7 END IF
8 response.write application("list_states")
9 %>
ListZip.asp displays listbox ofzips.
1 <!--#include virtual="/learn/test/lib_listmake.asp"-->
2 <%
3 IF application("list_zips")="" THEN
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select distinct zip from publishers"
6 application("list_zips")=query2htmlist(mySQL,"zip",myDSN)
7 END IF
8 response.write application("list_zips")
9 %>
10
Lib_Listmake.asp is a library that makes it easier to make listboxes.
1 <%
2 function query2htmList(myquery,myname,myDSN)
3 dim conntemp, rstemp
4 set conntemp=server.createobject("adodb.connection")
5 conntemp.open myDSN
6 set rstemp=conntemp.execute(myquery)
7 query2HTMlist="<Select name='" & myname & "'>"
8 do until rstemp.eof
9 thisfield=trim(RStemp(0))
10 if isnull(thisfield) or thisfield="" then
11 ' ignore
12 else
13 query2HTMlist=query2HTMlist & "<option>" & thisfield & "</option>"
14 end if
15 rstemp.movenext
16 loop
17 query2HTMlist=query2HTMlist & "</select>"
18 rstemp.close
19 set rstemp=nothing
20 conntemp.close
21 set conntemp=nothing
22 end function
23 %>
ListMakeClear.asp is a crude mechanism to force all the listboxes to refresh. It could be invoked on a timed basis (every 15 minutes for example) or triggered by data-changes.
1 <%
2 application("list_city")=""
3 application("list_states")=""
4 application("list_zips")=""
5 %>
Worlds Fastest Listbox with XML,
Application Variables
by Jamiel Humayun Jhumayun@liveperson.com
and Ian Payne ivpayne@wagga.fsnet.co.uk
Sometimes data (like a HTML list box or table) 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 unnecessary. The database it is drawn from is not changing thousands of times a day.
In the following example any page that displays the database needs to only transform the XML application variables, not hit the database. Very speedy. If the data changes or gains new records, a trigger mechanism could be added to sense data changes and only rebuild the list box if records were added or changed. Here is a demo script that displays the listboxes without re-querying the database.
DisplayCity.asp is the main script. Simple enough.
1 <!--#include file="XMLLibrary.asp"-->
2 <html>
3 <head>
4 <title>Display XMLized Listbox</title>
5 </head>
6 <body bgcolor="#FFFFFF">
7 <b>City Table:</b> <br>
8 <% DisplayCityTable() %><br><br>
9 <b>City List:</b> <br>
10 <% DisplayCityList() %><br><br>
11 </body>
12 </html>
ListBox.xsl is the style sheet to give it a list box look
1 <?xml version="1.0"?>
2 <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
3 <xsl:template match="/">
4 <select>
5 <xsl:for-each select="xml/rs:data/z:row">
6 <option><xsl:value-of select="@city"/></option>
7 </xsl:for-each>
8 </select>
9 </xsl:template>
10 </xsl:stylesheet>
Table.xsl is the style sheet to give it a list box look
1 <?xml version="1.0"?>
2 <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
3 <xsl:template match="/">
4 <table cellpadding="2" cellspacing="0" border="1" width="100%">
5 <xsl:for-each select="xml/rs:data/z:row">
6 <tr><td><xsl:value-of select="@city"/></td></tr>
7 </xsl:for-each>
8 </table>
9 </xsl:template>
10 </xsl:stylesheet>
XMLlibrary.asp is the library that does most of the work.
1 <%
2 adPersistXML=1
3
4 Function GenXML (objRs)
5 set stmXML = CreateObject("ADODB.Stream")
6
7 If Not objRs.EOF Then
8 objRs.Save stmXML, adPersistXML ' needs ADO 2.5
9 End If
10 GenXML = stmXML.ReadText
11 Set stmXML = Nothing
12
13 End Function
14
15 Function GetCityXML ()
16 ' Database connection - Usually kept in an include file, but presented for display purposes
17 strConnection = "DSN=student;UID=student;PWD=magic;"
18 Set objConn = Server.CreateObject ("ADODB.Connection")
19 objConn.Open strConnection
20 strSQL = "SELECT DISTINCT city FROM publishers"
21 Set objRs = objConn.Execute (strSQL)
22 GetCityXML = GenXML(objRs)
23 Set objConn = Nothing
24 Set objRs = Nothing
25 End Function
26
27 Function RenderXML (strXML,strStyleSheet)
28 Set objXML = CreateObject("MSXML.DOMDocument")
29 Set objXSL = CreateObject("MSXML.DOMDocument")
30 objXML.loadXML(strXML)
31 objXSL.load(Server.MapPath(strStyleSheet))
32 Response.Write objXML.transformNode (objXSL)
33 Set objXML = Nothing
34 Set objXSL = Nothing
35 End Function
36
37 Sub DisplayCityTable()
38 if Application("City") = "" then Application("City") = GetCityXML()
39 strStyleSheet = "table.xsl"
40 Call RenderXML (Application("City"),strStyleSheet)
41 End Sub
42
43 Sub DisplayCityList()
44 if Application("City") = "" then Application("City") = GetCityXML()
45 strStyleSheet = "listbox.xsl"
46 Call RenderXML (Application("City"),strStyleSheet)
47 End Sub
48
49 %>
XMLcacheclear.asp is called to force a fresh database display.
1 <%
2 Application("City") = ""
3 %>
Databases and Sessions....
Just Say No!
by Charles
Carroll
Many new ASP programmers and some who even call themselves experienced aspire or accomplish placing recordsets and/or applications in session and/or application variables. They do it to speed things up but actually ensure that the site will perform slower as it gets busier.
Putting a recordset or application into application or session scope leads to:
What works for few users will not for many
Imagine how fast and convenient a Porsche is when driving to Las Vegas with your significant other. Must be the best way to get there... Right? Now imagine a bunch of seniors want to go. 200 seniors x 100 trips in the porsche. Ouch! The tour bus or an airplane scales. The porsche does not. Developers should always design for scaling not minimal users.

Application Level Connections
Mechanically, creating one Application level variables with a database connection is simple.
SUB application_onstart
set application("theCONN")=server.createobject("adodb.connection")
END SUB
Then any code that wants to use that connection
might look like this:
<%
mySQL="select * from publishers where state='NY'
set rstemp=application("theconn").execute(mySQL)
%>
However this code will not scale well. The code is mechanically easy, but the
scripts using this code will suffer from Thread-Affinity and Serialization.
An application variable lives until a web server shuts down. It also lives on a specific thread; we would say the object has thread affinity. Any script utilizing that object must live on same thread, as that object or make an expensive marshalled call to talk to that object.
Thread Affinity
Thread affinity is bad. If a request comes in it would be fast if any thread could perform the task. Thread affinity guarantees only 1 thread can service the request and if that thread is busy the task waits in line for that thread, despite other threads who may be able to service the request.
http://www.learnasp.com/advice/threads.asp
explains threading fundamentals.
Serialization is an enemy of Scalability
If multiple tasks all have affinity to the same thread they become serialized, that is to say they all run in sequence. As a real-world analogy for serialization imagine you wanted to buy a meal at a fast-food cashier and the person in front of you ordered 150 sandwiches for their swim-team. You don't get your 1 sandwich until they finish their order. 6 request for 150 records from a database means the fourth request for 1 record comes after those 900 are retrieved. Without thread affinity the requests could be divided among available threads.
Conclusion: All recordsets and database access would have some level of thread affinity if one connection only is made in global.asa. The side-effect would be recordsets that were forced to specific threads and serialized requests effectively slowing a site's overall performance and for specific scripts.
Recordsets stored at Sessions Level...
Mechanically, this is easy to accomplish:
SUB session_onstart
set session("rstemp")=server.createobject("adodb.recordset")
END SUB
Then any code that wants to use that connection
might look like this:
<%
...
mySQL="select * from publishers where state='NY'
set session("rstemp")=conntemp.execute(mySQL)
%>
However this code will not scale well. The code is mechanically easy, but the
scripts using this code will suffer from Thread-Affinity, Serialization, and
there will always be more recordsets than users accessing a site. In fact a more
aggregious version of Thread Affinity occurs which I will nickname
Thread-Locking.
Thread Affinity Part #2
In IIS3 and IIS4 once a user is assigned a session object (recordset or VB5/VB6 component) with thread affinity every script run in that session is forced onto the thread the first script is assigned. It effectively handcuffs every user's script to the thread their first script was assigned. This occurs because recordsets and VB5 and VB6 need to store their data on a specific thread and until destroyed (unlike C++ components which specifically aggregate the Free Thread marshaller) the objects may never be moved to a different thread which hurts performance.
More Recordsets than Users??? Please explain...
If for example a mere 20 users who access 1 page each and no others at tour site, their session objects (in this case recordsets) persist for the default session timeout (20 minutes unless the registry is modified or a page explicitly sets it using the session.timeout command. If then 50 users access several scripts and 20 of them go lunch or go home for the day, the recordsets will waste memory until their session times out. In this example there would be 90 recordsets and 30 active users within minutes. How can any scenario where significantly more resources are allocated than are being used be efficient?
http://www.learnasp.com/learn/globalproblems.asp
explains a typical scenario.
Create and Destroy on Every Page
Even though every page creates and destroys connections, the newly created ones can execute on any thread. Also because of round-robin execution resources are used sparingly and connections are never open too long.
Make Sure Connection Pooling is in Effect
Connection Pooling can speed up sites. ADO invisibly can co-ordinate that any destroyed connections are not instantly destroyed, instead they are left ready to be grabbed by the next page who requests creating a connection. That page's code has a create request that gets intercepted at a low-level and given an already created connection ready to do database access. The programmers code then is not being executed literally; their create requests often get serviced by already created connections.
http://www.learnasp.com/learn/dbpooling.asp
has more information and details.
What is the fastest way then (if I want fast, scalable database displays)?
"The Worlds Fastest Listbox"
http://www.learnasp.com/learn/speedappdata.asp
shows a lightning fast way to display databases.
GetString to speed up Data Transfer
http://www.learnasp.com/learn/dbtablegetstring.asp
GetRows to speed up Data Transfer
http://www.learnasp.com/learn/dbtablegetrows.asp
All we discuss is fast code over at:
http://www.asplists.com/asplists/aspfastcode.asp
What If I am willing to pay the price?
Make sure you test the load using tools like the
Web Stress Tool @
http://homer.rte.microsoft.com
Much more information on scalability can be found
on
http://www.asplists.com/asplists/aspscalability.asp
which has links and a signup for an excellent 2 way listserver.
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.
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:
Session variables (particularly COM objects put in a session variable) can:
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):
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:
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"-->
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.
Global.asa Events by Charles Carroll
This page demonstrates what a blank global.asa should look like:
1 <script language=vbscript runat=server>
2 SUB Application_OnStart
3 END SUB
4
5 SUB Application_OnEnd
6 END SUB
7
8 SUB Session_OnStart
9 END SUB
10
11 SUB Session_OnEnd
12 END SUB
13 </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.
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
State Management Methods, Pros and Cons by Charles Carroll
Several methods exist to maintain state. We will present a high-level summary here with advantages and drawbacks.
Method #1 Cookies
Pros: can be set for long periods of time. Wastes no server memory.
Cons: set on a machine. If user visits another machine their info is not there. If someone sits down at users machine, sites they visit may read cookie and it is NOT same person. Users may disable cookies.
Method #2 ASP Sessions
Pros: requires less lines of code than cookies. Easy to program.
Cons: wastes server memory. Evaporates and must be placed in durable storage if user changed session values. User who disable cookies can't have sessions.
Method #3 Hidden Fields
Pros: Works if user has disabled cookies.
Cons: adds Lots of code to each page. If someone invents a page that is not in your website and studies the HTML (where hidden fields are visible) they could feed incorrect hidden data to your form submits (negative numbers into shopping carts, $0 prices into shopping carts, etc.)
Method #4 Hidden Fields + Database
Pros: Works if user has disabled cookies.
Cons: adds Lots of code to each page. Since the hidden field is used to do a database retrieve, each page must hit a database.
Method #5 Homebrewed Sessions
Pros: Solves the problems of traditional ASP sessions.
Cons: Must build component or buy 3rd Party solutions (SASession from www.AspStudio.com for example).
Every site uses one or more of these methods to maintain state.
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 <html><head>
2 <TITLE>surveypage1.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <form action="surveypage2.asp" method="post">
6 First Name<br>
7
8 <input type="text" name="first" size="20"><br>
9 Last Name<br>
10
11 <input type="text" name="last" size="20">
12 <p>
13 <input type="submit" value="Next Question ->"></p>
14 </form>
15 </body></html>
surveypage2.asp asks the user the next questions:
1 <html><head>
2 <TITLE>surveypage2.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <form action="surveypage3.asp" method="post">
6 <%
7 first=request.form("first")
8 last=request.form("last")
9 %>
10 Hair Color<br>
11
12 <input type="text" name="haircolor" size="20"><br>
13 Favorite Color<br>
14
15 <input type="text" name="favoritecolor" size="20">
16 <p>
17 <input type="hidden" name="first" value="<%=first%>">
18 <input type="hidden" name="last" value="<%=last%>">
19 <input type="submit" value="Next Question ->"></p>
20 </form>
21 </body></html>
surveypage3.asp asks the user yet some more questions:
1 <html><head>
2 <TITLE>surveypage3.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <%
6 first=request.form("first")
7 last=request.form("last")
8 haircolor=request.form("haircolor")
9 favoritecolor=request.form("favoritecolor")
10 %>
11 <form action="surveypage3respond.asp" method="post">
12 Street Address<br>
13
14 <input type="text" name="street" size="20">
15 <br>
16 City<br>
17
18 <input type="text" name="city" size="20"><br>
19 State<br>
20
21 <input type="text" name="state" size="20">
22 <br>
23 Zip<br>
24
25 <input type="text" name="zip" size="20">
26 <br>
27
28
29 <input type="hidden" name="first" value="<%=first%>">
30 <input type="hidden" name="last" value="<%=last%>">
31 <input type="hidden" name="haircolor" value="<%=haircolor%>">
32 <input type="hidden" name="favoritecolor" value="<%=favoritecolor%>">
33
34 <input type="submit" value="Final Step ->">
35 </form>
36 </body></html>
surveypage3respond.asp gathers all the answers and responds:
1 <html><head>
2 <TITLE>surveypage3respond.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <%
6 first=request.form("first")
7 last=request.form("last")
8 haircolor=request.form("haircolor")
9 favoritecolor=request.form("favoritecolor")
10 street=request.form("street")
11 city=request.form("city")
12 state=request.form("state")
13 zip=request.form("zip")
14 %>
15 Thanks for all your information<br>
16 We are happy to meet you <%=first%> <%=last%><br>
17 We know your hair color is <%=haircolor%><br>
18 and your favorite color is <%=favoritecolor%><br>
19 and we will ship all items to<br>
20 <%=first%> <%=last%><br>
21 <%=street%><br>
22 <%=city%> <%=state%> <%=zip%>
23 </body></html>
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 <html><head>
2 <TITLE>surveypage1.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <%
6 first=request.cookies("prefs")("first")
7 last=request.cookies("prefs")("last")
8 %>
9 <form action="surveypage2c.asp" method="post">
10 First Name<br>
11
12 <input type="text" name="first" size="20" value="<%=first%>"><br>
13 Last Name<br>
14
15 <input type="text" name="last" size="20" value="<%=last%>">
16 <p>
17 <input type="submit" value="Next Question ->"></p>
18 </form>
19 <%
20 For Each cookie in Response.Cookies
21 Response.Cookies(cookie).Expires = now()+365
22 Next
23 %>
24 </body></html>
surveypage2c.asp asks the user the next questions:
1 <%response.buffer=true%>
2 <html><head>
3 <TITLE>surveypage2c.asp</TITLE>
4 </head>
5 <body bgcolor="#FFFFFF">
6 <%
7 first=request("first")
8 last=request("last")
9 haircolor=request.cookies("prefs")("haircolor")
10 favoritecolor=request.cookies("prefs")("favoritecolor")
11 %>
12 <form action="surveypage3c.asp" method="post">
13 Hair Color<br>
14
15 <input type="text" name="haircolor" size="20" value="<%=haircolor%>"><br>
16 Favorite Color<br>
17
18 <input type="text" name="favoritecolor" size="20" value="<%=favoritecolor%>">
19 <p>
20 <%
21 response.cookies("prefs")("first")=first
22 response.cookies("prefs")("last")=last
23 For Each cookie in Response.Cookies
24 Response.Cookies(cookie).Expires = now()+365
25 Next
26 %>
27 <input type="submit" value="Next Question ->"></p>
28 </form>
29 </body></html>
surveypage3c.asp asks the user yet some more questions:
1 <%response.buffer=true%>
2 <html><head>
3 <TITLE>surveypage3c.asp</TITLE>
4 </head>
5 <body bgcolor="#FFFFFF">
6 <%
7 haircolor=request("haircolor")
8 favoritecolor=request("favoritecolor")
9 street=request.cookies("prefs")("street")
10 city=request.cookies("prefs")("city")
11 state=request.cookies("prefs")("state")
12 zip=request.cookies("prefs")("zip")
13 %>
14 <form action="surveypage3crespond.asp" method="post">
15 Street Address<br>
16
17 <input type="text" name="street" size="20" value="<%=street%>">
18 <br>
19 City<br>
20
21 <input type="text" name="city" size="20" value="<%=city%>"><br>
22 State<br>
23
24 <input type="text" name="state" size="20" value="<%=state%>">
25 <br>
26 Zip<br>
27
28 <input type="text" name="zip" size="20" value="<%=zip%>">
29 <br>
30 <%
31 response.cookies("prefs")("haircolor")=haircolor
32 response.cookies("prefs")("favoritecolor")=favoritecolor
33 For Each cookie in Response.Cookies
34 Response.Cookies(cookie).Expires = now()+365
35 Next
36 %>
37 <input type="submit" value="Final Step ->">
38 </form>
39 </body></html>
surveypage3crespond.asp gathers all the answers and responds:
1 <%response.buffer=true%>
2 <html><head>
3 <TITLE>surveypage3respond.asp</TITLE>
4 </head>
5 <body bgcolor="#FFFFFF">
6 <%
7 first=request.cookies("prefs")("first")
8 last=request.cookies("prefs")("last")
9 haircolor=request.cookies("prefs")("haircolor")
10 favoritecolor=request.cookies("prefs")("favoritecolor")
11 street=request("street")
12 city=request("city")
13 state=request("state")
14 zip=request("zip")
15 %>
16 Thanks for all your information<br>
17 We are happy to meet you <%=first%> <%=last%><br>
18 We know your hair color is <%=haircolor%><br>
19 and your favorite color is <%=favoritecolor%><br>
20 and we will ship all items to<br>
21 <%=first%> <%=last%><br>
22 <%=street%><br>
23 <%=city%> <%=state%> <%=zip%>
24 <%
25 response.cookies("prefs")("street")=street
26 response.cookies("prefs")("city")=city
27 response.cookies("prefs")("state")=state
28 response.cookies("prefs")("zip")=zip
29 For Each cookie in Response.Cookies
30 Response.Cookies(cookie).Expires = now()+365
31 Next
32 %>
33 </body></html>
Passing Data with Sessions by Charles Carroll
These demos are not written yet but show the survey implemented with ASP sessions.
Passing Data with Databases by Charles Carroll
These demos are not written yet but show the survey implemented with a GUID and a request to a database to read and write state values for a user.
Related Links:
Hidden Fields to Pass Data between pages @
http://www.learnasp.com/learn/hidden.asp
Sessions: what are they? @
http://www.learnasp.com/learn/sessionswhat.asp
Cache application level Recordset @
http://msdn.microsoft.com/workshop/server/feature/cache.asp
Disconnected Recordsets in Session Variables by Don Hayward @
http://www.insightgraphics.com/reference/ASPStateMgmt.htm
Global.asa Sclability problems @
http://www.learnasp.com/learn/globalproblems.asp
Session Management without cookies @
http://domaindlx.com/asms/
FREE Dictionary Component that is session/app safe @
http://www.caprockconsulting.com/comsoftware.asp
Databases and Session/App Vars? Say no! @
http://www.learnasp.com/advice/dbsessionapp.asp
4 Ways to Pass data from page to page @
http://www.4guysfromrolla.com/webtech/041399-1.shtml
Cookie Munger - Sessions with no cookies @
http://msdn.microsoft.com/workshop/server/toolbox/cookie.asp
Global.asa Basics @
http://www.learnasp.com/learn/global.asp
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
Forms/Decisions
Forms: Introduction (formintro.asp) - Page 51
Forms: Text Box (formtextbox.asp) - Page 52
Forms: Text Area (formtextarea.asp) - Page 53
Forms: Check Box (formcheckbox.asp) - Page 54
Forms: Radio Buttons (formradio.asp) - Page 55
Forms: List Box (formlistbox.asp) - Page 56
Forms: CASE syntax #1 (case.asp) - Page 57
Forms: CASE syntax #2 (case2.asp) - Page 58
Forms: IF syntax #1 (if.asp) - Page 59
Forms: IF syntax #2 (if2.asp) - Page 60
Forms: IF syntax #3 (if3.asp) - Page 61
Forms: IF syntax #4 (if4.asp) - Page 62
Forms: For Each Iteration (formforeach.asp) - Page 63
Form - Submit To Self' (formsubmitself.asp) - Page 64
Form - Change Action on Fly (formactionchange.asp) - Page 65
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.
Form with GET
<form action="x.asp" name="whatever" method=get>
....
<input type=submit>
<input type=reset>
</form>
Form with POST
<form action="x.asp" name="whatever" method="post">
....
<input type=submit>
<input type=reset>
</form>
Tips:
Tip #1: If using response.redirect to simulate a GET don't forget to encode:
/learn/encode.aspTip #2: A text link can be used intead of a button to post above form would look like this:
<a href="javascript:document.yourformname.submit();">
send data</a>
Forms - Text Box (by John Kauffman & Charles Carroll)
| <INPUT NAME="NameLast"> | 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. |
| <INPUT NAME="ZipCode" SIZE="10"> | This is not a limit to the number of characters that can be entered. Do not use size as a validation technique to limit verbose users. |
| <INPUT NAME="State" MaxLength="2"> | This controls the maximum number of characters that can be entered. |
| <INPUT NAME="NameLast" VALUE="Bertrand"> | The name of Bertrand will appear when the page is opened and will re-appear if the form is reset. |
1 <html><head>
2 <title>FormTextBox.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <Form action = "FormTextBoxRespond.asp" method="get">
5 Fill Out This Form For Us:<p>
6 Last Name -> <Input NAME="NameLast" size ="10"><br>
7 Country -> <Input NAME="Country" value="USA" size="10"><br>
8 State -> <Input NAME="State" MaxLength="2" size="2"><br>
9 <Input type="submit" value="Give me your data!">
10 <hr></form>
11 </body></html>
1 <html><head>
2 <title>FormTextBoxRespond.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 lname=request.querystring("namelast")
6 cty=request.querystring("country")
7 st=request.querystring("state")
8
9 response.write lname & "<br>"
10 response.write cty & "<br>"
11 response.write st & "<br>"%>
12 </body></html>
Forms - Text Area by John Kauffman & Charles Carroll
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 <html><head>
2 <TITLE>formTextArea.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="FormTextAreaRespond.asp" method="post">
5 <p>TextArea Example</p>
6 <p>Please type your special shipping comments:</p>
7 <TEXTAREA NAME="shippingComments" ROWS="5" COLS="50">
8 shipping comments go here
9 </textarea>
10 <p><input type=submit value="send in comments!">
11 </form>
12 </body></html>
The responder to the form will look like this:
1 <html><head>
2 <TITLE>formTextArearespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 comm=request.form("shippingcomments")
6 response.write comm
7 %>
8 <hr>
9 </body></html>
Tip: Want to retain Hard-Returns the User Types?
Then change the form responder:
comm=request.form("shippingcomments")
becomes
comm=request.form("shippingcomments")
comm=replace(comm,vbcrlf,"<br>")
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 <html><head>
2 <TITLE>FormCheckBox.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="FormCheckBoxRespond.asp" method="post">
5 <p>CheckBox Form Example</p>
6 <p>How do you want your order confirmed?</p>
7 <input TYPE="checkbox" NAME="USMail">confirmation sent by first class US Postal Service<br>
8 <input TYPE="checkbox" NAME="UPS">confirmation sent by UPS overnight letter service<br>
9 <input TYPE="checkbox" NAME="EMail" CHECKED>confirmation sent by EMail<br>
10 <input TYPE="checkbox" NAME="Fax">confirmation sent by Fax<br>
11 <input TYPE="checkbox" NAME="Tel" CHECKED>confirmation made by telephone call<br><br>
12 <input type="submit"><input type="reset">
13 </form><hr></body></html>
The responder looks like this:
1 <html><head>
2 <TITLE>formCheckBoxRespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 If request.form("USMail")="on" then
6 response.write "<br>We will confirm by US Mail"
7 end if
8 If request.form("UPS")="on" then
9 response.write "<br>We will confirm by UPS"
10 end if
11 If request.form("EMail")="on" then
12 response.write "<br>We will confirm by EMail"
13 end if
14 If request.form("fax")="on" then
15 response.write "<br>We will confirm by fax"
16 end if
17 If request.form("tel")="on" then
18 response.write "<br>We will confirm by tel"
19 end if%>
20 </body>
21 </html>
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 <html><head>
2 <TITLE>formRadio.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="FormRadiorespond.asp" method="post">
5 <p><b>Radio Buttons </b> example</p>
6 <p>Which Regional Office will you be visiting?</p>
7 <input TYPE="radio" NAME="City" VALUE="NY">New York City
8 <input TYPE="radio" NAME="City" VALUE="LA">Los Angeles
9 <input TYPE="radio" NAME="City" VALUE="SV" CHECKED>Savannah
10 <br><input type="submit" value="choose a city">
11 </form>
12 </body></html>
The responder looks like:
1 <html><head>
2 <TITLE>formradiorespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%myCity = request.form("City")
5 Select Case ucase(MyCity)
6 case "NY"
7 response.write "New York meeting is on Jan 3"
8 case "LA"
9 response.write "LA meeting meeting is on Jan 15"
10 case "SV"
11 response.write "Savannah meeting is on Jan 20"
12 End Select%>
13 </body>
14 </html>
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 <html><head>
2 <TITLE>FormListBox.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="FormListBoxRespond.asp" method="post">
5 <SELECT NAME="state">
6 <OPTION SELECTED VALUE="md">Maryland</OPTION>
7 <OPTION value="dc">District of Columbia</OPTION>
8 <OPTION value="va">Virginia</OPTION>
9 <OPTION value="whoknows">Somewhere Else!</OPTION>
10 </SELECT>
11 <input type=submit value="Choose State">
12 </form>
13 </body></html>
The responder looks like this:
1 <html><head>
2 <TITLE>formlistboxrespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%mystate = request.form("state")
5 Select Case ucase(mystate)
6 case "DC"
7 response.write "DC meeting on 15th"
8 case "MD"
9 response.write "MD meeting on 20th"
10 case else
11 response.write "No meetings for you to attend!"
12 End Select%>
13 </body>
14 </html>
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 <html><head>
2 <TITLE>case.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="caserespond.asp" method="get">
5 Your First Name<INPUT NAME="FirstName" MaxLength=20><p>
6 Your Last Name<INPUT NAME="LastName" MaxLength=20><p>
7 <INPUT TYPE=submit><p><INPUT TYPE=reset>
8 </form>
9 </body></html>
Here is the select case that will determine what the form input means.
1 <html><head>
2 <TITLE>caserespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 fname=request.querystring("Firstname")
6 lname=request.querystring("Lastname")
7 %>
8 Nice to Meet You <%=fname%> <%=lname%><p>
9 <%If fname="" then%>
10 Sorry we are not on a first name basis...<p>
11 <%end if
12 select case lcase(lname)
13 case "washington","adams"
14 response.write "The first president has same last name<p>"
15 case "jefferson"
16 response.write "The third president has same last name<p>"
17 case "lincoln"
18 response.write "The sixteenth president has same last name<p>"
19 end select%>
20 </body></html>
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 <html><head>
2 <TITLE>case2.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="case2respond.asp" method="get">
5 Your First Name<INPUT NAME="FirstName" MaxLength=20><p>
6 Your Last Name<INPUT NAME="LastName" MaxLength=20><p>
7 Your Title
8 <INPUT TYPE="Radio" name="Title" VALUE="employee">Entry Level
9 <INPUT TYPE="Radio" name="Title" VALUE="temp" CHECKED>Temporary Employee
10 <INPUT TYPE="Radio" name="Title" VALUE="manager">Management Candidate
11 <INPUT TYPE="Radio" name="Title" VALUE="executive">Executive
12 <INPUT TYPE="Radio" name="Title" VALUE="vice-prez">The Vice President of...
13 <INPUT TYPE="Radio" name="Title" VALUE="CEO">The Boss<p>
14 <INPUT TYPE=submit><p>
15 </form>
16 </body></html>
Here is the select case that will determine what the form input means.
1 <html><head>
2 <TITLE>case2respond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 fname=request.querystring("Firstname")
6 lname=request.querystring("Lastname")
7 title=request.querystring("title")
8 response.write "Nice to Hire You " & fname & " " & lname & "<p>"
9 Select Case lcase(Title)
10 case "employee","temp"
11 response.write("The washroom is in the hall")
12 case "manager","executive"
13 response.write("Here is your key to the Executive washroom")
14 case "ceo", "vice-prez"
15 response.write("The maid will attend to your private washroom")
16 End Select%>
17 </body></html>
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 <TITLE>if.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="ifrespond.asp" method=get>
5 Your First Name<INPUT NAME="FirstName" MaxLength=20><p>
6 Your Last Name<INPUT NAME="LastName" MaxLength=20><p>
7 <INPUT TYPE=submit><p><INPUT TYPE=reset>
8 </form></body></html>
Now we make a asp file that examines their first name and last name after the form is submitted.
1 <html><head>
2 <TITLE>ifrespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%fname=request.querystring("Firstname")
5 lname=request.querystring("Lastname")
6 If fname="George" and lname="Washington" then%>
7 Hi.<p>You must be the first president!
8 <%else%>
9 Hi!<p>Nice to Meet You
10 <%end if%>
11 </body></html>
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 <html><head>
2 <TITLE>if2.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="if2respond.asp" method=get>
5 Your First Name<INPUT NAME="FirstName" MaxLength=20><p>
6 Your Last Name<INPUT NAME="LastName" MaxLength=20><p>
7 <INPUT TYPE=submit><p><INPUT TYPE=reset>
8 </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 <html><head>
2 <TITLE>if2respond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 fname=lcase(request.querystring("Firstname"))
6 lname=lcase(request.querystring("Lastname"))
7 If fname="george" and lname="washington" then%>
8 Hi.<p>You must be the first president!
9 <%elseIf fname="ronald" and lname="reagan" then%>
10 Hi.<p>You must be the actor president!
11 <%elseIf fname="jimmy" and lname="carter" then%>
12 Hi.<p>You must be the peanut farmer president!
13 <%elseIf fname="naoko" or fname="charles" then%>
14 Hi.<p>Your name reminds me of someone<p>
15 but I am not sure who!
16 <%else%>
17 Hi!<p>Nice to Meet You
18 <%end if%>
19 </body></html>
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 <html><head>
2 <TITLE>if3.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="if3respond.asp" method=get>
5 Your First Name<INPUT NAME="FirstName" MaxLength=20><p>
6 Your Last Name<INPUT NAME="LastName" MaxLength=20><p>
7 Your Salary <INPUT NAME="Salary" MaxLength=7><p>
8 <INPUT TYPE=submit><p><INPUT TYPE=reset>
9 </form></body></html>
This example shows how IF can deal with ranges and use various other boolean operators.
1 <html><head>
2 <TITLE>if3respond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 fname=request.querystring("Firstname")
6 lname=request.querystring("Lastname")
7 salary=request.querystring("Salary")
8 response.write "Nice to Meet You " & fname & " " & lname & "<p>"
9 if salary>100000 then%>
10 Would you like to loan me some money?<p>
11 <%
12 sstaxMarginal=15
13 else
14 SSTaxMarginal=15
15 end if
16 If salary>6700 and salary<30000 then
17 SSTaxMarginal=0%>
18 Would you like me to loan you some money?<p>
19 <%end if
20 If salary<6700 then
21 SSTaxMarginal=0
22 end if
23 %>
24 By the way your marginal tax rate is <%=sstaxmarginal%>
25 </body></html>
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 <html><head>
2 <TITLE>if4.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="if4respond.asp" method=get>
5 Your First Name<INPUT NAME="FirstName" MaxLength="20"><p>
6 Your Last Name<INPUT NAME="LastName" MaxLength="20"><p>
7 Your Salary <INPUT NAME="Salary" MaxLength="7"><p>
8 <INPUT TYPE=submit><p>
9 </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 <html><head>
2 <TITLE>if4respond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%fname=request.querystring("Firstname")
5 lname=request.querystring("Lastname")
6 salary=request.querystring("Salary")
7 response.write "Nice to Meet You " & fname & " " & lname & "<p>"
8 if salary>80000 then
9 salarygrade=4
10 end if
11 if salary <=80000 then
12 salarygrade=3
13 end if
14 If salary <=60000 then
15 salarygrade=2
16 end if
17 if salary <=40000 then
18 salarygrade=1
19 end if
20 response.write ("Your Salary is $" & salary)
21 response.write (", your Grade is " & salarygrade & ".<p>")
22 %>
23 </body></html>
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 <html><head>
2 <TITLE>monthlyForm.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form action="monthlyFormRespond.asp" method="post">
5 <p>CheckBox Form Example</p>
6 <p><b>Check Off The Days You Worked</b></p>
7 <%
8 my_month=request.querystring("whichmonth")
9 ' response.write my_month & "<br>"
10 if my_month="" then
11 my_date=now()
12 else
13 my_month=month(request.querystring("whichmonth") & "/1/2000")
14 my_date=dateserial(year(now()),my_month,1)
15 end if
16 'response.write my_date & "<br>"
17
18 If my_month=12 then
19 my_day=1
20 my_month=1
21 my_year=my_year+1
22 else
23 my_day=1
24 my_month=month(my_date)+1
25 my_year=year(my_date)
26 end if
27
28 lastdayofmonth=day(DateSerial(Year(my_Date), my_Month,0))
29 'response.write lastdayofmonth & "<br>"
30
31 for counter=1 to lastdayofmonth%>
32 <input TYPE="checkbox" NAME="workingday<%=counter%>">day <%=counter%> Worked?<br>
33 <%next%>
34 <input type="submit" value="Submit Days Worked">
35 </form>
36 </body></html>
1 <html><head>
2 <TITLE>monthlyFormRespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 daysworked=0
6 for each whatever in request.form
7 thisvalue=request.form(whatever)
8 If thisvalue="on" then
9 daysworked=daysworked+1
10 end if
11 next
12 response.write "Thanks for working <b>" & daysworked & "</b> days"
13 %>
14 </body></html>
Form Tricks #2: Self-Submitting Forms
There are some clever tactics programmers can apply when dealing with forms. They have their drawbacks and should be used sparingly.
Some people prefer to combine their forms and actions in one file. I don't because of usability issues -- a user who refreshes a combined form will be presented with a confusing choice "repost form data (y/n)" which they are not presented with if the forms are separate. Such a form could be submitted twice accidentally when they just meant to redisplay the form.
1 <html><head>
2 <title>FormSubmitSelf.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 SELECT CASE lcase(request.form("join"))
6 CASE "join"
7 response.write "Thanks for joining "
8 response.write request.form("namefirst") & " "
9 response.write request.form("namelast") & " "
10 CASE ELSE
11 %>
12 <Form method="post">
13 Fill Out This Form For Us:<p>
14 First Name <Input NAME="NameLast" size ="10"><br>
15 Last Name <Input NAME="NameLast" size ="10"><br>
16 <input type="submit" name="Join" value="Join">
17 </form>
18 <%END SELECT%>
19 </body></html>
20
Form Tricks #3: Forms that Dynamically Change Action
There are some clever tactics programmers can apply when dealing with forms. They have their drawbacks and should be used sparingly.
Some forms need to vary their action.
1 <html><head>
2 <title>FormTextBox.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <Form name="profile" action = "profilerespond.asp" method="post">
5 Fill Out This Form For Us:<p>
6 First Name <Input NAME="NameLast" size ="10"><br>
7 Last Name <Input NAME="NameLast" size ="10"><br>
8 <a href="Javascript:army()">Join Army</a>
9 <a href="Javascript:navy()">Join Navy</a>
10 <a href="Javascript:marines()">Join Marines</a>
11 </form>
12 </body></html>
13
14 <form name=myform>
15 </form>
16
17 <script language =javascript>
18 function army(form)
19 {
20 document.myform.action="joinarmy.asp"
21 document.myform.submit()
22 }
23 function navy(form)
24 {
25 document.myform.action="joinnavy.asp"
26 document.myform.submit()
27 }
28 function marines(form)
29 {
30 document.myform.action="joinmarines.asp"
31 document.myform.submit()
32 }
33 </script>
Databases
Displaying Table w/Simple Code (dbsimple.asp) - Page 67
List Box Displayed Generically (dblist.asp) - Page 68
Database to ListBox Online Resources (dblistmore.asp) - Page 69
DSNLess Connections (dbopen.asp) - Page 70
DSN Setup #1 by Rob Martinson (dsn1.asp) - Page 71
DSN Setup #2 by Rob Martinson (dsn2.asp) - Page 72
DSN Setup #3 by Rob Martinson (dsn3.asp) - Page 73
DSN Setup #4 by Rob Martinson (dsn4.asp) - Page 74
DSN Setup #5 by Rob Martinson (dsn5.asp) - Page 75
DSN Setup #6 by Rob Martinson (dsn6.asp) - Page 76
Full Cycle #1 Show/Edit/Update (dbfull1.asp) - Page 77
Full Cycle #2 Show/Edit/Update (dbfull2.asp) - Page 78
Full Cycle #3 Show/Edit/Update (dbfull3.asp) - Page 79
SQL Mistakes Everyone Makes (dbtroubleshoot2.asp) - Page 80
DB: Table Displayed Generically (dbtable.asp) - Page 81
Getstring to display database table (dbtablegetstring.asp) - Page 82
Getrows to display database table (dbtablegetrows.asp) - Page 83
GetRows w/no Numbers (dbtablegetrowsnonum.asp) - Page 84
Disconnected Recordsets, Display Table (dbtabledisconnected.asp) - Page 85
DB: More ways To Display Tables (dbtablemore.asp) - Page 86
DB: Generic DB by Eli Robillard (genericdb.asp) - Page 87
Generic DB Listserver (aspgenericdb.asp) - Page 88
DB: Converting a DB to a Comma-Delimited file (dbconvert.asp) - Page 89
DB: Deleting a Record w/SQL (dbSQLdelete.asp) - Page 90
DB: Access Scalability (accesstest.asp) - Page 91
ADO: Paging Records (dbtablepaged.asp) - Page 92
ADO: Limiting Number of Records (dbmaxrecs.asp) - Page 93
ADO: Count Records in Query (dbcount.asp) - Page 94
ADO: Cursor Types by Phil Paxton (adocursortypes.asp) - Page 95
ADO: Input Form (dbnewrec.asp) - Page 96
ADO: Input Form, added w/SQL (dbnewSQL.asp) - Page 97
ADO: Input Form, Added w/ADO .addnew (dbnewADO.asp) - Page 98
ADO: Tables within Databases (dbtablelists.asp) - Page 99
ADO: Schemas to access table lists (dbschemas.asp) - Page 100
ADO: Schemas to access All Data (dbschemasall.asp) - Page 101
ADO: Show Table,1 param (db1parm.asp) - Page 102
ADO: Update/edit Record (dbupdate.asp) - Page 103
DB: Troubleshooting Part 1 (dbtroubles.asp) - Page 104
DB: Troubleshooting Part 2 (dbtroubles2.asp) - Page 105
Database -- Simple Table Display by Charles Carroll
This page demonstrates the capabilities how to display a table from a SQL statement.
1 <html><head>
2 <TITLE>dbsimple.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <%
6 ' this code opens the database
7 myDSN="DSN=Student;uid=student;pwd=magic"
8 set conntemp=server.createobject("adodb.connection")
9 conntemp.open myDSN
10
11 ' this code retrieves the data
12 mySQL="select * from publishers where state='NY'"
13 set rstemp=conntemp.execute(mySQL)
14
15 ' this code detects if data is empty
16 If rstemp.eof then
17 response.write "No records matched<br>"
18 response.write mySQL & "<br>So cannot make table..."
19 connection.close
20 set connection=nothing
21 response.end
22 end if
23 %>
24 <table border=1>
25 <%
26 ' This code puts fieldnames into column headings
27 response.write "<tr>"
28 for each whatever in rstemp.fields
29 response.write "<td><B>" & whatever.name & "</B></TD>"
30 next
31 response.write "</tr>"
32
33 ' Now lets grab all the records
34 DO UNTIL rstemp.eof
35 ' put fields into variables
36 pubid=rstemp("pubid")
37 name=rstemp("name")
38 company_name=rstemp("company name")
39 address=rstemp("address")
40 city=rstemp("city")
41 state=rstemp("state")
42 zip=rstemp("zip")
43 telephone=rstemp("telephone")
44 fax=rstemp("fax")
45 comments=rstemp("comments")
46
47 ' write the fields to browser
48 cellstart="<td align=""top"">"
49 response.write "<tr>"
50 response.write cellstart & pubid & "</td>"
51 response.write cellstart & name & "</td>"
52 response.write cellstart & company_name & "</td>"
53 response.write cellstart & address & "</td>"
54 response.write cellstart & city & "</td>"
55 response.write cellstart & state & "</td>"
56 response.write cellstart & zip & "</td>"
57 response.write cellstart & telephone & "</td>"
58 response.write cellstart & fax & "</td>"
59 response.write cellstart & comments & "</td>"
60
61 response.write "</tr>"
62 rstemp.movenext
63 LOOP
64 %>
65 </table>
66
67 <%
68 ' Now close and dispose of resources
69 rstemp.close
70 set rstemp=nothing
71 conntemp.close
72 set conntemp=nothing
73 %>
74 </body></html>
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 <html><head>
2 <TITLE>dblist.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 myDSN="DSN=Student;uid=student;pwd=magic"
6 mySQL="select author from authors where AU_ID<100"
7
8 ' displays a database field as a listbox
9 set conntemp=server.createobject("adodb.connection")
10 conntemp.open myDSN
11 set rstemp=conntemp.execute(mySQL)
12 if rstemp.eof then
13 response.write "no data for<br>"
14 response.write mySQL
15 conntemp.close
16 set conntemp=nothing
17 response.end
18 end if
19
20 %>
21 <form action="dblistrespond.asp" method="post">
22 <Select name="authorname">
23 <%
24 ' Now lets grab all the data
25 do until rstemp.eof %>
26 <option> <%=RStemp(0)%> </option>
27 <%
28 rstemp.movenext
29 loop
30
31 rstemp.close
32 set rstemp=nothing
33 conntemp.close
34 set conntemp=nothing
35 %>
36 <input type="submit" value="Choose Author">
37 </Select></form>
38 </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>
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
DSN, DSNless connections by Charles Carroll
OLEDB Good Connection String (recommended)
strconn="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE="
strconn=strconn & server.mappath(accessDB)
& ";"
'strconn=strconn & "Password=whatever;"
ODBC Connection String
(not recommended)
strconn="DRIVER={Microsoft
Access Driver (*.mdb)};"
strconn=sourceDSN & "DBQ=" & server.mappath(accessdb)
strconn=sourceDSN & "Password=whatever;"
NOTE: An ODBC connection string to Access often results in the dreaded: Unable to open registry key or 'Unspecified Error' usually occurs with an ODBC connection string to Access, i.e.
Any ASP script that needs to connect to a database must open it on the server first. There are several ways:
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 NOT the fastest way* since all the information resides
on the server and need only be validated when the DSN is setup.
FILE DSN
which is not recommended for high concurrency situations since all
users would be bottlenecked by how fast the ASII file that holds the DSN
could be accessed. The trouble with a File DSN is that every
connection.open must open, read, close an ASCII file
and present the data anew to the provider/driver
since the ASCII file may have changed since last connection.File DSNs are
bottlenecks on busy sites.
Most Connection strings are detailed @
http://www.able-consulting.com/ado_conn.htm?f=ado_conn.htm
& http://support.microsoft.com/support/kb/articles/q193/3/32.asp
http://support.microsoft.com/support/kb/articles/Q191/7/54.ASP
4GuyfromRolla (a superb ASP site of unparalleled depth) has a great set of DSN articles:
* System DSN or DSNless connection @
http://www.4guysfromrolla.com/webtech/070399-1.shtmlNifty way to make DSNless connections @
http://www.4guysfromrolla.com/webtech/070699-1.shtmlListing System DSNs with a FREE component:
http://www.4guysfromrolla.com/webtech/011900-1.shtml
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. 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.
1 <HTML><HEAD>
2 <TITLE>nwind.asp</TITLE>
3 <body bgcolor="#FFFFFF"></HEAD>
4 <%
5 accessdb=server.mappath("nwind.mdb")
6 strconn="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE="
7 strconn=strconn & accessDB & ";"
8 'strconn=strconn & "USER ID=;PASSWORD=;"
9
10 mySQL="select * from customers"
11
12 call query2table(mySQL,strconn)
13 %>
14 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
15 </BODY>
16 </HTML>
17
18
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>sqlserverdsn.asp</TITLE>
3 <body bgcolor="#FFFFFF"></HEAD>
4 <%
5 strconn="DSN=student;uid=student;pwd=magic"
6 mySQL="select * from publishers where state='NY'"
7
8 call query2table(mySQL,strconn)
9 %>
10 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
11 </BODY>
12 </HTML>
13
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 <TITLE>sqlDSNless.asp</TITLE>
3 <body bgcolor="#FFFFFF"></HEAD>
4 <%
5 strconn="PROVIDER=MSDASQL;DRIVER={SQL Server};"
6 strconn=strconn & "SERVER=sql2.datareturn.com;DATABASE=;"
7 strconn=strconn & "UID=student;PWD=magic;"
8
9 mySQL="select * from publishers where state='NY'"
10
11 call query2table(mySQL,strconn)
12 %>
13 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
14 </BODY>
15 </HTML>
16
17
18
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%>
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).
![]()
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.

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".
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).
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 response.buffer=true
3 Response.ExpiresAbsolute = Now() - 1
4 Response.AddHeader "Cache-Control", "private"
5 %>
6 <html><head>
7 <title>authorshow.asp</title>
8 <meta http-equiv="pragma" content="no-cache">
9 </head><body bgcolor="#FFFFFF">
10 <%
11 myDSN="DSN=Student;uid=student;pwd=magic"
12 mySQL="select * from authors where AU_ID<100 order by author"
13 IDfield="AU_ID"
14 scriptresponder="authoredit.asp"
15
16 set conntemp=server.createobject("adodb.connection")
17 conntemp.open myDSN
18 set rstemp=conntemp.execute(mySQL)
19 howmanyfields=rstemp.fields.count -1
20 %>
21 <table border="1">
22 <tr>
23 <td valign="top">---</td>
24 <% 'Put Headings On The Table of Field Names
25 for i=0 to howmanyfields %>
26 <td><b><%=rstemp(i).name %></b></td>
27 <% next %>
28 </tr>
29 <% ' Now lets grab all the records
30 do while not rstemp.eof %>
31 <tr><td valign="top">
32 <%my_link=scriptresponder & "?which=" & rstemp(idfield)%>
33 <a HREF="<%=my_link%>">Edit</a></td>
34 <% for i = 0 to howmanyfields%>
35 <td valign="top"><%=rstemp(i)%></td>
36 <% next %>
37 </tr>
38 <%
39 rstemp.movenext
40 loop
41
42 rstemp.close
43 set rstemp=nothing
44 conntemp.close
45 set conntemp=nothing
46 %>
47 </table></body></html>
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 <html><head>
2 <title>authoredit.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 ' My ASP program that given an AU_ID, allows editing a record
6
7 myDSN="DSN=Student;uid=student;pwd=magic"
8
9 set conntemp=server.createobject("adodb.connection")
10 conntemp.open myDSN
11 form_ID=request.querystring("which")
12
13 sqltemp="select * from authors "
14 sqltemp=sqltemp & " where AU_ID=" & form_id
15
16 set rstemp=conntemp.execute(sqltemp)
17
18
19 form_auID=rstemp("AU_ID")
20 form_author=rstemp("Author")
21 form_year_born=rstemp("Year_Born")
22
23 rstemp.close
24 set rstemp=nothing
25 conntemp.close
26 set conntemp=nothing
27 %>
28 <body>
29 <form name="myauthor" action="authoreditrespond.asp" method="POST">
30
31 <input type="hidden" name="id" value="<%=form_auid%>">
32
33 <p>Author ID: <%=form_auid%></p>
34
35 <p> Author Name:
36 <input type="TEXT" name="name" value="<%=form_author%>"></p>
37
38 <p> Year Born:
39 <input type="TEXT" name="year" value="<%=form_year_born%>"></p>
40
41 <p> <input type="SUBMIT"> </p>
42 </form>
43 </body>
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 <HTML><HEAD>
2 <TITLE>authoreditrespond.asp</TITLE>
3 <body bgcolor="#FFFFFF"></HEAD>
4 <%
5 on error resume next
6 form_name=request.form("name")
7 form_year=request.form("year")
8 form_ID=request.form("ID")
9
10 Set Conn = Server.CreateObject("ADODB.Connection")
11 conn.open "DSN=Student;uid=student;pwd=magic"
12
13 ' change apostrophe to double apostrophe
14 form_name=Replace(form_name, "'", "''")
15 IF instr(lcase(form_name),"<img")>0 THEN
16 form_name=""
17 END IF
18
19 SQLstmt = "UPDATE authors SET "
20 SQLStmt = SQLstmt & "Author='" & form_name & "',"
21 SQLstmt = SQLstmt & "year_born=" & form_year
22 SQLStmt = SQLStmt & " WHERE AU_ID=" & form_id
23
24
25 Set RS = Conn.Execute(SQLStmt)
26
27 If err.number>0 then
28 response.write "VBScript Errors Occured:" & "<P>"
29 response.write "Error Number=" & err.number & "<P>"
30 response.write "Error Descr.=" & err.description & "<P>"
31 response.write "Help Context=" & err.helpcontext & "<P>"
32 response.write "Help Path=" & err.helppath & "<P>"
33 response.write "Native Error=" & err.nativeerror & "<P>"
34 response.write "Source=" & err.source & "<P>"
35 response.write "SQLState=" & err.sqlstate & "<P>"
36 end if
37 IF conn.errors.count> 0 then
38 response.write "Database Errors Occured" & "<P>"
39 response.write SQLstmt & "<P>"
40 for counter= 0 to conn.errors.count
41 response.write "Error #" & conn.errors(counter).number & "<P>"
42 response.write "Error desc. -> " & conn.errors(counter).description & "<P>"
43 next
44 else
45 response.write "<B>Everything Went Fine. Record is updated now!</b>"
46 response.write "<br>" & SQLstmt
47 end if
48
49 rs.close
50 set rs=nothing
51 Conn.Close
52 set conn=nothing
53 %>
54 </BODY>
55 </HTML>
56
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) |
| UPDATE mytableSET LocID=0007,Material=13 1/4 Description=T-shirts ListPrice=35 WHERE CusID=97 |
added space before SET UPDATE mytable SET LocID='0007',Material='13 1/4', Description='T-shirts', [List Price]=35 WHERE CusID=97 |
| INSERT INTO authors (AU_ID, author, year_born) VALUES (7000, Joe Smith,1950) | INSERT INTO authors (AU_ID, author, year_born) VALUES (7000, 'Joe Smith',1950) |
| SELECT * from atable
where state = MD and year born<1955 |
SELECT * from atable
where state = 'MD' and and [year born]<1955 |
| <% key=request.querystring("id") au=request.querystring("author") birthyear=request.querystring("year") SQLstmt="INSERT INTO authors (AU_ID, author, year_born) VALUES (" SQLstmt= SQLstmt & key & "," SQLstmt= SQLstmt & author & "," SQLstmt= SQLstmt & birthyear & ")" %> |
<% key=request.querystring("id") au=request.querystring("author") au=Replace(au, "'", "''") birthyear=request.querystring("year") SQLstmt="INSERT INTO authors (AU_ID, author, year_born) VALUES (" SQLstmt= SQLstmt & key & ",'" SQLstmt= SQLstmt & author & "'," SQLstmt= SQLstmt & birthyear & ")" %> |
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 <html><head>
2 <TITLE>dbtable.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <%
6 ' ASP program that displays a database in table form
7 myDSN="DSN=Student;uid=student;pwd=magic"
8 mySQL="select * from publishers where state='NY'"
9 showblank=" "
10 shownull="-null-"
11
12 set conntemp=server.createobject("adodb.connection")
13 conntemp.open myDSN
14 set rstemp=conntemp.execute(mySQL)
15 If rstemp.eof then
16 response.write "No records matched<br>"
17 response.write mySQL & "<br>So cannot make table..."
18 conntemp.close
19 set conntemp=nothing
20 response.end
21 end if
22 %>
23 <table border=1><tr>
24
25 <% 'Put Headings On The Table of Field Names
26 for each whatever in rstemp.fields%>
27 <td><b><%=whatever.name%></B></TD>
28 <% next %>
29 </tr>
30
31 <% ' Now lets grab all the records
32 DO UNTIL rstemp.eof %>
33 <tr>
34 <% for each whatever in rstemp.fields
35 thisfield=whatever.value
36 if isnull(thisfield) then
37 thisfield=shownull
38 end if
39 if trim(thisfield)="" then
40 thisfield=showblank
41 end if%>
42 <td valign=top><%=thisfield%></td>
43 <% next %>
44 </tr>
45 <%rstemp.movenext
46 LOOP%>
47 </table>
48
49 <%
50 rstemp.close
51 set rstemp=nothing
52 conntemp.close
53 set conntemp=nothing
54 %>
55 </body></html>
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.
Its speed and scalability advantages
are explained in:
Http://www.learnasp.com/advice/whygetrows.asp
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
http://www.learnasp.com/learn/versioncheck.asp
will help you determine this.
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.
"The Worlds Fastest Listbox"
http://www.learnasp.com/learn/speedappdata.asp
shows the only faster way to display databases.
1 <TITLE>dbtablegetstring.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <%
4 whichDSN="DSN=Student;uid=student;pwd=magic"
5 mySQL="select * from publishers where state='NY'"
6
7 set conntemp=server.createobject("adodb.connection")
8 conntemp.open whichDSN
9 set rstemp=conntemp.execute(mySQL)
10 If rstemp.eof then
11 response.write "No records matched<br>"
12 response.write mySQL & "<br>So cannot make table..."
13 Call CloseAll
14 response.end
15 end if
16
17 response.write "<table border='1'><tr>"
18 'Put Headings On The Table of Field Names
19 for each whatever in rstemp.fields
20 response.write "<td><b>" & whatever.name & "</B></TD>"
21 next
22 response.write "</tr><tr><td>"
23 response.write rstemp.getstring(,, "</td><td>", "</td></tr><TR><TD>", "-null-")
24 response.write "</td></tr></table>"
25 Call CloseAll
26
27
28 SUB CloseALL
29 rstemp.close
30 set rstemp=nothing
31 conntemp.close
32 set conntemp=nothing
33 END SUB
34 %>
35 </body></html>
36
37
38
39
40
41
42
43
44
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.
The array fields are accessed by
number, a script at:
http://www.learnasp.com/learn/dbtablegetrowsnamed.asp
shows how to combine the speed of getrows and simulate named fields using
dictionary objects.
In terms of why this is faster and
reduces server resource consumption,
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....)
"The Worlds Fastest Listbox"
http://www.learnasp.com/learn/speedappdata.asp
shows the only faster way to display databases.
Since this code relies heavily on arrays you may want to read up on them at:
1 <%@enablesessionstate=false%>
2 <%response.buffer=true%>
3 <html><head>
4 <TITLE>dbtablegetrows.asp</TITLE>
5 </head>
6 <body bgcolor="#FFFFFF">
7 <%
8 ' displays a database in table form via GetRows
9 myDSN="DSN=Student;uid=student;pwd=magic"
10 mySQL="select * from publishers where state='NY'"
11 showblank=" "
12 shownull="-null-"
13
14 set conntemp=server.createobject("adodb.connection")
15 conntemp.open myDSN
16 set rstemp=conntemp.execute(mySQL)
17 If rstemp.eof then
18 response.write "No records matched<br>"
19 response.write mySQL & "<br>So cannot make table..."
20 Call CloseAll
21 response.end
22 end if
23
24 response.write "<table border='1'><tr>" & vbcrlf
25 'Put Headings On The Table of Field Names
26 for each whatever in rstemp.fields
27 response.write "<td><b>" & whatever.name & "</B></TD>" & vbcrlf
28 next
29 response.write "</tr>" & vbcrlf
30
31 ' Now lets grab all the records
32 alldata=rstemp.getrows
33 Call CloseAll
34
35 numcols=ubound(alldata,1)
36 numrows=ubound(alldata,2)
37 FOR rowcounter= 0 TO numrows
38 response.write "<tr>" & vbcrlf
39 FOR colcounter=0 to numcols
40 thisfield=alldata(colcounter,rowcounter)
41 if isnull(thisfield) then
42 thisfield=shownull
43 end if
44 if trim(thisfield)="" then
45 thisfield=showblank
46 end if
47 response.write "<td valign=top>"
48 response.write thisfield
49 response.write "</td>" & vbcrlf
50 NEXT
51 response.write "</tr>" & vbcrlf
52 NEXT
53 response.write "</table>"
54 %>
55 </body></html>
56 <%
57 SUB CloseAll
58 rstemp.close
59 set rstemp=nothing
60 conntemp.close
61 set conntemp=nothing
62 END SUB
63 %>
64
GetRows NOT BY THE Numbers by Charles Carroll
Getrows Rocks! It is
lightning fast and much more scalable than the .MOVENEXT approach. See a
complete explanation @
http://www.learnasp.com/advice/whygetrows.asp
Tired of accessing a getrows array by number? There is an easier way we show here below*. But below is the most straightforward ways to use names instead of numbers with a Getrows array.
* and an easier ENCAPSULATED way (easy to use,
complex source code) at:
http://www.learnasp.com/learn/getrowsultimate.asp
1 <%@enablesessionstate=false%>
2 <%response.buffer=true%>
3 <html><head>
4 <TITLE>dbtablegetrowsnonum.asp</TITLE>
5 </head>
6 <body bgcolor="#FFFFFF">
7 <%
8 ' displays a database in table form via GetRows
9 myDSN="DSN=Student;uid=student;pwd=magic"
10 'mySQL="select PubID, [Company Name], Address, City, State, Zip, Telephone, Fax, Comments "
11 ' above statement fails because of [company name] still researching why....
12 mySQL="select * "
13 mySQL=mySQL & " from publishers"
14 mySQL=mySQL & " where state='NY'"
15 set conntemp=server.createobject("adodb.connection")
16 conntemp.open myDSN
17 set rstemp=conntemp.execute(mySQL)
18 response.write rstemp(2).name
19
20 If rstemp.eof then
21 response.write "No records matched<br>"
22 response.write mySQL & "<br>So cannot make table..."
23 Call CloseAll
24 response.end
25 end if
26
27 response.write "<table border='1'><tr>" & vbcrlf
28 'Put Headings On The Table of Field Names
29 for each whatever in rstemp.fields
30 response.write "<td><b>" & whatever.name & "</B></TD>" & vbcrlf
31 next
32 response.write "</tr>" & vbcrlf
33
34 ' Now lets grab all the records
35 alldata=rstemp.getrows
36 Call CloseAll
37
38 numrows=ubound(alldata,2)
39 fld_pubid=0
40 fld_Name=1
41 fld_companyname=2
42 fld_address=3
43 fld_city=4
44 fld_state=5
45 fld_zip=6
46 fld_telephone=7
47 fld_fax=8
48 fld_comments=9
49
50 FOR rowcounter= 0 TO numrows
51 response.write "<tr>" & vbcrlf
52 pubid=alldata(fld_pubid,rowcounter)
53 name=alldata(fld_name,rowcounter)
54 companyname=alldata(fld_companyname,rowcounter)
55 address=alldata(fld_address,rowcounter)
56 city=alldata(fld_city,rowcounter)
57 state=alldata(fld_state,rowcounter)
58 zip=alldata(fld_zip,rowcounter)
59 telephone=alldata(fld_telephone,rowcounter)
60 fax=alldata(fld_fax,rowcounter)
61 comments=alldata(fld_comments,rowcounter)
62
63 pubid=cleanfield(pubid)
64 response.write "<td valign=top>" & pubid & "</td>" & vbcrlf
65
66 name=cleanfield(name)
67 response.write "<td valign=top>" & name & "</td>" & vbcrlf
68
69 companyname=cleanfield(companyname)
70 response.write "<td valign=top>" & companyname & "</td>" & vbcrlf
71
72
73 companyname=cleanfield(address)
74 response.write "<td valign=top>" & address & "</td>" & vbcrlf
75
76 city=cleanfield(city)
77 response.write "<td valign=top>" & city & "</td>" & vbcrlf
78
79 state=cleanfield(state)
80 response.write "<td valign=top>" & state & "</td>" & vbcrlf
81
82 zip=cleanfield(zip)
83 response.write "<td valign=top>" & zip & "</td>" & vbcrlf
84
85 telephone=cleanfield(telephone)
86 response.write "<td valign=top>" & telephone & "</td>" & vbcrlf
87
88 fax=cleanfield(fax)
89 response.write "<td valign=top>" & fax & "</td>" & vbcrlf
90
91 comments=cleanfield(comments)
92 response.write "<td valign=top>" & comments & "</td>" & vbcrlf
93
94 response.write "</tr>" & vbcrlf
95 NEXT
96 response.write "</table>"
97 %>
98 </body></html>
99 <%
100 SUB CloseAll
101 rstemp.close
102 set rstemp=nothing
103 conntemp.close
104 set conntemp=nothing
105 END SUB
106
107 FUNCTION CleanField(parm1)
108 cleanfield=parm1
109 if isnull(parm1) then
110 cleanfield=" "
111 end if
112 if trim(parm1)="" then
113 cleanfield=" "
114 end if
115 END FUNCTION
116 %>
117
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 <%@enablesessionstate=false%>
2 <%response.buffer=true%>
3 <!--#include virtual="/adovbs.inc"-->
4 <html><head>
5 <TITLE>dbtabledisconnected.asp</TITLE>
6 </head>
7 <body bgcolor="#FFFFFF">
8 <%
9 ' displays a database in table form via GetRows
10 myDSN="DSN=Student;uid=student;pwd=magic"
11 mySQL="select * from publishers where state='NY'"
12 showblank=" "
13 shownull="-null-"
14
15 set conntemp=server.createobject("adodb.connection")
16 conntemp.open myDSN
17 ' to disconnect a recordset it must be created explicitly
18 set rstemp=server.createobject("adodb.recordset")
19 rstemp.cursorlocation=aduseclient
20 rstemp.open mySQL,conntemp
21 ' this line below disconnects the recordset
22 set rstemp.activeconnection=nothing
23
24 If rstemp.eof then
25 response.write "No records matched<br>"
26 response.write mySQL & "<br>So cannot make table..."
27 rstemp.close
28 set rstemp=nothing
29 conntemp.close
30 set conntemp=nothing
31 response.end
32 end if
33
34 response.write "<table border='1'><tr>"
35 'Put Headings On The Table of Field Names
36 for each whatever in rstemp.fields
37 response.write "<td><b>" & whatever.name & "</B></TD>"
38 next
39 response.write "</tr>"
40 DO UNTIL rstemp.eof
41 response.write "<tr>"
42 for each whatever in rstemp.fields
43 thisfield=whatever.value
44 if isnull(thisfield) then
45 thisfield=shownull
46 end if
47 if trim(thisfield)="" then
48 thisfield=showblank
49 end if
50 response.write "<td valign=top>" & thisfield & "</td>"
51 next
52 response.write "</tr>"
53 rstemp.movenext
54 LOOP
55 response.write "</table>"
56 %>
57 </body></html>
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: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
Generic Database Display Made Easy
When you want a quick easy generic database
display, go on over to:
http://www.genericdb.com
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 ' Generic interface to the Northwinds Employee table.
3 Session("dbGenericPath") = "/learn/test/genericdb/"
4 Session("dbExitPage") = "http://www.activeserverpages.com"
5 Session("dbTitle") = "Pubs"
6 Session("dbType") = "SQL"
7 Session("dbConn") = "DSN=student;uid=student;pwd=magic"
8 Session("dbRs") = "Publishers"
9 Session("dbKey") = 1
10 Session("dbOrder") = 2
11 Session("dbRecsPerPage") = 10
12 Session("dbFooter") = 1
13 Session("dbDispList") = "011101000000100010"
14 Session("dbDispView") = "111111111111111111"
15 Session("dbDispEdit") = "011111111111111111"
16 Session("dbSearchFields") = "011100010010001000"
17 Session("dbDefault6") = Date()
18 Session("dbCombo11") = "LIST, ??, Unknown, CA, Canada, US, United States, DE, Denmark"
19 Session("dbDefault17") = 10
20 Session("dbWhere") = ""
21 Session("dbDebug") = 1
22 Session("dbCanEdit") = 1
23 Session("dbCanAdd") = 1
24 Session("dbCanDelete") = 1
25 Session("dbConfirmDelete") = 1
26 Session("dbViewPage") = Request.ServerVariables("PATH_INFO")
27 Response.Redirect Session("dbGenericPath") & "GenericList.asp"
28 %>
There is even a listserve
supporting this great FREE script collection @
http://www.asplists.com/asplists/aspgenericdb.asp
It is not a general database troubleshooting
list, instead only questions concerning these wonderful scripts are allowed.
Related Links:
Generic DB Sample @
http://www.learnasp.com/learn/genericdb.asp
Generic DB Main Page @
http://www.genericdb.com
Generic DB Tips @
http://squeek.tzo.com/genericdb
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
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 <html><head>
2 <TITLE>dbconvert.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 whichname="/upload/tests/authors.txt"
6 myDSN="DSN=Student;uid=student;pwd=magic"
7 mySQL="select * from authors where au_id<100"
8 showblank=""
9 shownull="<null>"
10 linestart=chr(34)
11 lineend=chr(34)
12 delimiter=chr(34) & "," & chr(34)
13 delimitersub=""
14
15 whichFN=server.mappath(whichname)
16
17 Set fstemp = server.CreateObject("Scripting.FileSystemObject")
18 Set filetemp = fstemp.CreateTextFile(whichFN, true)
19 ' true = file can be over-written if it exists
20 ' false = file CANNOT be over-written if it exists
21
22 set conntemp=server.createobject("adodb.connection")
23 conntemp.open myDSN
24 set rstemp=conntemp.execute(mySQL)
25
26 ' this code detects if data is empty
27 If rstemp.eof then
28 response.write "No data to convert for SQL statement<br>"
29 response.write mySQL & "<br>"
30 connection.close
31 set connection=nothing
32 response.end
33 end if
34
35 DO UNTIL rstemp.eof
36 thisline=linestart
37 for each whatever in rstemp.fields
38 thisfield=whatever.value
39 if isnull(thisfield) then
40 thisfield=shownull
41 end if
42 if trim(thisfield)="" then
43 thisfield=showblank
44 end if
45 thisfield=replace(thisfield,delimiter,delimitersub)
46 thisline=thisline & thisfield & delimiter
47 next
48 tempLen=len(thisline)
49 tempLenDelim=len(delimiter)
50 thisline=mid(thisline,1,tempLEN-tempLenDelim) & lineend
51 filetemp.WriteLine(thisline)
52 ' response.write thisline & "<br>"
53 rstemp.movenext
54 LOOP
55 filetemp.Close
56 set filetemp=nothing
57 set fstemp=nothing
58 rstemp.close
59 set rstemp=nothing
60 conntemp.close
61 set conntemp=nothing
62
63
64
65 If err.number=0 then
66 response.write "File was converted sucessfully!<br>"
67 response.write "Converted file is at <a href='"
68 response.write whichname & "'>" & whichname & "</a>"
69 else
70 response.write "VBScript Errors Occured!<br>"
71 response.write "Error Number=#<b>" & err.number & "</b><br>"
72 response.write "Error Desc. =<b>" & err.description & "</b><br>"
73 response.write "Help Path =<b>" & err.helppath & "</b><br>"
74 response.write "Native Error=<b>" & err.nativeerror & "</b><br>"
75 response.write "Error Source =<b>" & err.source & "</b><br>"
76 response.write "SQL State=#<b>" & err.sqlstate & "</b><br>"
77 end if
78
79
80 %>
81 </body></html>
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>Now here is a script that will delete all the records the above script added:
1 <TITLE>dbdeletemany.asp</TITLE>The error trapping library looks like this:
1 <%
2 SUB ErrorVBScriptReport(parm_msg)
3 If err.number=0 then
4 exit sub
5 end if
6 pad=" "
7 response.write "<b>VBScript Errors Occured!<br>"
8 response.write parm_msg & "</b><br>"
9 response.write pad & "Error Number= #<b>" & err.number & "</b><br>"
10 response.write pad & "Error Desc.= <b>" & err.description & "</b><br>"
11 response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>"
12 response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>"
13 response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>"
14 END SUB
15
16 SUB ErrorADOReport(parm_msg,parm_conn)
17 HowManyErrs=parm_conn.errors.count
18 IF HowManyErrs=0 then
19 exit sub
20 END IF
21 pad=" "
22 response.write "<b>ADO Reports these Database Error(s) executing:<br>"
23 response.write SQLstmt & "</b><br>"
24 for counter= 0 to HowManyErrs-1
25 errornum=parm_conn.errors(counter).number
26 errordesc=parm_conn.errors(counter).description
27 response.write pad & "Error#=<b>" & errornum & "</b><br>"
28 response.write pad & "Error description=<b>"
29 response.write errordesc & "</b><p>"
30 next
31 END SUB
32 %>
Access Scalability Notes by Charles Carroll
This page demonstrates how many Access connections can be opened by one script. Testing generally indicates a single script can only initiate 64 connections. Microsoft Tech Support has suggested a 255 limit easily disproved by this script. As a point of reference I ran this same script against a SQL7 data source and attempted 2,550 connections. All were sucessful.
Access has the following limitations:
1. Access is STA (single-threaded-apartment), NOT
MTA or Free-Threaded (see http://www.learnasp.com/advice/threads.asp
for thread basics). What this means is that all database requests are
serialized, i.e.
user1 asks for 100 records
user2 asks for 2 records
user3 asks for 5000 records
user4 asks for 3 records
If an agile back-end (free-threaded or MTA for example SQLserver, Oracle, etc.)
was handling those requests it could send user2 and user4 records before dealing
with other requests. Access cannot. User 4 will receive their data AFTER the
other requests have completed. Requests are handled as they come in and to
completion before next low-level data access starts. So the application's
pattern of retrieval makes a huge difference in whether an Access app will
scale.
2. Since open connections are the issue and scripts run round-robin, see: http://www.learnasp.com/advice/roundrobin.asp (see advice about open late/close early) http://www.learnasp.com/advice/whybuffer.asp http://www.learnasp.com/advice/whygetrows.asp are EXTREMELY relevant in this case.
3. Access unfortunately does not support
connection pooling which can dramatically improve performance, see:
http://www.learnasp.com/learn/dbpooling.asp
4. The free answer to this problem is MSDE, a
chopped down version of SQLserver that Microsoft gives away which can handle
much more load, see:
http://msdn.microsoft.com/vstudio/msde/
Additional Note: ODBC connections are very flaky producing a
variety of run-time error messages that OLEDB connections do not. This
sample uses an OLEDB connection hence it's "microsoft.jet.oledb...."
vs. a connection string that contains "{microsoft access...}". The
latter connection string/ODBC connection is far less reliable. See:
http://www.learnasp.com/learn/dbopen.asp
for more connection string info. For example:
[Microsoft][ODBC Microsoft Access Driver]General error
Unable to open registry key 'Temporary (volatile) Jet DSN for process 0xda8
Thread 0x49c DBC 0x254d024 Jet'. occurs when connecting to data with
"{microsoft access..." connection string whereas exactly the same data
can be accessed with "Jet.oledb" string fine.
1 <HTML><HEAD><TITLE>accesstest.asp</TITLE></HEAD>
2 <body bgcolor="#FFFFFF">
3 <%
4 on error resume next
5 myconn = "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" & server.mappath("nwind.mdb") & ";"
6 ' the above string is recommended way to connect
7 ' myconn = "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.mappath("nwind.mdb") & ";"
8 ' the above connect string is VERY flaky
9 dim test(256)
10 dim errn(256)
11 dim errd(256)
12 for counter=1 to 255
13 set test(counter)=server.createobject("adodb.connection")
14 goodconn=true
15 test(counter).open myconn
16 ' have to test error here because if conn cant be created
17 ' the errcount... line will fail
18 vbserror=err.number
19 errcount=test(counter).errors.count
20 IF errcount>0 then
21 DBErrNum=test(counter).errors(0).number
22 DBErrDes=test(counter).errors(0).description
23 errn(counter)=DBErrNum
24 errd(counter)="ADO: " & DBErrDes
25 goodconn=false
26 END IF
27
28 ' VBScript Error Trap
29 IF vbserror<>0 THEN
30 errn(counter)=vbserror
31 errd(counter)="VBS: " & err.description
32 goodconn=false
33 END IF
34 If goodconn=true THEN
35 errn(counter)=0
36 success=success+1
37 END IF
38 response.flush
39 NEXT
40 for counter=1 to 255
41 test(counter).close
42 set test(counter)=nothing
43 next
44 response.write "Successful connections=" & success & "<br>"
45
46 for counter = 1 To 255
47 errnum=errn(counter)
48 IF errnum<>0 THEN
49 response.write "#" & counter & " connection failed:"
50 response.write errd(counter) & "<br>"
51 END IF
52 next
53 %>
54 </BODY></HTML>
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 <html><head>
2 <TITLE>dbtablepaged.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <!--#INCLUDE VIRTUAL="/ADOVBS.INC" -->
5 <%
6 connectme="DSN=Student;uid=student;pwd=magic"
7 sqltemp="select * from publishers"
8
9 ' Troubleshooting TIP:
10 ' if you use this code and get an error, for example:
11 '
12 ' ADODB.Recordset error 800a0cb3
13 '
14 ' The operation requested by the application is not
15 ' supported by the provider.
16 '
17 ' You may have a driver that is out of date, see:
18 ' http://www.learnasp.com/learn/connectioninfo.asp
19 ' for code that will identify what your driver version is
20 ' this script works with Access, SQLserver and Oracle
21 ' with up-to-date drivers
22
23 If aduseclient="" THEN
24 ref="http://www.learnasp.com/adovbs.inc"
25 response.write "You forgot to include:<br>"
26 response.write "/adovbs.inc<br>"
27 response.write "Get the file from <a href='" & ref & "'>" & ref & "<br>"
28 response.end
29 END IF
30
31 mypage=request("whichpage")
32 If mypage="" then
33 mypage=1
34 end if
35 mypagesize=request("pagesize")
36 If mypagesize="" then
37 mypagesize=10
38 end if
39 mySQL=request("SQLquery")
40 IF mySQL="" THEN
41 mySQL=SQLtemp
42 END IF
43
44 set rstemp=Server.CreateObject("ADODB.Recordset")
45 rstemp.cursorlocation=aduseclient
46 rstemp.cachesize=5
47 tempSQL=lcase(mySQL)
48 badquery=false
49 IF instr(tempSQL,"delete")>0 THEN
50 badquery=true
51 END IF
52 IF instr(tempSQL,"insert")>0 THEN
53 badquery=true
54 END IF
55 IF instr(tempSQL,"update")>0 THEN
56 badquery=true
57 END IF
58 If badquery=true THEN
59 response.write "Not a SELECT Statement<br>"
60 response.end
61 END IF
62
63 rstemp.open mySQL,connectme
64 rstemp.movefirst
65 rstemp.pagesize=mypagesize
66 maxpages=cint(rstemp.pagecount)
67 maxrecs=cint(rstemp.pagesize)
68 rstemp.absolutepage=mypage
69 howmanyrecs=0
70 howmanyfields=rstemp.fields.count -1
71 response.write "Page " & mypage & " of " & maxpages & "<br>"
72 response.write "<table border='1'><tr>"
73
74 'Put Headings On The Table of Field Names
75 FOR i=0 to howmanyfields
76 response.write "<td><b>" & rstemp(i).name & "</b></td>"
77 NEXT
78 response.write "</tr>"
79
80 ' Now loop through the data
81 DO UNTIL rstemp.eof OR howmanyrecs>=maxrecs
82 response.write "<tr>"
83 FOR i = 0 to howmanyfields
84 fieldvalue=rstemp(i)
85 If isnull(fieldvalue) THEN
86 fieldvalue="n/a"
87 END IF
88 If trim(fieldvalue)="" THEN
89 fieldvalue=" "
90 END IF
91 response.write "<td valign='top'>"
92 response.write fieldvalue
93 response.write "</td>"
94 next
95 response.write "</tr>"
96 rstemp.movenext
97 howmanyrecs=howmanyrecs+1
98 LOOP
99 response.write "</table><p>"
100
101 ' close, destroy
102 rstemp.close
103 set rstemp=nothing
104
105 ' Now make the page _ of _ hyperlinks
106 Call PageNavBar
107
108 sub PageNavBar()
109 ' Thanks to Jeff Emrich <jeff.emrich@datafuse.com>
110 pad=""
111 scriptname=request.servervariables("script_name")
112 response.write "<table rows='1' cols='1' width='97%'><tr>"
113 response.write "<td>"
114 response.write "<font size='2' color='black' face='Verdana, Arial,Helvetica, sans-serif'>"
115 if (mypage mod 10) = 0 then
116 counterstart = mypage - 9
117 else
118 counterstart = mypage - (mypage mod 10) + 1
119 end if
120 counterend = counterstart + 9
121 if counterend > maxpages then counterend = maxpages
122 if counterstart <> 1 then
123 ref="<a href='" & scriptname
124 ref=ref & "?whichpage=" & 1
125 ref=ref & "&pagesize=" & mypagesize
126 ref=ref & "&sqlQuery=" & server.URLencode(mySQL)
127 ref=ref & "'>First</a> : "
128 Response.Write ref
129
130
131 ref="<a href='" & scriptname
132 ref=ref & "?whichpage=" & (counterstart - 1)
133 ref=ref & "&pagesize=" & mypagesize
134 ref=ref & "&sqlQuery=" & server.URLencode(mySQL)
135 ref=ref & "'>Previous</a> "
136 Response.Write ref
137 end if
138 Response.Write "["
139 for counter=counterstart to counterend
140 If counter>=10 then
141 pad=""
142 end if
143 if cstr(counter) <> mypage then
144 ref="<a href='" & scriptname
145 ref=ref & "?whichpage=" & counter
146 ref=ref & "&pagesize=" & mypagesize
147 ref=ref & "&sqlQuery=" & server.URLencode(mySQL)
148 ref=ref & "'>" & pad & counter & "</a>"
149 else
150 ref="<b>" & pad & counter & "</b>"
151 end if
152 response.write ref
153 if counter <> counterend then response.write " "
154 next
155 Response.Write "]"
156 if counterend <> maxpages then
157 ref=" <a href='" & scriptname
158 ref=ref & "?whichpage=" & (counterend + 1)
159 ref=ref & "&pagesize=" & mypagesize
160 ref=ref & "&sqlQuery=" & server.URLencode(mySQL)
161 ref=ref & "'>Next</a>"
162 Response.Write ref
163
164
165 ref=" : <a href='" & scriptname
166 ref=ref & "?whichpage=" & maxpages
167 ref=ref & "&pagesize=" & mypagesize
168 ref=ref & "&sqlQuery=" & server.URLencode(mySQL)
169 ref=ref & "'>Last</a>"
170 Response.Write ref
171 end if
172 response.write "<br></font>"
173 response.write "</td>"
174 response.write "</table>"
175 end sub
176 %>
177 </body></html>
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 <html><head>
2 <TITLE>dbmaxrecs.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <!--#INCLUDE VIRTUAL="/ADOVBS.INC" -->
5 <%
6 set rstemp=Server.CreateObject("adodb.Recordset")
7 rstemp.maxrecords=15
8 connectme="DSN=Student;uid=student;pwd=magic"
9 rstemp.open "select * from titles", _
10 connectme,adopenstatic
11 ' table display
12 howmanyfields=rstemp.fields.count -1
13 %>
14 <table border=1><tr>
15 <%
16 for i=0 to howmanyfields %>
17 <td><b><%=rstemp(i).name %></B></TD>
18 <% next %>
19 </tr>
20 <%
21 do while not rstemp.eof %>
22 <tr>
23 <% for i = 0 to howmanyfields%>
24 <td valign=top><% = rstemp.fields(i).value %> </td>
25 <% next %>
26 </tr>
27 <%
28 rstemp.movenext
29 loop
30 rstemp.close
31 set rstemp=nothing
32 %>
33 </table></body></html>
Count 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 cursor type is AdOpenforwardonly (see below for explanation of all cursor types). Here is the script that counts the query results and WILL NOT return -1:
1 <head><html>
2 <TITLE>dbcount.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <!--#INCLUDE VIRTUAL="/ADOVBS.INC" -->
5 <%
6 ' change these for your site
7 connectme="DSN=Student;uid=student;pwd=magic"
8 sqltemp="select * from publishers where state='NY'"
9 set rstemp=Server.CreateObject("adodb.Recordset")
10 rstemp.open sqltemp, connectme, adopenstatic
11 howmanyrecs=rstemp.recordcount
12 response.write howmanyrecs & " records in<br>" & sqltemp
13 rstemp.close
14 set rstemp=nothing
15 %>
16 </body></html>
17
The critical part here is having a cursor type that supports it (Adopenforward only is the default cursor type and it does NOT support counting records) and including adovbs.inc to define the cursor types. The file adovbs.inc can be obtained from http://www.learnasp.com/adovbs.inc
If you open the database and are able to obtain an accurate record count is by nature a slower connection; it is a burden on a recordset that it must know exact record counts upon demand. The additional overhead and limitations of a adopendynamic or adopenstatic cursor may be a glacially slow way to retrieve the data even though they count accurately. If you must count AND retrieve, you can't go wrong using GetRows (see http://www.learnasp.com/learn/dbtablegetrow.asp) because:
Here is a description of the significance of each cursor type:
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.
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 Static AbsolutePage N/A N/A R/W R/W AbsolutePosition N/A N/A R/W R/W ActiveConnection R/W R/W R/W R/W BOF R/O R/O R/O R/O Bookmark N/A N/A R/W R/W CacheSize R/W R/W R/W R/W CursorLocation R/W R/W R/W R/W CursorType R/W R/W R/W R/W EditMode R/O R/O R/O R/O EOF R/O R/O R/O R/O Filter R/W R/W R/W R/W LockType R/W R/W R/W R/W MarshalOptions R/W R/W R/W R/W MaxRecords R/W R/W R/W R/W PageCount N/A N/A R/O R/O PageSize R/W R/W R/W R/W RecordCount N/A N/A R/O R/O Source R/W R/W R/W R/W State R/O R/O R/O R/O Status R/O R/O R/O R/O Method AddNew Yes Yes Yes Yes CancelBatch Yes Yes Yes Yes CancelUpdate Yes Yes Yes Yes Clone N/A N/A Yes Yes Close Yes Yes Yes Yes Delete Yes Yes Yes Yes GetRows Yes Yes Yes Yes Move Yes Yes Yes Yes MoveFirst Yes Yes Yes Yes MoveLast N/A Yes Yes Yes MoveNext Yes Yes Yes Yes MovePrevious N/A Yes Yes Yes NextRecordset Yes Yes Yes Yes Open Yes Yes Yes Yes Requery Yes Yes Yes Yes Resync N/A N/A Yes Yes Supports Yes Yes Yes Yes Update Yes Yes Yes Yes UpdateBatch Yes Yes Yes Yes Legend:
R/W = Read/Write
R/O = Read-Only
N/A = Not Available or Supported
Yes = Available/Supported
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 <html><head>
2 <title>dbnewrec.asp</title>&
3 <body bgcolor="#FFFFFF">
4 <% ' My ASP program that allows you to append a record %>
5 <form name="myauthor" action="dbnewrecSQL.asp" method="GET">
6 <p>Author ID: <input type="TEXT" name="id"></p>
7 <p> Author Name: <input type="TEXT" name="name"></p>
8 <p> Year Born: <input type="TEXT" name="year"></p>
9 <p> <input type="SUBMIT"> </p>
10 </form></body></html>
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 Script Below>
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>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 <html><head>
2 <title>dbnewrec.asp</title>&
3 <body bgcolor="#FFFFFF">
4 <% ' My ASP program that allows you to append a record %>
5 <form name="myauthor" action="dbnewADOrespond.asp" method="GET">
6 <p>Author ID: <input type="TEXT" name="id"></p>
7 <p> Author Name: <input type="TEXT" name="name"></p>
8 <p> Year Born: <input type="TEXT" name="year"></p>
9 <p> <input type="SUBMIT"> </p>
10 </form></body></html>
The form responder looks like this:
1 <TITLE>dbnewADO.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <HTML>
4 <!--#INCLUDE VIRTUAL="/ADOVBS.INC" -->
5 <!--#INCLUDE VIRTUAL="/learn/test/lib_errors.asp" -->
6 <%
7 on error resume next
8 auname=request.querystring("name")
9 auyear=request.querystring("year")
10 auID=request.querystring("ID")
11 If auid<9000 then
12 auid=auid+9000
13 end if
14 conn="DSN=Student;uid=student;pwd=magic"
15 Set RS = Server.CreateObject("ADODB.Recordset")
16 RS.Open "authors",Conn,adopenstatic,adlockoptimistic
17 RS.AddNew
18 'RS("AU_ID")=auid
19 RS("Author") = auname
20 RS("Year_Born")= int(auyear)
21 RS.Update
22 Call ErrorVBscriptReport("Adding Record")
23 Call ErrorADOReport("Adding Record",RS.activeconnection)
24 RS.Close
25 set rs=nothing
26 %>
27 </BODY>
28 </HTML>
29
30
31
32
Here is the include file that displays appropriate errors:
1 <%
2 SUB ErrorVBScriptReport(parm_msg)
3 If err.number=0 then
4 exit sub
5 end if
6 pad=" "
7 response.write "<b>VBScript Errors Occured!<br>"
8 response.write parm_msg & "</b><br>"
9 response.write pad & "Error Number= #<b>" & err.number & "</b><br>"
10 response.write pad & "Error Desc.= <b>" & err.description & "</b><br>"
11 response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>"
12 response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>"
13 response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>"
14 END SUB
15
16 SUB ErrorADOReport(parm_msg,parm_conn)
17 HowManyErrs=parm_conn.errors.count
18 IF HowManyErrs=0 then
19 exit sub
20 END IF
21 pad=" "
22 response.write "<b>ADO Reports these Database Error(s) executing:<br>"
23 response.write SQLstmt & "</b><br>"
24 for counter= 0 to HowManyErrs-1
25 errornum=parm_conn.errors(counter).number
26 errordesc=parm_conn.errors(counter).description
27 response.write pad & "Error#=<b>" & errornum & "</b><br>"
28 response.write pad & "Error description=<b>"
29 response.write errordesc & "</b><p>"
30 next
31 END SUB
32 %>
Listing Tables within Databases by Charles Carroll DRAFT
SQL Server allows you to list tables like this:
1 <HEAD><TITLE>sqlservertablelist.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 whichDSN="DSN=student;uid=student;pwd=magic"
5
6 call query2table("select name,type from sysobjects where type='U'", whichDSN)
7 %>
8 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
9 </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 <HEAD><TITLE>accesstablelist.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 whichDSN="DRIVER={Microsoft Access Driver (*.mdb)}; "
5 whichDSN=whichDSN & "DBQ=" & server.mappath("/learn/test/biblio.mdb")
6 call query2table("select * from MsysObjects WHERE type = 1",whichDSN)
7 %>
8 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
9 </BODY></HTML>
The Include file 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%>
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 <TITLE>dbschemas.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <!--#INCLUDE VIRTUAL="/ADOVBS.INC" -->
6 <!--#INCLUDE VIRTUAL="/learn/test/lib_fieldtypes.asp" -->
7 <%
8 myDSN="DSN=Student;uid=student;pwd=magic"
9
10 set conntemp=server.createobject("adodb.connection")
11 conntemp.open myDSN
12
13 Set rsSchema = conntemp.OpenSchema(adSchemaColumns)
14 thistable=""
15 pad=" "
16 DO UNTIL rsSchema.EOF
17 prevtable=thistable
18 thistable=rsSchema("Table_Name")
19 thiscolumn=rsSchema("COLUMN_NAME")
20 IF thistable<>prevtable THEN
21 response.write "Table=<b>" & thistable & "</b><br>"
22 response.write "TABLE_CATALOG=<b>" & rsSchema("TABLE_CATALOG") & "</b><br>"
23 response.write "TABLE_SCHEMA=<b>" & rsSchema("TABLE_SCHEMA") & "</b><p>"
24 END IF
25 response.write "<br>" & pad & "Field=<b>" & thiscolumn & "</b><br>"
26 response.write pad & "Type=<b>" & fieldtypename(rsSchema("DATA_TYPE")) & "</b><br>"
27
28
29 DIM colschema(27)
30 colschema(0)="TABLE_CATALOG"
31 colschema(1)="TABLE_SCHEMA"
32 colschema(2)="TABLE_NAME"
33 colschema(3)="COLUMN_NAME"
34 colschema(4)="COLUMN_GUID"
35 colschema(5)="COLUMN_PROP_ID"
36 colschema(6)="ORDINAL_POSITION"
37 colschema(7)="COLUMN_HASDEFAULT"
38 colschema(8)="COLUMN_DEFAULT"
39 colschema(9)="COLUMN_FLAGS"
40 colschema(10)="IS_NULLABLE"
41 colschema(11)="DATA_TYPE"
42 colschema(12)="TYPE_GUID"
43 colschema(13)="CHARACTER_MAXIMUM_LENGTH"
44 colschema(14)="CHARACTER_OCTET_LENGTH"
45 colschema(15)="NUMERIC_PRECISION"
46 colschema(16)="NUMERIC_SCALE"
47 colschema(17)="DATETIME_PRECISION"
48 colschema(18)="CHARACTER_SET_CATALOG"
49 colschema(19)="CHARACTER_SET_SCHEMA"
50 colschema(20)="CHARACTER_SET_NAME"
51 colschema(21)="COLLATION_CATALOG"
52 colschema(22)="COLLATION_SCHEMA"
53 colschema(23)="COLLATION_NAME"
54 colschema(24)="DOMAIN_NAME"
55 colschema(25)="DOMAIN_CATALOG"
56 colschema(26)="DOMAIN_SCHEMA"
57 colschema(27)="DESCRIPTION"
58
59 ON ERROR RESUME NEXT
60 FOR counter=4 to 27
61 thisColInfoType=colschema(counter)
62 thisColInfo=rsSchema(thisColInfoType)
63 If err.number<>0 then
64 thiscolinfo="-error-"
65 err.clear
66 END IF
67 IF thisColInfo<>"" THEN
68 response.write pad & pad & pad & thiscolinfotype
69 response.write "=<b>" & thiscolinfo & "</b><br>"
70 END IF
71 NEXT
72 response.flush
73 rsSchema.MoveNext
74 LOOP
75
76 rsSchema.Close
77 set rsSchema=nothing
78
79 conntemp.close
80 set conntemp=nothing
81 %>
82 </body></html>
Here is the contents of lib_fieldtypes.asp which is included to make this example work:
1 <%
2 FUNCTION fieldtypename(parm1)
3 SELECT CASE Parm1
4 CASE 0
5 fieldtypename="adEmpty"
6 CASE 16
7 fieldtypename="adTinyInt"
8 CASE 2
9 fieldtypename="adSmallInt"
10 CASE 3
11 fieldtypename="adInteger"
12 CASE 20
13 fieldtypename="adBigInt"
14 CASE 17
15 fieldtypename="adUnsignedTinyInt"
16 CASE 18
17 fieldtypename="adUnsignedSmallInt"
18 CASE 19
19 fieldtypename="adUnsignedInt"
20 CASE 21
21 fieldtypename="adUnsignedBigInt"
22 CASE 4
23 fieldtypename="adSingle"
24 CASE 5
25 fieldtypename="adDouble"
26 CASE 6
27 fieldtypename="adCurrency"
28 CASE 14
29 fieldtypename="adDecimal"
30 CASE 131
31 fieldtypename="adNumeric"
32 CASE 11
33 fieldtypename="adBoolean"
34 CASE 10
35 fieldtypename="adError"
36 CASE 132
37 fieldtypename="adUserDefined"
38 CASE 12
39 fieldtypename="adVariant"
40 CASE 9
41 fieldtypename="adIDispatch"
42 CASE 13
43 fieldtypename="adIUnknown"
44 CASE 72
45 fieldtypename="adGUID"
46 CASE 7
47 fieldtypename="adDate"
48 CASE 133
49 fieldtypename="adDBDate"
50 CASE 134
51 fieldtypename="adDBTime"
52 CASE 135
53 fieldtypename="adDBTimeStamp"
54 CASE 8
55 fieldtypename="adBSTR"
56 CASE 129
57 fieldtypename="adChar"
58 CASE 200
59 fieldtypename="adVarChar"
60 CASE 201
61 fieldtypename="adLongVarChar"
62 CASE 130
63 fieldtypename="adWChar"
64 CASE 202
65 fieldtypename="adVarWChar"
66 CASE 203
67 fieldtypename="adLongVarWChar"
68 CASE 128
69 fieldtypename="adBinary"
70 CASE 204
71 fieldtypename="adVarBinary"
72 CASE 205
73 fieldtypename="adLongVarBinary"
74 CASE ELSE
75 fieldtypename="Undefined by ADO"
76 END SELECT
77 END FUNCTION
78 %>
ADO Schemas/listing tables and fields
You can examine a Schema for the table names and column names and column detail information.
1 <html><head>
2 <TITLE>dbschemasall.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <!--#INCLUDE VIRTUAL="/ADOVBS.INC" -->
6 <!--#INCLUDE VIRTUAL="/learn/test/lib_schemas.asp" -->
7 <%
8 myDSN="DSN=Student;uid=student;pwd=magic"
9
10 DIM colschema(30)
11 colschema(0)=adSchemaProviderSpecific
12 colschema(1)=adSchemaAsserts
13 colschema(2)=adSchemaCatalogs
14 colschema(3)=adSchemaCharacterSets
15 colschema(4)=adSchemaCollations
16 colschema(5)=adSchemaColumns
17 colschema(6)=adSchemaCheckConstraints
18 colschema(7)=adSchemaConstraintColumnUsage
19 colschema(8)=adSchemaConstraintTableUsage
20 colschema(9)=adSchemaKeyColumnUsage
21 colschema(10)=adSchemaReferentialContraints
22 colschema(11)=adSchemaTableConstraints
23 colschema(12)=adSchemaColumnsDomainUsage
24 colschema(13)= adSchemaIndexes
25 colschema(14)=adSchemaColumnPrivileges
26 colschema(15)=adSchemaTablePrivileges
27 colschema(16)=adSchemaUsagePrivileges
28 colschema(17)=adSchemaProcedures
29 colschema(18)=adSchemaSchemata
30 colschema(19)=adSchemaSQLLanguages
31 colschema(20)=adSchemaStatistics
32 colschema(21)=adSchemaTables
33 colschema(22)=adSchemaTranslations
34 colschema(23)=adSchemaProviderTypes
35 colschema(24)=adSchemaViews
36 colschema(25)=adSchemaViewColumnUsage
37 colschema(26)=adSchemaViewTableUsage
38 colschema(27)=adSchemaProcedureParameters
39 colschema(28)=adSchemaForeignKeys
40 colschema(29)=adSchemaPrimaryKeys
41 colschema(30)=adSchemaProcedureColumns
42
43 FOR counter=1 to 30
44 thisSchema=colSchema(counter)
45 Call Schema2Table(myDSN,thisSchema)
46 response.write "<p>"
47 NEXT
48 %>
49 </body></html>
The include file lib_schemas.asp looks like this:
1 <%
2 FUNCTION schemaName(parm1)
3 SELECT CASE parm1
4 CASE adSchemaProviderSpecific
5 schemaname="adSchemaProviderSpecific"
6 CASE adSchemaAsserts
7 schemaName="adSchemaAsserts"
8 CASE adSchemaCatalogs
9 schemaName="adSchemaCatalogs"
10 CASE adSchemaCharacterSets
11 schemaName="adSchemaCharacterSets"
12 CASE adSchemaCollations
13 schemaName="adSchemaCollations"
14 CASE adSchemaColumns
15 schemaName="adSchemaColumns"
16 CASE adSchemaCheckConstraints
17 schemaName="adSchemaCheckConstraints"
18 CASE adSchemaConstraintColumnUsage
19 schemaName="adSchemaConstraintColumnUsage"
20 CASE adSchemaConstraintTableUsage
21 schemaName="adSchemaConstraintTableUsage"
22 CASE adSchemaKeyColumnUsage
23 schemaName="adSchemaKeyColumnUsage"
24 CASE adSchemaReferentialContraints
25 schemaName="adSchemaReferentialContraints"
26 CASE adSchemaTableConstraints
27 schemaName="adSchemaTableConstraints"
28 CASE adSchemaColumnsDomainUsage
29 schemaName="adSchemaColumnsDomainUsage"
30 CASE adSchemaIndexes
31 schemaName="adSchemaIndexes"
32 CASE adSchemaColumnPrivileges
33 schemaName="adSchemaColumnPrivileges"
34 CASE adSchemaTablePrivileges
35 schemaName="adSchemaTablePrivileges"
36 CASE adSchemaUsagePrivileges
37 schemaName="adSchemaUsagePrivileges"
38 CASE adSchemaProcedures
39 schemaName="adSchemaProcedures"
40 CASE adSchemaSchemata
41 schemaName="adSchemaSchemata"
42 CASE adSchemaSQLLanguages
43 schemaName="adSchemaSQLLanguages"
44 CASE adSchemaStatistics
45 schemaName="adSchemaStatistics"
46 CASE adSchemaTables
47 schemaName="adSchemaTables"
48 CASE adSchemaTranslations
49 schemaName="adSchemaTranslations"
50 CASE adSchemaProviderTypes
51 schemaName="adSchemaProviderTypes"
52 CASE adSchemaViews
53 schemaName="adSchemaViews"
54 CASE adSchemaViewColumnUsage
55 schemaName="adSchemaViewColumnUsage"
56 CASE adSchemaViewTableUsage
57 schemaName="adSchemaViewTableUsage"
58 CASE adSchemaProcedureParameters
59 schemaName="adSchemaProcedureParameters"
60 CASE adSchemaForeignKeys
61 schemaName="adSchemaForeignKeys"
62 CASE adSchemaPrimaryKeys
63 schemaName="adSchemaPrimaryKeys"
64 CASE adSchemaProcedureColumns
65 schemaName="adSchemaProcedureColumns"
66 CASE ELSE
67 schemaName="-unknown-"
68 END SELECT
69 END FUNCTION
70
71 SUB Schema2Table(parmDSN, parmSchemaName)
72 set conntemp=server.createobject("adodb.connection")
73 conntemp.open parmDSN
74
75 on error resume next
76 set rsSchema=conntemp.OpenSchema(parmSchemaName)
77
78 IF err.number=3251 THEN
79 response.flush
80 response.write "<b>" & SchemaName(parmSchemaName)
81 response.write "</b><br> is not supported<br>"
82 err.clear
83 ELSE
84 Call Schema2Table(thisSchema)
85 response.write "<P><b>" & schemaName(parmSchemaName) & "</b><br>"
86 response.write "<table border=1><tr>"
87 'Put Headings On The Table of Field Names
88 for each whatever in rsSchema.fields
89 response.write "<td><b>" & whatever.name & "</b></td>"
90 next
91 response.write "</tr>"
92 DO UNTIL rsSchema.eof
93 response.write "<tr>"
94 for each whatever in rsSchema.fields
95 thisfield=whatever.value
96 if isnull(thisfield) then
97 thisfield=" "
98 end if
99 if trim(thisfield)="" then
100 thisfield=" "
101 end if
102 response.write "<td valign=top>" & thisfield & "</td>"
103 next
104 response.write "</tr>"
105 rsSchema.MoveNext
106 LOOP
107 response.write "</table><br>"
108 response.flush
109 END IF
110
111 rsSchema.Close
112 set rsSchema=nothing
113
114 conntemp.close
115 set conntemp=nothing
116 END SUB
117 %>
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 <TITLE>db1parm.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <%
4 ' My ASP program that talks to a database
5 set conntemp=server.createobject("adodb.connection")
6 conntemp.open "DSN=Student;uid=student;pwd=magic"
7 p1=request.querystring("ID")
8 temp="select * from authors where AU_ID=" & p1
9 set rstemp=conntemp.execute(temp)
10 howmanyfields=rstemp.fields.count -1
11 %>
12 <table border=1>
13 <tr>
14 <% 'Put Headings On The Table of Field Names
15 for i=0 to howmanyfields %>
16 <td><b><%=rstemp(i).name %></B></TD>
17 <% next %>
18 </tr>
19 <% ' Now lets grab all the records
20 do while not rstemp.eof %>
21 <tr>
22 <% for i = 0 to howmanyfields%>
23 <td valign=top><% = rstemp(i) %></td>
24 <% next %>
25 </tr>
26 <% rstemp.movenext
27 loop
28 rstemp.close
29 set rstemp=nothing
30 conntemp.close
31 set conntemp=nothing%>
32 </table>
33 </body>
34 </html>
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 Script Below>
To double check it is in the
database try:
<Test Script Below>
Now try:
<Test Script Below>
to change the
"NewPerson" Birthday to 1964 again and
<Test Script Below>
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 SQLStmt = SQLstmt & "SET Author='" & auname & "',"
13 SQLstmt = SQLstmt & "year_born=" & auyear
14 SQLStmt = SQLStmt & " WHERE AU_ID=" & auid
15 Set RS = Conn.Execute(SQLStmt)
16 If err.number>0 then
17 response.write "VBScript Errors Occured:" & "<P>"
18 response.write "Error Number=" & err.number & "<P>"
19 response.write "Error Descr.=" & err.description & "<P>"
20 response.write "Help Context=" & err.helpcontext & "<P>"
21 response.write "Help Path=" & err.helppath & "<P>"
22 response.write "Native Error=" & err.nativeerror & "<P>"
23 response.write "Source=" & err.source & "<P>"
24 response.write "SQLState=" & err.sqlstate & "<P>"
25 else
26 response.write "No problems occured!" & "<P>"
27 end if
28 IF conn.errors.count> 0 then
29 response.write "Database Errors Occured" & "<P>"
30 for counter= 0 to conn.errors.count
31 response.write "Error #" & conn.errors(counter).number & "<P>"
32 response.write "Error desc. -> " & conn.errors(counter).description & "<P>"
33 next
34 else
35 response.write SQLstmt
36 response.write "Everything Went Fine. Author is updated now!" & "<P>"
37 end if
38 set rstemp=nothing
39 Conn.Close
40 set conntemp=nothing
41 %>
42 </BODY>
43 </HTML>
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:
ALL Oracle Lists
ALL RDS (Remote Data Services) Lists
ALL SQL Server Lists
[aspngdata] ASP+/ADO+, Templates, Lists, Repeaters
[aspsqlhowto] SQL: Joins, complex queries, shaping
[aspAccess] MS-Access
[aspAcc2SQL] MS-Access to SQLserver migration
[aspAcc2SQL] Tough ASP + MS-Access Questions only
[aspBtrieve] Btrieve and ASP
[aspCOMTICICS] COMTI and CICS w/ASP
[aspDB2as400] DB2 and/or AS400
[aspDbase] Dbase
[aspFileMaker] FileMaker & ASP
[aspFox] Fox/Visual FoxPro
[aspGenericdb] FREE code to display/edit data
[aspInformix] Informix
[aspMSDE] Asp with free MSDE Engine
[aspmySQL] MySQL and ASP
[aspParadox] Paradox
[aspreports] Reports/Printing (Crystal, PDF, etc.)
[aspSAP] SAP + ASP can mix
[aspSybase] Sybase
Databases Troubleshooting Resources Part 2
The web is replete with many database resources that we think people should read up on.
SQL Basics, Searching Databases
SQL Troubles (SQLtroubles.asp) - Page 107
SQL: Example Tables (SQLexamples.asp) - Page 108
SQL: Where Clause Basics (SQLwhere.asp) - Page 109
SQL: Where Clause Examples (SQLwhere2.asp) - Page 110
SQL: Search Forms #1 (SQLwhereform1.asp) - Page 111
SQL: Search Forms #2 (SQLwhereform2.asp) - Page 112
SQL: Search Forms #3 (SQLwhereform3.asp) - Page 113
SQL: Search AND/OR Operators (SQLandor.asp) - Page 114
SQL: Search AND/OR Examples (SQLandor2.asp) - Page 115
SQL: COUNT, GROUPBY (SQLcount.asp) - Page 116
SQL: SUM, MIN, AVE, MAX (SQLaggregate.asp) - Page 117
SQL Joins by Aaron Alexander (dbjoin.asp) - Page 118
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.
Undergoing renovation - SUB ListServSignup
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
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 |
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.
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 |
SQL Where Examples by Charles Carroll
Here are some where statements and their results.
1 <HEAD><TITLE>SQLwhere1.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select * from publisher where name like 'A%%'")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
8
9
1 <HEAD><TITLE>SQLwhere2.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select * from titles where Year_Published >= 1994")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
1 <HEAD><TITLE>SQLwhere3.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select * from publishers where fax like '212%%'")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
1 <HEAD><TITLE>sqlwhere4.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select * from publishers where state<> 'NY'")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
The Include file looks like this:
1 <%
2 sub query2table(inputquery)
3 set conntemp=server.createobject("adodb.connection")
4 conntemp.open "DSN=Student;uid=student;pwd=magic"
5 set rstemp=conntemp.execute(inputquery)
6 howmanyfields=rstemp.fields.count -1%>
7 <table border=1><tr>
8 <% 'Put Headings On The Table of Field Names
9 for i=0 to howmanyfields %>
10 <td><b><%=rstemp(i).name%></B></TD>
11 <% next %>
12 </tr>
13 <% ' Now lets grab all the records
14 do while not rstemp.eof %>
15 <tr>
16 <% for i = 0 to howmanyfields
17 thisvalue=rstemp(i)
18 If isnull(thisvalue) then
19 thisvalue=" "
20 end if%>
21 <td valign=top><%=thisvalue%></td>
22 <% next %>
23 </tr>
24 <%rstemp.movenext
25 loop%>
26 </table>
27 <%
28 rstemp.close
29 set rstemp=nothing
30 conntemp.close
31 set conntemp=nothing
32 end sub%>
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:
The form that they can enter a city in:
1 <HEAD><TITLE>sqlwhereform1.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <Form action = "sqlwhereForm1respond.asp" method=GET>
4 Choose A State:<p>
5 State: <Input NAME="st" MaxLength="2" size="3"><P>
6 <Input type="submit" value="Get Data"> <Input type="reset" value="Clear State"></form>
7 </BODY></HTML>
The responder that deals with that form:
1 <HEAD><TITLE>sqlwhereform1respond.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5
6 mystate=request.querystring("st")
7 SQLtemp="select * from publishers where state='"
8 SQLtemp=SQLtemp & mystate & "'"
9
10 call query2table(SQLtemp,myDSN)
11 %>
12 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
13 </BODY></HTML>
The library 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%>
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 <HEAD><TITLE>SQLwhereform2.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <Form action = "SQLwhereForm2respond.asp" method=GET>
4 Choose A City:<p>
5 City: <Input NAME="cy" MaxLength="20" size="23"><P>
6 <input TYPE="checkbox" NAME="ExactSearch" CHECKED>Exact Search<P>
7 * note if Exact Search is -> NOT CHECKED <-<br>You can use % as a wildcard<p>
8 <Input type="submit" value="Get Data"> <Input type="reset" value="Clear City"></form>
9 </BODY></HTML>
1 <HTML><HEAD>
2 <TITLE>sqlwhereform2respond.asp</TITLE>&
3 <body bgcolor="#FFFFFF">
4 <%
5 myDSN="DSN=student;uid=student;pwd=magic"
6 mycity=request.querystring("cy")
7 myexactsearch=request.querystring("exactsearch")
8 SQLtemp="select * from publishers where city"
9 If myexactsearch="on" then
10 SQLtemp=SQLtemp & " ='"
11 Else
12 SQLtemp=SQLtemp & " LIKE '"
13 End If
14 SQLtemp=SQLtemp & mycity & "'"
15 'response.write SQLtemp
16 call query2table(SQLtemp,myDSN)
17 %>
18 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
19 </BODY></HTML>
The 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%>
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 <HEAD><TITLE>SQLwhereform3.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <Form action = "SQLwhereForm3respond.asp" method=GET>
4 Choose A City:<p>
5 City:
6 <%
7 call query2list("select distinct city from publishers", _
8 "cy","DSN=student;uid=student;pwd=magic")
9 %>
10 <P>
11 <Input type="submit" value="Get Data"> <Input type="reset" value="Clear City"></form>
12 </BODY></HTML>
13 <!--#include virtual="/learn/test/lib_dblist.asp"-->
1 <html><head><TITLE>sqlwhereform3respond.asp</TITLE></head>
2 <body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mycity=request.querystring("cy")
6 myexactsearch=request.querystring("exactsearch")
7 SQLtemp="select * from publishers where city"
8 If myexactsearch="on" then
9 SQLtemp=SQLtemp & " ='"
10 Else
11 SQLtemp=SQLtemp & " LIKE '"
12 End If
13 SQLtemp=SQLtemp & mycity & "'"
14 'response.write SQLtemp
15 call query2table(SQLtemp,myDSN)
16 %>
17 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
18 </body></html>
The 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%>
The file lib_dblist.asp looks like this:
1 <%sub query2list(myquery,myname,myDSN)
2 dim conntemp, rstemp
3 set conntemp=server.createobject("adodb.connection")
4 conntemp.open myDSN
5 set rstemp=conntemp.execute(myquery)
6 %>
7 <Select name="<%=myname%>">
8 <%
9 do while not rstemp.eof
10 thisfield=trim(RStemp(0))
11 if isnull(thisfield) or thisfield="" then
12 ' ignore
13 else
14 response.write "<option>" & thisfield & "</option>"
15 end if
16 rstemp.movenext
17 loop
18 %>
19 </select>
20 <%rstemp.close
21 set rstemp=nothing
22 conntemp.close
23 set conntemp=nothing
24 end sub%>
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 <HEAD><TITLE>SQLcities.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <Form action = "SQLcitiesrespond.asp" method="POST">
4 Choose City (or Cities):<p>
5 <%
6 call query2listm("select distinct city from publishers", _
7 "cy","DSN=student;uid=student;pwd=magic")
8 %>
9 <P>
10 <Input type="submit" value="Get Data"> <Input type="reset" value="Clear City"></form>
11 </BODY></HTML>
12 <!--#include virtual="/learn/test/lib_dblistm.asp"-->
13
The responder looks like this:
1 <HEAD><TITLE>sqlcitiesrespond.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 citycount=request.form("cy").count
5 If citycount=0 then%>
6 <B>You never choose a city!</b><br>
7 <a href="sqlcities.asp">Choose City</a>
8 <%
9 response.end
10 end if
11 firstcity=request.form("cy")(1)
12 SQLtemp="select * from publishers "
13 SQLtemp = SQLtemp & " where city='" & firstcity & "'"
14 for counter=2 to citycount
15 whichcity=request.form("cy")(counter)
16 SQLtemp = SQLtemp & " or city='" & whichcity & "' "
17 next
18 response.write SQLtemp
19 call query2table(SQLtemp,"DSN=student;uid=student;pwd=magic")
20 %>
21 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
22 </BODY></HTML>
The 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%>
The file lib_dblistm.asp looks like this:
1 <%
2 SUB query2listm(myquery,myname,myDSN)
3 dim conntemp, rstemp
4 set conntemp=server.createobject("adodb.connection")
5 conntemp.open myDSN
6 set rstemp=conntemp.execute(myquery)
7 %>
8 <Select name="<%=myname%>" multiple>
9 <%
10 do while not rstemp.eof
11 thisfield=trim(RStemp(0))
12 if isnull(thisfield) or thisfield="" then
13 ' ignore
14 else
15 response.write "<option>" & thisfield & "</option>"
16 end if
17 rstemp.movenext
18 loop
19 %>
20 </select>
21 <%rstemp.close
22 set rstemp=nothing
23 conntemp.close
24 set conntemp=nothing
25 END SUB
26 %>
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!
SQL Count Syntax/Examples
SQL can count items. There are a few variations on the syntax and some simple rules to remember:
1 <HEAD><TITLE>SQLcount1.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select count(*) from publishers where state='NY'")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
1 <HEAD><TITLE>SQLcount2.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select count(city),city from publishers group by city")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
1 <HEAD><TITLE>SQLcount3.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select count(city) as howmany,city from publishers group by city")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
1 <HEAD><TITLE>SQLcount4.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 call query2table("select count(*),city,state from publishers group by city,state")
5 %>
6 <!--#include virtual="/learn/test/subdbtable.inc"-->
7 </BODY></HTML>
The Include file looks like this:
1 <%
2 sub query2table(inputquery)
3 set conntemp=server.createobject("adodb.connection")
4 conntemp.open "DSN=Student;uid=student;pwd=magic"
5 set rstemp=conntemp.execute(inputquery)
6 howmanyfields=rstemp.fields.count -1%>
7 <table border=1><tr>
8 <% 'Put Headings On The Table of Field Names
9 for i=0 to howmanyfields %>
10 <td><b><%=rstemp(i).name%></B></TD>
11 <% next %>
12 </tr>
13 <% ' Now lets grab all the records
14 do while not rstemp.eof %>
15 <tr>
16 <% for i = 0 to howmanyfields
17 thisvalue=rstemp(i)
18 If isnull(thisvalue) then
19 thisvalue=" "
20 end if%>
21 <td valign=top><%=thisvalue%></td>
22 <% next %>
23 </tr>
24 <%rstemp.movenext
25 loop%>
26 </table>
27 <%
28 rstemp.close
29 set rstemp=nothing
30 conntemp.close
31 set conntemp=nothing
32 end sub%>
SQL Aggregate Syntax/Examples
SQL can also compute various aggregate items (MIN, MAX, AVERAGE are the most popular).
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 isnt 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
RSFAST: Lightning Fast Database Library
RSFast Library Introduction (rsfast-intro.asp) - Page 120
Table Display Fast (rsfast-table.asp) - Page 121
Table Display Fast + Caching (rsfast-table-cached.asp) - Page 122
Listbox Display Fast (rsfast-lists.asp) - Page 123
Listbox Display Fast + Caching (rsfast-lists-cached.asp) - Page 124
Templates for any look Fast (rsfast-templates.asp) - Page 125
Debug Info helps troubleshoot (rsfast-lists-debug.asp) - Page 126
Library Source Code (rsfast-lib.asp) - Page 127
caching Method Explained (rsfast-cache.asp) - Page 128
New Features for Future Versions (rsfast-newfeatures.asp) - Page 129
Overview: RSFast - Intro
by Charles Carroll
The Short Explanation
Everybody knows Getstring and
Getrows is the fastest way to fetch data (see: http://www.learnasp.com/advice/whygetrows.asp)
but people don't like to re-write their code or have the heartache of the
ugliness of the code.
Rsfast is a library that makes fetching data easier. It looks easy on the outside. You just tell it how you want the data to look an under the covers it does highly optimized getstrings and then parses the strings and combines it with your formatting.
Easy for you, hard for the library. This is very complex internally but you never have to worry about that. Just call it. It works.
The Long Explanation (skip it and goto samples if you want)
There are many ways to retrieve data.
LOOPs and MOVENEXT, seen @
http://www.learnasp.com/learn/dbtable.asp
Getrows, seen @
http://www.learnasp.com/learn/dbtablegetrows.asp
http://www.learnasp.com/learn/dbtablegetrowsnonum.asp
Getstring, seen @
http://www.learnasp.com/learn/dbtablegetrows.asp
Cached solutions like the worlds
fastest listbox
http://www.learnasp.com/learn/speedappdata.asp
And there are many ways to make
above code re-usable. Several examples of re-usable database display code
exist @
http://www.learnasp.com/learn/subdbtable.asp
http://www.learnasp.com/learn/subdblist.asp
http://www.learnasp.com/learn/subreusable.asp
http://www.learnasp.com/learn/subDBlistbest.asp
This "Rsfast" library is the best of all worlds and is a suitable replacement for any database display mentioned above. It provides re-usability, lightning fast data fetching and supports every kind of formatting desired so that it can be used in many situations. In addition to any custom formatting, it provides support for listboxes, tables, page n of n tables, nth row formatting, hyperlink, and date-formatting. The feature that provides massive application speed up is that it can cache data for a specified duration. Even if the formatting applied is totally different, the data, not the format is cached. Imagine 1,000 people hit your server in 1 minute period. Instead of 1,000 queries, only the first user that minute would fetch the data. Other 999 users get same exact data. Cache can be expressed in seconds, minutes or hours. (only in minutes in this version, next version supports richer caching options).
If a long cache duration is required yet data freshness needs to be assured some caching "rules" ensure that fresh data will trigger a cache update at instance data appears.
Overview: RSFast - Table
Example
by Charles Carroll
the library Rsfast can make tables in a simple way. Here is the code:
1 <%@ enablesessionstate=false%>
2 <%option explicit%>
3 <%
4 response.buffer=true
5 server.scripttimeout=40
6 %>
7 <!--#include file="lib_rsfast.asp"-->
8 <html>
9 <head>
10 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
11 <title>RsFast Tables</title>
12 </head>
13 <body bgcolor="#FFFFFF">
14 <%
15 dim rsparms, conntest
16 conntest="DSN=student;uid=student;pwd=magic"
17 set rsparms=server.CreateObject("Scripting.Dictionary")
18 rsparms.Add "conn", conntest
19 rsparms.add "sql", "select * from publishers where state='NY'"
20 rsparms.add "template", "table"
21 Call RsFast(rsparms)
22 ' Include below line if you want to see millisecond timing
23 'Call PerfDisplay(rsparms)
24 set rsparms=nothing
25 %>
26 </body>
27 </html>
The library
file that does all the work is at:
http://www.learnasp.com/learn/rsfast-lib.asp
so go there to cut and paste the include file if needed.
Overview: RSFast - Table +
Caching Example
by Charles Carroll
The library Rsfast can make tables in a simple way. Here is the code:
1 <%@ enablesessionstate=false%>
2 <%option explicit%>
3 <%
4 response.buffer=true
5 server.scripttimeout=40
6 %>
7 <!--#include file="lib_rsfast.asp"-->
8 <html>
9 <head>
10 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
11 <title>rsfast-table-cache</title>
12 </head>
13 <body bgcolor="#FFFFFF">
14 <%
15 dim rsparms,conntest
16 conntest="DSN=student;uid=student;pwd=magic"
17 set rsparms=server.CreateObject("Scripting.Dictionary")
18 rsparms.Add "conn", conntest
19 rsparms.add "sql", "select * from publishers where state='NY'"
20 rsparms.add "template", "table"
21 rsparms.add "cachename", "nydata"
22 rsparms.add "cachemin", 5
23 Call RsFast(rsparms)
24 response.flush
25 Call PerfDisplay(rsparms)
26 %>
27 </body></html>
The library file that does
all the work is at:
http://www.learnasp.com/learn/rsfast-lib.asp
so go there to cut and paste the include file if needed.
Overview: RSFast - Lists Example
by Charles Carroll
the library Rsfast can make tables in a simple way. Here is the code:
1 <%@ enablesessionstate=false%>
2 <%option explicit%>
3 <%
4 response.buffer=true
5 server.scripttimeout=40
6 %>
7 <!--#include file="lib_rsfast.asp"-->
8 <html>
9 <head>
10 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
11 <title>rsfast-lists</title>
12 </head>
13 <body bgcolor="#FFFFFF">
14 <%
15 dim rsparms,conntest
16 conntest="DSN=student;uid=student;pwd=magic"
17 set rsparms=server.CreateObject("Scripting.Dictionary")
18
19 rsparms.Add "conn", conntest
20
21 rsparms.add "sql", "select distinct city from publishers"
22 rsparms.add "template", "list"
23 rsparms.add "templatename", "city"
24 Call RsFast(rsparms)
25 'Call PerfDisplay(rsparms)
26 response.flush
27
28 rsparms.item("sql")="select distinct state from publishers"
29 rsparms.item("templatename")="state"
30 Call RsFast(rsparms)
31 'Call PerfDisplay(rsparms)
32 response.flush
33
34 rsparms.item("sql")="select distinct zip from publishers"
35 rsparms.item("templatename")="zip"
36 Call RsFast(rsparms)
37 'Call PerfDisplay(rsparms)
38 response.flush
39
40 set rsparms=nothing
41 %>
42 </body>
43 </html>
The library file that does
all the work is at:
http://www.learnasp.com/learn/rsfast-lib.asp
so go there to cut and paste the include file if needed.
Overview: RSFast - Lists
Cached Example
by Charles Carroll
Here are some listboxes combined with caching features. Here is the code:
1 <%@ enablesessionstate=false%>
2 <%option explicit%>
3 <%
4 response.buffer=true
5 server.scripttimeout=40
6 %>
7 <!--#include file="lib_rsfast.asp"-->
8 <html>
9 <head>
10 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
11 <title>rsfast-lists-cache</title>
12 </head>
13 <body bgcolor="#FFFFFF">
14 <%
15 dim rsparms,conntest
16 conntest="DSN=student;uid=student;pwd=magic"
17 set rsparms=server.CreateObject("Scripting.Dictionary")
18 rsparms.add "conn", conntest
19 rsparms.add "sql", "select distinct city from publishers"
20 rsparms.add "template", "list"
21 rsparms.add "templatename", "city"
22 Call RsFast(rsparms)
23 response.flush
24
25 rsparms.item("sql")="select distinct state from publishers"
26 rsparms.item("templatename")="state"
27 rsparms.item("cachename")="liststate"
28 rsparms.item("cachemin")=10
29 Call RsFast(rsparms)
30 response.flush
31
32 rsparms.item("sql")="select distinct zip from publishers"
33 rsparms.item("templatename")="zip"
34 rsparms.item("cachename")="listzip"
35 rsparms.item("cachemin")=10
36 Call RsFast(rsparms)
37 response.flush
38
39 set rsparms=nothing
40 %>
41 </body>
42 </html>
The library file that does
all the work is at:
http://www.learnasp.com/learn/rsfast-lib.asp
so go there to cut and paste the include file if needed.
Overview: RSFast - Templates
Example
by Charles Carroll
The library Rsfast can use a template you supply to format data any way. Here is the code:
1 <%@ enablesessionstate=false%>
2 <%option explicit%>
3 <%
4 response.buffer=true
5 server.scripttimeout=40
6 %>
7 <!--#include file="lib_rsfast.asp"-->
8 <html>
9 <head>
10 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
11 <title>rsfast-templates</title>
12 </head>
13 <body bgcolor="#FFFFFF">
14 <%
15 dim rsparms,conntest
16 conntest="DSN=student;uid=student;pwd=magic"
17 set rsparms=server.CreateObject("Scripting.Dictionary")
18
19 rsparms.Add "conn", conntest
20 rsparms.add "sql", "select * from publishers where state='NY'"
21 rsparms.add "template_header", "<table border=1>"
22 rsparms.add "template_row_header", "<tr>"
23 rsparms.add "template_row_footer", "</tr>"
24 rsparms.add "template_col_header", "<td>"
25 rsparms.add "template_col_footer", "</td>"
26 rsparms.add "template_footer", "</table>"
27 rsparms.add "fieldnull", " "
28 rsparms.add "fieldblank", " "
29 rsparms.add "fld_city", "<td bgcolor='lightblue'><b>{0}</b><br></td>"
30 rsparms.add "fld_state", "<td><b>{0}</b><br></td>"
31 rsparms.add "colnames", "display"
32 Call RsFast(rsparms)
33 Call PerfDisplay(rsparms)
34 set rsparms=nothing
35 %>
36 </body>
37 </html>
The library file that does
all the work is at:
http://www.learnasp.com/learn/rsfast-lib.asp
so go there to cut and paste the include file if needed.
Overview: RSFast - Debug Example
by Charles Carroll
If the library Rsfast is misbehaving due to bad info supplied you can turn on lots of debugging info. We will turn this on in a working file to see it in action. Here is the code:
1 <%@ enablesessionstate=false%>
2 <%option explicit%>
3 <%
4 response.buffer=true
5 server.scripttimeout=40
6 %>
7 <!--#include file="lib_rsfast.asp"-->
8 <html>
9 <head>
10 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
11 <title>rsfast-lists</title>
12 </head>
13 <body bgcolor="#FFFFFF">
14 <%
15 dim rsparms,conntest
16 conntest="DSN=student;uid=student;pwd=magic"
17 set rsparms=server.CreateObject("Scripting.Dictionary")
18 rsparms.add "debug", true
19 rsparms.Add "conn", conntest
20 rsparms.add "sql", "select distinct city from publishers"
21 rsparms.add "template", "list"
22 rsparms.add "templatename", "city"
23 Call RsFast(rsparms)
24 Call PerfDisplay(rsparms)
25 response.flush
26
27 rsparms.item("sql")="select distinct state from publishers"
28 rsparms.item("templatename")="state"
29 Call RsFast(rsparms)
30 Call PerfDisplay(rsparms)
31 response.flush
32
33 rsparms.item("sql")="select distinct zip from publishers"
34 rsparms.item("templatename")="zip"
35 Call RsFast(rsparms)
36 Call PerfDisplay(rsparms)
37 response.flush
38
39 set rsparms=nothing
40 %>
41 </body>
42 </html>
The library file that does
all the work is at:
http://www.learnasp.com/learn/rsfast-lib.asp
so go there to cut and paste the include file if needed.
Overview: RSFast - Library
Printout
by Charles Carroll
Here is the the library file that does all the work:
1 <%
2 ' fix 1: removed some extra code that wasn't executing in this version
3 ' fix 2: fixed .add "colnames", "display" so it works correctly
4 SUB RSfast(byref parmdict)
5 DIM totalstart, totalend, totalelapsed
6 totalstart=timer()
7
8 ' Access database build OLEDB connection string START
9 If parmdict.item("accdb")="" THEN
10 ' nothing to do
11 ELSE
12 parmdict.item("conn")="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" & server.mappath(parmdict.item("accdb")) & ";"
13 END IF
14
15 ' Caching and Data-Fetching START
16 DIM cachename,cachems,cachesec,cachemin,cacheday
17 DIM CacheIsRelevant,cacheduration
18 cachename=parmdict.item("cachename")
19 cachems=parmdict.item("cachems")
20 cachesec=parmdict.item("cachesec")
21 cachemin=parmdict.item("cachemin")
22 cacheday=parmdict.item("cacheday")
23
24 DIM thedata,thefields, cachedata
25 parmdict.item("cachegrab")="no"
26 parmdict.item("cachebuild")="no"
27 CacheIsRelevant=CacheCheck(parmDict)
28 SELECT CASE CacheIsRelevant
29 CASE False
30 Call DataFetch(parmDict,thedata,thefields)
31 CASE True
32 If application(cachename & "_building")=TRUE THEN
33 Call DataFetch(parmDict,thedata,thefields)
34 ELSE
35 IF cacheExpired(parmDict)=TRUE THEN
36 Call CacheBuild(parmDict)
37 END IF
38 IF cacheEmpty(parmDict)=TRUE THEN
39 Call CacheBuild(parmDict)
40 END IF
41 Call CacheGrab(parmDict,cachedata,thefields)
42 thedata=split(cachedata,"#r#" & vbcrlf)
43 END IF
44 END SELECT
45 Call DataDisplay(parmDict,thedata,thefields)
46
47 totalend=timer()
48 totalelapsed=totalend-totalstart
49 parmDict.item("timetotalms")=totalelapsed*1000
50
51 ' Now calculate further stats
52 ' Thanks to Mike "micro-optimization" Shaffer
53 parmdict.item("timeopensec")=parmdict.item("timeopenms") \ 1000
54 parmdict.item("timequerysec")=parmdict.item("timequeryms") \ 1000
55 parmdict.item("timefetchsec")=parmdict.item("timefetchms") \ 1000
56 parmdict.item("timedisplaysec")=parmdict.item("timedisplayms") \ 1000
57 parmdict.item("timetotalsec")=parmdict.item("timetotalms") \ 1000
58
59 parmdict.item("timeopenmin")=parmdict.item("timeopenms") \ 60000
60 parmdict.item("timequerymin")=parmdict.item("timequeryms") \ 60000
61 parmdict.item("timefetchmin")=parmdict.item("timefetchms") \ 60000
62 parmdict.item("timedisplaymin")=parmdict.item("timedisplayms") \ 60000
63 parmdict.item("timetotalmin")=parmdict.item("timetotalms") \ 60000
64
65 ' reset cache should NEVER remember between calls
66 parmdict.item("cachename")=""
67 parmdict.item("cachemin")=""
68 END SUB
69
70 SUB Cache2Array(byref parmDict,byref theArray())
71 If parmdict.item("debug")=true THEN
72 response.write "Cache2Array called"
73 response.flush
74 END IF
75 ' Now transfer cache to Array
76 thearray=split(application(cachename & "_cachedata"),"#r#" & vbcrlf)
77 END SUB
78
79 SUB CacheBuild(parmDict)
80 If parmdict.item("debug")=true THEN
81 response.write "CacheBuild called<br>"
82 response.flush
83 END IF
84 DIM cachename,cachedata,cachefields
85 application(cachename & "_building")=true
86 cachename=parmdict.item("cachename")
87
88 parmdict.item("cachefetch")=true
89 Call DataFetch(parmDict,cachedata,cachefields)
90 parmdict.item("cachefetch")=false
91
92 application(cachename & "_cachedata")=cachedata
93 application(cachename & "_cachefields")=cachefields
94 ' Now Expire The Cache
95 ' cachename_cacheExpires
96 application(cachename & "_cachecreated")=now()
97 application(cachename & "_cachemin")=parmdict.item("cachemin")
98 If parmdict.item("debug")=true THEN
99 response.write "Cachecreated=" & application(cachename & "_cachecreated") & "<br>" & "<br>"
100 response.write "cachemin=" & application(cachename & "_cachemin") & "<br>"
101 response.flush
102 END IF
103 parmdict.item("cachebuild")="yes"
104 application(cachename & "_building")=false
105 END SUB
106
107 SUB CacheGrab(byref parmDict,byref ParmData,byref parmFields)
108 If parmdict.item("debug")=true THEN
109 response.write "CacheGrab called<br>"
110 response.flush
111 END IF
112
113 DIM cachename
114 cachename=parmdict.item("cachename")
115 parmData=application(cachename & "_cachedata")
116 parmFields=application(cachename & "_cachefields")
117 parmdict.item("cachegrab")="yes"
118 END SUB
119
120 FUNCTION cacheEmpty(parmDict)
121 If parmdict.item("debug")=true THEN
122 response.write "CacheEmpty called<br>"
123 response.flush
124 END IF
125 DIM cachename, cachedatakey, cachedata
126 cachename=parmdict.item("cachename")
127 ' If cache is filled with data, return TRUE
128 cachedatakey=cachename & "_cachedata"
129 cachedata=application(cachedatakey)
130 If cachedata="" THEN
131 cacheEmpty=True
132 ELSE
133 cacheEmpty=False
134 END IF
135 If parmdict.item("debug")=true AND cacheempty=True THEN
136 response.write "CacheEmpty=TRUE<br>"
137 response.flush
138 END IF
139 If parmdict.item("debug")=true AND cacheempty=False THEN
140 response.write "CacheEmpty=False<br>"
141 response.flush
142 END IF
143 END FUNCTION
144
145 FUNCTION cacheExpired(parmDict)
146 ' If cache is out of date return TRUE
147 DIM whenexpires, cachename, cachemin, cachecreated
148 cachename=parmdict.item("cachename")
149 cachemin=application(cachename & "_cachemin")
150 cachecreated=application(cachename & "_cachecreated")
151 whenexpires=dateadd("n",cachemin,cachecreated)
152 cacheExpired=false
153 If now()>=whenexpires THEN
154 cacheExpired=True
155 END IF
156 If cachecreated="" AND cachemin="" THEN
157 cacheExpired=False
158 END IF
159 If parmdict.item("debug")=true AND cacheExpired=True THEN
160 response.write "whenexpires=" & whenexpires & "<br>"
161 response.write "CacheExpired=TRUE<br>"
162 response.flush
163 END IF
164 If parmdict.item("debug")=true AND cacheExpired=False THEN
165 response.write "CacheExpired=FALSE<br>"
166 response.flush
167 END IF
168 END FUNCTION
169
170 FUNCTION cacheCheck(parmDict)
171 ' Returns True/False whether data is cache affected
172 DIM cachename
173 cachename=parmdict.item("cachename")
174 If cachename="" THEN
175 cachecheck=False
176 ELSE
177 cachecheck=True
178 END IF
179 END FUNCTION
180
181 SUB DataFetch(parmDict, parmArray,parmFields)
182 If parmdict.item("debug")=true THEN
183 response.write "DataFetch called<br>"
184 response.flush
185 END IF
186
187 ' used for timing
188 DIM openst, openend, openelapsed
189 DIM queryst, queryend, queryelapsed
190 DIM fetchst, fetchelapsed
191 DIM conntemp, rstemp
192
193 DIM howmany,counter,thename,tempSTRdata,tempSTR
194 Dim tempSTRfields,thefields
195
196 openst = timer
197 ' Open and check for EOF
198 set conntemp=server.createobject("adodb.connection")
199 conntemp.open parmdict.item("conn")
200 openend = timer
201 openelapsed = openend - openst
202
203 parmdict.item("timeopenms")=openelapsed
204
205 If parmdict.item("debug")=true THEN
206 response.write "Conn=" & parmdict.item("conn") & "<br>"
207 response.write "Database Opened in " & openelapsed & "ms<br>"
208 response.flush
209 END IF
210
211 ' If recordset is paged must be opened special
212 queryst=timer
213 IF cint(parmdict.item("pagesize"))>0 THEN
214 set rstemp=Server.CreateObject("ADODB.Recordset")
215 aduseclient=3
216 rstemp.cursorlocation=aduseclient
217 rstemp.cachesize=parmdict.item("pagesize")
218 rstemp.open parmdict.item("sql"),parmdict.item("conn")
219 rstemp.absolutepage=parmdict.item("page")
220 pagemax=cint(rstemp.pagecount)
221 parmdict.add "pagemax", pagemax
222 paged=true
223 If parmdict.item("debug")=true THEN
224 response.write "SQL=" & parmdict.item("sql") & "<br>"
225 response.write "Recordset Opened for Paging!<br>"
226 response.flush
227 END IF
228 ELSE
229 set rstemp=conntemp.execute(parmdict.item("sql"))
230 END IF
231 queryend = timer
232 queryelapsed = queryend - queryst
233
234 parmdict.item("timequeryms")=openelapsed
235
236 fetchst=timer
237 If parmdict.item("debug")=true THEN
238 response.write "SQL=" & parmdict.item("sql") & "<br>"
239 response.write "Query Executed: " & queryelapsed & "ms<br>"
240 response.flush
241 END IF
242 If rstemp.eof then
243 parmdict.item("errordesc")="No records matched"
244 parmdict.item("errornum")=1
245 rstemp.close
246 set rstemp=nothing
247 conntemp.close
248 set conntemp=nothing
249 If parmdict.item("debug")=true THEN
250 response.write "EOF encountered!" & queryelapsed & "ms<br>"
251 response.flush
252 END IF
253 EXIT SUB
254 end if
255
256 ' Now Fill The Array
257 ' Rockville#c#MD#c#20849#r#<vbcrlf>
258 ' Dallas#c#TX#c#XXXXX#r#<vbcrlf>
259 tempSTRdata=rstemp.getstring(,, "#c#","#r#" & vbcrlf,"#n#")
260
261 ' Now Fill The FieldMaps
262 ' City#c#State#c#Zip#r#<vbcrlf>
263 howmany=rstemp.fields.count
264 for counter=0 to howmany-1
265 thename=rstemp(counter).name
266 tempstr=tempSTR & thename & "#c#"
267 next
268 tempSTRfields=tempSTR
269 rstemp.close
270 set rstemp=nothing
271 conntemp.close
272 set conntemp=nothing
273 If parmdict.item("cachefetch")=true THEN
274 parmarray=TempSTRdata
275 ELSE
276 parmArray=split(tempSTRdata,"#r#" & vbcrlf)
277 END IF
278 parmFields=tempSTRfields
279 If parmdict.item("debug")=true THEN
280 response.write "Data Before Split=<br>" & tempSTRdata & "<hr><br>"
281 response.write "Fields Before Split=<br>" & tempSTRfields & "<hr><br>"
282 response.flush
283 END IF
284 fetchelapsed=timer-fetchst
285 parmdict.item("timefetchms")=fetchelapsed
286 END SUB
287
288 SUB DataDisplay(parmDict, parmData(),parmFields)
289 DIM displayst,displayelapsed
290 displayst=timer
291
292 If parmdict.item("debug")=true THEN
293 response.write "DataDisplay called<br>"
294 response.flush
295 END IF
296
297 DIM cellcount,cellspersecond
298 DIM template_header, template_footer
299 DIM rowheader,rowfooter,colheader,colfooter
300 DIM fieldnull,fieldblank,template
301
302 ' used for looping through query results
303 DIM alldata, coldisplay,counter,howmany,rsinfo,thename,colcounter
304
305 DIM rstemp, conntemp,rowcount,colcount
306
307 DIM therow, fldname,fldnumb,fldvalue,fldtemplate
308 DIM thisrow, datarow
309 DIM whatever
310 DIM parmtemplate, parmtemplatename
311
312 parmtemplate=lcase(parmdict.item("template"))
313 parmtemplatename=parmdict.item("templatename")
314 ' Templates Are Applied As Needed START
315 ' Probably need to replace dictionary items ONLY if they don't exist
316
317 template=false
318 SELECT CASE parmtemplate
319 CASE "list", "listm"
320 template_header="<select name='" & parmtemplatename
321 If parmtemplate="listm" THEN
322 template_header=template_header & " multiple "
323 END IF
324 template_header=template_header & "'>"
325 rowheader="<option>"
326 rowfooter="</option>"
327 template_footer="</select><br>"
328 fieldnull=" "
329 fieldblank=" "
330 template=True
331 CASE "table","tablepaged"
332 template_header="<table border=1>"
333 rowheader="<tr>"
334 rowfooter="</tr>"
335 colheader="<td>"
336 colfooter="</td>"
337 template_footer="</table>"
338 fieldnull=" "
339 fieldblank=" "
340 parmdict.item("colnames")="display"
341 template=true
342 CASE ELSE
343 ' nothing to do
344 END SELECT
345
346 IF template=false THEN
347 template_header=parmdict.item("template_header")
348 template_footer=parmdict.item("template_footer")
349 ' Load dictionary items into simple variable to avoid
350 ' doing so many times in loop
351 rowheader=parmdict.item("template_row_header")
352 rowfooter=parmdict.item("template_row_footer")
353 colheader=parmdict.item("template_col_header")
354 colfooter=parmdict.item("template_col_footer")
355 fieldnull=parmdict.item("fieldnull")
356 fieldblank=parmdict.item("fieldblank")
357 END IF
358
359 ' Page x of x displays may need to appear in header/footer
360 template_header=replace(template_header,"{page}",cstr(parmdict.item("page")))
361 template_footer=replace(template_footer,"{page}",cstr(parmdict.item("page")))
362 template_header=replace(template_header,"{pagemax}",cstr(parmdict.item("pagemax")))
363 template_footer=replace(template_footer,"{pagemax}",cstr(parmdict.item("pagemax")))
364
365
366 DIM highcount
367 If parmdict.item("debug")=true THEN
368 response.write "ParmData Array Data=<Br>"
369 highcount=ubound(parmData)
370 response.write "Parm Data ubound=" & highcount & "<p>"
371 for counter=0 to highcount
372 response.write "<b>ParmData(" & counter & ")</b>="
373 response.write parmData(counter) & "<br>"
374 next
375 response.write "<hr>"
376 response.write "ParmFields " & parmfields & "<br>"
377 response.flush
378 END IF
379
380 DIM datafields
381 datafields=split(parmFields,"#c#")
382
383 If parmdict.item("debug")=true THEN
384 response.write "DataFields Data<Br>"
385 highcount=ubound(datafields)
386 response.write "DataFields ubound=" & highcount & "<p>"
387 for counter=0 to highcount
388 response.write "<b>DataFields(" & counter & ")</b>="
389 response.write DataFields(counter) & "<br>"
390 next
391 response.write "<hr>"
392 response.write "<b>formatting info</b><br>"
393 response.write "template_header=" & server.htmlencode(template_header) & "<br>"
394 response.write "template_footer=" & server.htmlencode(template_footer) & "<br>"
395 response.write "rowheader=" & server.htmlencode(rowheader) & "<br>"
396 response.write "rowfooter=" & server.htmlencode(rowfooter) & "<br>"
397 response.write "colheader=" & server.htmlencode(colheader) & "<br>"
398 response.write "colfooter=" & server.htmlencode(colfooter) & "<br>"
399 response.write "<hr>"
400 for each whatever in parmdict
401 IF instr(whatever, "fld_")>0 THEN
402 response.write whatever & "=" & server.htmlencode(parmdict.item(whatever)) & "<br>"
403 END IF
404 next
405 response.write "<hr>"
406 END IF
407
408 ' Page x of x displays may need to appear in header/footer
409 template_header=replace(template_header,"{page}",cstr(parmdict.item("page")))
410 template_footer=replace(template_footer,"{page}",cstr(parmdict.item("page")))
411
412 template_header=replace(template_header,"{pagemax}",cstr(parmdict.item("pagemax")))
413 template_footer=replace(template_footer,"{pagemax}",cstr(parmdict.item("pagemax")))
414
415 colcount=ubound(datafields)
416 response.write template_header
417
418 If parmdict.item("colnames")="display" THEN
419 coldisplay=true
420 response.write rowheader
421 END IF
422
423 FOR colcounter=0 TO colcount-1
424 thename=datafields(colcounter)
425 If coldisplay=TRUE THEN
426 response.write colheader
427 response.write "<b>" & thename & "</b>"
428 response.write colfooter
429 END IF
430 NEXT
431 If coldisplay=TRUE THEN
432 response.write rowfooter
433 END IF
434
435 rowcount=ubound(parmData)
436 ' suck display out of cache
437 FOR therow=0 TO rowcount-1
438 response.write vbcrlf & rowheader
439 thisrow=parmdata(therow)
440 datarow=split(thisrow,"#c#")
441 FOR colcounter=0 TO colcount-1
442 fldname=lcase(datafields(colcounter))
443 fldvalue=datarow(colcounter)
444 IF trim(fldvalue)="#n#" THEN
445 fldvalue=fieldnull
446 END IF
447 IF trim(fldvalue)="" THEN
448 fldvalue=fieldblank
449 END IF
450
451 fldtemplate=parmdict.item("fld_" & fldname)
452 If fldtemplate<>"" THEN
453 fldvalue=replace(fldtemplate,"{0}",fldvalue)
454 response.write fldvalue
455 ELSE
456 response.write vbcrlf & colheader
457 response.write fldvalue
458 response.write colfooter & vbcrlf
459 END IF
460 cellcount=cellcount+1
461 NEXT
462 response.write rowfooter & vbcrlf
463 NEXT
464 response.write template_footer
465
466 displayelapsed=timer-displayst
467
468 parmdict.item("timedisplayms")=displayelapsed
469 parmdict.item("cellcount")=cellcount
470 END SUB
471
472 SUB PerfDisplay(parmDict)
473 dim linebreak
474 linebreak="<Br>" & vbcrlf
475
476 response.write "cachegrab=" & parmdict.item("cachegrab") & linebreak
477 response.write "cachebuild=" & parmdict.item("cachebuild") & linebreak
478
479 Response.write "total ms=" & parmDict.item("timetotalms") & linebreak
480 Response.write "open ms=" & parmDict.item("timeopenms") & linebreak
481 Response.write "query ms=" & parmDict.item("timequeryms") & linebreak
482 Response.write "fetch ms=" & parmDict.item("timefetchms") & linebreak
483 Response.write "display ms=" & parmDict.item("timedisplayms") & linebreak
484 Response.write "cellcount=" & parmDict.item("cellcount") & linebreak
485 response.write "<hr>"
486
487 Response.write "total sec=" & parmDict.item("timetotalsec") & linebreak
488 Response.write "open sec=" & parmDict.item("timeopensec") & linebreak
489 Response.write "query sec=" & parmDict.item("timequerysec") & linebreak
490 Response.write "fetch sec=" & parmDict.item("timefetchsec") & linebreak
491 Response.write "display sec=" & parmDict.item("timedisplaysec") & linebreak
492 response.write "<hr>"
493
494 Response.write "total min=" & parmDict.item("timetotalmin") & linebreak
495 Response.write "open min=" & parmDict.item("timeopenmin") & linebreak
496 Response.write "query min=" & parmDict.item("timequerymin") & linebreak
497 Response.write "fetch min=" & parmDict.item("timefetchmin") & linebreak
498 Response.write "display min=" & parmDict.item("timedisplaymin") & linebreak
499 response.write "<hr>"
500 END SUB
501 %>
Overview: RSFast - Caching
System
by Charles Carroll
The current caching method is extremely lightweight and scalable. It merely fills in 2 app variables with 2 strings (the data and field map) and has 2 other application variables (one holds date/time of cache creation, and duration in minutes)
It uses delimited strings, i.e. the data string would be stored as:
' Rockville#c#MD#c#20849#r#<vbcrlf>
' Dallas#c#TX#c#XXXXX#r#<vbcrlf>
and the fieldmap string would be stored as:
' City#c#State#c#Zip#c#
This means cache take up little memory. Since the data is cached not the format, even if it is formatted for a total different "look and feel" the data still comes from the cache.
Overview: RSFast - New
Fatures in the Works
by Charles Carroll
The following features will appear in next versions of Rsfast. We mention then now so you can see if we addressed any limit you found. Join the listserver on next page if you want help on using Rsfast or want to discuss these features implementations or features you would like us to add.
http://www.asplists.com/asplists/asprsfast.asp
is location of listserver where we discuss this library.
It records timing for every unique query pair (i.e. connection+SQLquery) fed to it. Timing include connection open, query time and fetch/display time averages, best and worst. It tracks cells per second (i.e. 6 columns x 120 rows would be 720 "cells"). It also records when users "give up" before the data is fetched.
Albany
... a bunch of Albany Data
Albany
Buffalo
... a bunch of Bufallo Data
Buffalo
Chelsea
... a bunch of Chelsey Data
Chelsea
In the new version you can have a special additional header/footer for each city band. There could be state, city and zip bands and relevant templates if a multiple order by was involved.
Editors Used With ASP
ASPExpress: HOT ASP Editor (aspexpress.asp) - Page 131
Visual Interdev + Admunsen Resources (admunsen.asp) - Page 132
Visual Interdev Listserver (aspvisualinterdev.asp) - Page 133
Homesite: HTML editor (homesite.asp) - Page 134
DreamWeaver: HTML and Script Editor (dreamweaver.asp) - Page 135
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.
Interdev Guru Michael Amundsen's listserver 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.
We of course have an active Visual-Interdev listserver - not as good as his - but hey we are trying @ http://www.asplists.com/asplists/aspvisualinterdev.asp
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.
Related Links:
King Interdev/Michael Admunsen @
http://www.amundsen.com/vinterdev/default.htm
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
Homesite - Popular HTML Editor
This is a very popular HTML editor
from
http://www.allaire.com/products/homesite/
If you are using it with ASP I recommend checking out:
http://www.wilk4.com/asp4hs
which focuses on how people using Homesite can edit their ASP scripts even
easier.
Dreamweaver - HTML and Script Editor
This is a very popular HTML editor
from Macromedia @
http://www.dreamweaver.com
If you are using it with ASP I recommend checking out:
which focuses on how people using Dreamweaver can edit their ASP scripts even easier.
Essential Commercial Components
ASPDB: Displaying Data (aspdb1.asp) - Page 137
ASPDB: Editing, Adding Data (aspdb2.asp) - Page 138
BrowserHawk: Determing Browser Type (bhbrowtype.asp) - Page 139
AOL detection w/BrowserHawk (bhaol.asp) - Page 140
MS-Wallet w/BrowserHawk (bhwallet.asp) - Page 141
Reverse DNS lookups w/BrowserHawk (bhresolveip.asp) - Page 142
BrowserHawk - Frame support (bhframes.asp) - Page 143
Flash Detection w/BrowserHawk (bhflash.asp) - Page 144
ServerObject Mail: Simple Example (serverobjectsmail.asp) - Page 145
ServerObject: Mailing Form w/ASPMail (formsendmail.asp) - Page 146
3rd Party Mail, CDO/CDONTS Listserver (aspmail.asp) - Page 147
SA: File Upload, Simple Example (uploadsimple.asp) - Page 148
SA: File Upload, Multi-part form (uploadmultipart.asp) - Page 149
SA: File Upload, Limit Size (uploadlimitsize.asp) - Page 150
SA: File Upload, Many Files (uploadmanyfiles.asp) - Page 151
Upload/Soft-Artisans Listserver (aspsoftartisans.asp) - Page 152
Perf Counters on ASP page (perfcounters.asp) - Page 153
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 <% response.buffer=true %>
2 <HTML>
3 <Head><Title>ASPdb1.asp</Title></Head>
4 <%
5 Set MyDb = Server.CreateObject("ASPdb.Pro")
6 MyDb.dbUnit = 1000
7 MyDb.dbMDB=Server.MapPath("/learn/test/nwind.mdb")
8 MyDb.dbColor = "11"
9 MyDb.dbGridTableTag = "border=3"
10 MyDb.dbMode= "Grid"
11 MyDb.dbSQL = "Select * FROM Customers"
12 MyDb.dbNavigationItem = "top, bottom, next, prev, filter"
13 MyDb.ASPdbPro
14 set myDB=nothing
15 %>
16 </BODY>
17 </HTML>
18
19
Now we will display publishers:
1 <% response.buffer=true %>
2 <HTML>
3 <Head><Title>ASPdb1.asp</Title></Head>
4 <%
5 Set MyDb = Server.CreateObject("ASPdb.Pro")
6 MyDb.dbUnit = 1000
7 MyDb.dbMDB=Server.MapPath("/learn/test/biblio.mdb")
8 MyDb.dbColor = "11"
9 MyDb.dbGridTableTag = "border=3"
10 MyDb.dbMode= "Grid"
11 MyDb.dbSQL = "Select * FROM Publishers"
12 MyDb.dbNavigationItem = "top, bottom, next, prev, filter"
13 MyDb.ASPdbPro
14 set myDB=nothing
15 %>
16 </BODY>
17 </HTML>
18
19
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 end if
32
33 if UL12 = "ASPDBEDITDEL" then
34 MSG1 = "<CENTER><FONT SIZE=4 COLOR=red><B>"
35 MSG1 = MSG1 + "You are about to DELETE all of the Information for: " + THISNAME
36 MSG1 = MSG1 + "</B></FONT><P>"
37 response.write(MSG1)
38 end if
39
40 if UL12 = "ASPDBEDITEDI" then
41 MSG1 = "<CENTER><FONT SIZE=4 COLOR=red><B>"
42 MSG1 = MSG1 + "You are about to EDIT all of the Information for: " + THISNAME
43 MSG1 = MSG1 + "</B></FONT><P>"
44 response.write(MSG1)
45 end if
46
47 Mydb.dbMDB = Server.MapPath("Pro-Demo.mdb") ' Has fields: Name, Age, Salary, NetWorth
48
49 MyDb.DBColor = "11,auto,white"
50 MyDb.dbGridTableTag = "border=3 cellspacing=3 cellpadding=3"
51 MyDb.dbFormTableTag = "border=3 cellspacing=3 cellpadding=3"
52 MyDb.dbGridDisplayFlds = "Name,Age,Salary,NetWorth"
53 MyDb.DbMode = "dual-horiz"
54 MyDb.dbGridInc = 10
55 MyDb.dbButtonAnchor=false
56 MyDb.dbExportFlds = "Name"
57
58 Mydb.dbFilterDropFlds = "Name,,People,Name,,,,,Distinct; Salary,,People,Salary,,,,,Distinct"
59
60 Mydb.dbEditDropFlds = "Salary,,,9250.75/11000/15000/21000/25000/32000/38000/44000/75000"
61
62 Mydb.dbEditFlds = "Name,Age[10],Salary,NetWorth[123]" ' added Name 07-27-98
63 MyDb.dbEditUpdateROFlds = "Name" ' ***** NEW!!!!! *****
64
65 EP = "TableName=People,BookMarkFlds=0,TableTag=Border=2"
66 EP = EP & ",RecordScope=single,CriteriaSize=4x25,EditSemiColon=;"
67 Mydb.dbEditParams = EP
68
69 MyDb.dbSQL = "Select * from People"
70
71 MyDb.dbMagicCell = _
72 "1, align=Left , <font size=2 face=ARIAL color=black><I><B>#1#</B></I>;" & _
73 "2, align=Center, <font size=2 face=ARIAL color=black> #2#;" & _
74 "3, align=right , <font size=2 face=ARIAL color=black>format=[currency];" & _
75 "4, align=right , <font size=2 face=ARIAL color=black>format=[currency];"
76
77 MyDb.dbImageDir="images/"
78 Mydb.dbNavigation="both"
79 Mydb.dbNavigationItem="Next, Prev, Gridrow, Filter, add, update, edit, delete"
80 Mydb.dbNavigationIcon="std"
81
82 MyDb.aspDBPro
83 set mydb=nothing
84 %>
85
86 </HTML>
87
88
89
90
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 <%
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 set bh = server.createobject("cyScape.browserObj")
3 if (bh.majorver >=4 ) and (bh.Browser ="IE" or bh.Browser ="Netscape") then
4 else
5 response.redirect("PageForNonIEorNNv4.asp")
6 end if
7 set bh = nothing
8 %>
9 <html><body> </body></html>
10
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 set bh = server.createobject("cyScape.browserObj")
3 if bh.version>=4 and bh.browser="IE" then
4 %>
5 <a href='x.asp' title=' This is the alternate text. '>
6 <% else %>
7 </a>
8 <a href='x.asp'>
9 <%
10 end if
11 set bh = nothing
12 %>
13 <p>
14 Hover here</a>
15
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.
Detect AOL browsers and versions
Many people ask about how to detect which version of an AOL browser is being used, 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 check for the AOL version number, you can easily use the following script to do so.
1 <%
2 set bh = Server.CreateObject("cyScape.browserObj")
3 aolVer = bh.AOLVersion
4 if aolVer > 0 AND aolVer <= 3 then
5 response.redirect "noaol3.asp"
6 end if
7 'Or for example, if you wanted to check for AOL Version 4 you would do this:
8 ' if bh.AOLVersion = 4 then ...
9
10 %>
11 <html>
12
13 <head>
14 <title>AOL check script</title>
15 </head>
16
17 <body>
18
19 <p>You are not using AOL v3 or lower</p>
20 </body>
21 </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.
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 <html>
2
3 <head>
4 <title>Purchase</title>
5 </head>
6
7 <body>
8
9 <p>Payment info:<br>
10 <%
11 set bh = Server.CreateObject("cyScape.browserObj")
12 if bh.ActiveXControls then
13 response.write "... send MS Wallet control"
14 else
15 response.write "... send alternative code for collecting payment info"
16 end if
17 %></p>
18
19 <p>%></p>
20 </body>
21 </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.
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 <html>
2
3 <head>
4 <title>Resolve IP</title>
5 </head>
6
7 <body>
8
9 <p>Hello user connected from <%
10 set bh = Server.CreateObject("cyScape.browserObj")
11 hostname = bh.ResolveIP
12 if hostname <> "" then
13 response.write hostname
14 else
15 response.write "Unknown"
16 end if
17 %> </p>
18
19 <p>%></p>
20 </body>
21 </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 <html>
2
3 <head>
4 <title>Resolve IP</title>
5 </head>
6
7 <body>
8 <%
9 ipToLookup = "198.137.240.91"
10 %>
11
12 <p>The host name for <%=ipToLookup%> is <%
13 set bh = Server.CreateObject("cyScape.browserObj")
14 hostname = bh.ResolveIP(ipToLookup)
15 if hostname <> "" then
16 response.write hostname
17 else
18 response.write "Unknown"
19 end if
20 %> </p>
21
22 <p>%></p>
23 </body>
24 </html>
Copyright (c) 1999 cyScape, Inc. All rights reserved. This material may not be published, distributed, or reprinted without written consent from cyScape.
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 set bh = Server.CreateObject("cyScape.browserObj")
3 if not bh.frames then 'note: this could also be written as "if bh.frames = false"
4 response.redirect "noframes.asp"
5 end if
6 %>
7 <html>
8
9 <head>
10 <title></title>
11 </head>
12
13 <body>
14
15 <p>HTML code to load your frameset goes here </p>
16 </body>
17 </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.
Detecting Flash plug-in support
The Macromedia Flash plug-in provides a great way to liven up your web site. With Flash you can make fancy splash screens, animated graphics, interactive presentations, and much more. The downside? Not all of your visitors will have the Flash plug-in installed, and therefore will not experience your site as you'd expect. :(
While it's true that Internet Explorer will automatically attempt to download and install the Flash player if not already installed, many people find this to be highly intrusive. As a result, developers prefer only to serve Flash content to Flash capable browsers. In addition, this automatic download isn't an option for users of other popular browsers, such as Netscape Communicator.
By using the approach demonstrated here, however, you can have an alternative plan up your sleeve, and be ready to serve non Flash folks with a suitable alternative.
Let's assume you have a fancy Flash animation on your home page waiting to dazzle your visitors, and that this animation requires the Flash 4 plug-in to be installed. To make sure that visitors without Flash 4 will not be left staring at a blank home page, you'll want to provide an alternative such as an image where the Flash animation would normally go.
Here is a summary of the steps needed to implement this approach:
The toughest part of this approach is determining whether the visitor has the Flash 4 player installed in their browser. Fortunately BrowserHawk 2000 makes detecting Flash support as simple as calling a single method and checking the Plugin_Flash property.
1 <%
2 set bh = Server.CreateObject("cyScape.browserObj")
3 bh.GetExtProperties "BGCOLOR=#FFFFFF"
4
5 'Note: The above method must be called before the HTML tag.
6 'Pass in the background color used by your site as shown above
7 'for best results. See the BrowserHawk documentation for more
8 'details on using this method.
9 %>
10
11 <HTML><HEAD><TITLE>Flowers 'n Things Home Page (Demo)</TITLE></HEAD>
12 <BODY>
13 <CENTER><H3>Welcome to Flowers 'n Things!</H3></CENTER>
14
15 <%
16 flashVer = bh.Plugin_Flash
17
18 if flashVer >=4 then %>
19
20 <!-- Code for Flash 4 users goes here -->
21
22 <CENTER>
23 <OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
24 codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=4,0,0,0"
25 ID=Flower WIDTH=360 HEIGHT=360>
26 <PARAM NAME=movie VALUE="Flower.swf"> <PARAM NAME=quality VALUE=high> <PARAM NAME=bgcolor VALUE=#FFFFFF> <embed src="Flower.swf" quality="high" bgcolor="#FFFFFF" WIDTH="360" HEIGHT="360" TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">
27 </OBJECT><BR>
28 </CENTER>
29 <HR WIDTH=400>
30 <CENTER><TABLE WIDTH=400><TR><TD>
31 Lesson note: This is the page shown to all visitors with the Flash 4 plug-in or higher installed. If they
32 did not have Flash 4 installed, we would have presented <A HREF="flower.gif" WIDTH=360 HEIGHT=360>this image</A>
33 instead of the Flash animation above. This script uses cyScape's <A HREF="http://www.cyscape.com/products/">BrowserHawk</A> to determine whether Flash is installed.
34 </TD></TR></TABLE></CENTER>
35
36 <% else %>
37
38 <!-- Code for Non-Flash 4 users goes here -->
39
40 <CENTER><IMG SRC="flower.gif" WIDTH=360 HEIGHT=360></CENTER><BR>
41 <CENTER><FONT SIZE=-1>Best viewed with <A HREF="http://www.macromedia.com/shockwave/download/?P1_Prod_Version=ShockwaveFlash">Macromedia Flash 4</A></FONT></CENTER>
42 <HR WIDTH=400>
43 <CENTER><TABLE WIDTH=400><TR><TD>
44 <%
45 msg = ""
46 if flashVer = 0 then
47 msg = "You do not have Flash installed."
48 elseif flashVer = -1 then
49 msg = "It is not possible with your browser/platform to detect whether your Flash is installed."
50 else
51 msg = "You have Flash version " & flashVer & " installed."
52 end if
53 %>
54 Lesson note: <% =msg%> This is the page shown to all visitors without the Flash 4 plug-in or higher installed. Since
55 their browser does not support Flash, we provide them with this alternative graphic for the home
56 page. This script uses cyScape's <A HREF="http://www.cyscape.com/products/">BrowserHawk</A> to determine whether Flash is installed.
57 </TD></TR></TABLE></CENTER>
58
59 <% end if %>
60
61 </BODY></HTML>
Need a copy of BrowserHawk? See our section on Getting Started.
Copyright (c) 2000 cyScape, Inc. All rights reserved. This material may not be published, distributed, or reprinted without written consent from cyScape.
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 <html><head>
2 <title>serverobjectsmail.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 ' ASPMail(tm) from www.serverobjects.com
6 ' is not part of ASP per se,
7 ' but a third party utility from serverobjects.com
8 Set Mailer = Server.CreateObject("SMTPsvg.Mailer")
9 Mailer.RemoteHost = "mail.innerhost.com"
10
11 Mailer.FromName = "Some Student"
12 Mailer.FromAddress = "somestudent@activeserverpages.com"
13 Mailer.AddRecipient "Charles Carroll","selfdestruct@learnasp.com"
14 Mailer.AddBCC "Sally Jones","selfdestruct@learnasp.com"
15 Mailer.Subject = "ASPMail Tutorial"
16
17 Mailer.BodyText = "Hi. Just trying the mail example" & vbCrLf
18 Mailer.BodyText = "Line 2"
19 Mailer.BodyText = "Line 3"
20 If Mailer.SendMail then
21 Msg = "mail sent sucessfully!"
22 Else
23 Msg = "mail <b>not</b> sent sucessfully"
24 msg = msg & "<br>" & mailer.response
25 End If
26 response.write Msg
27
28 set mailer=nothing
29 %>
30 </body></html>
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:
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 ' change these to reflect where form should go
3 fromName="Whoever"
4 fromAddress="somestudent@activeserverpages.com"
5 toName="Charles M. Carroll"
6 toAddress="cc@thebestweb.com"
7 subject="form send mail tutorial"
8 relay="mail.innerhost.com"
9 %>
10 <html><head>
11 <title>FormToBeMailed.asp</title>
12 </head><body bgcolor="#FFFFFF">
13 <form action="FormToBeMailedrespond.asp" method="GET">
14 Fill Out This Form For Us:<p>
15 First Name -> <input NAME="NameFirst" size="20"><br>
16 Last Name -> <input NAME="NameLast" size="20"><br>
17 Country -> <input NAME="Country" value="USA" size="20"><br>
18 State -> <input NAME="State" MaxLength="2" size="2"><br>
19 email copy to -> <input NAME="emailcopy" MaxLength="40" size="40"><br>
20
21 <input type="submit"><input type="reset">
22
23 <% ' do not touch these lines. Needed to send mail! %>
24 <input type="hidden" name="mail-from" value="<%=fromName%>">
25 <input type="hidden" name="mail-fromAddress" value="<%=fromAddress%>">
26 <input type="hidden" name="mail-to" value="<%=ToName%>">
27 <input type="hidden" name="mail-toaddress" value="<%=toaddress%>">
28 <input type="hidden" name="mail-subject" value="<%=subject%>">
29 <input type="hidden" name="mail-relay" value="<%=relay%>">
30 </form>
31 </body></html>
Here is the generic form responder that can be used with this or any form:
1 <html><head>
2 <title>serverobjectsmailrespond.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 ' ASPMail(tm) from http://www.serverobjects.com
6 ' is not part of ASP per se,
7 ' but a excellent third party component
8
9 my_from=request("mail-fromName")
10 my_fromAddress=request("mail-fromaddress")
11 my_to=request("mail-toName")
12 my_toAddress=request("mail-toaddress")
13 my_subject=request("mail-subject")
14 my_relay=request("mail-relay")
15
16 Set Mailer = Server.CreateObject("SMTPsvg.Mailer")
17 Mailer.RemoteHost = my_relay
18
19 Mailer.FromName = my_from
20 Mailer.FromAddress = my_fromAddress
21 Mailer.AddRecipient my_to, my_toaddress
22 Mailer.Subject = my_subject
23
24 for each whatever in request.querystring
25 If instr(whatever,"mail-")=0 then
26 Mailer.BodyText = whatever & "=" & vbcrlf
27 Mailer.BodyText = request.querystring(whatever) & vbcrlf & vbcrlf
28 end if
29 next
30
31 for each whatever in request.form
32 If instr(whatever,"mail-")=0 then
33 Mailer.BodyText = whatever & "=" & vbcrlf
34 Mailer.BodyText = request.form(whatever) & vbcrlf & vbcrlf
35 end if
36 next
37
38 my_emailcopy=request("emailcopy")
39 If my_emailcopy="" then
40 else
41 Mailer.AddRecipient "form filler",my_emailcopy
42 end if
43
44 If Mailer.SendMail then
45 Msg = "mail sent sucessfully!"
46 Else
47 Msg = "mail was not sent sucessfully<br>"
48 msg = msg & mailer.response & "<br>"
49 End If
50 response.write Msg
51 %>
52 </body></html>
Related Links:
CDO Download @
http://www.microsoft.com/exchange/55/downloads/CDO.htm
PRB: Permission Denied While Using CDONTS to Send Mail with Exchange @
http://support.microsoft.com/support/kb/articles/q228/4/65.asp
Formatting Mail as HTML @
http://msdn.microsoft.com/library/psdk/cdo/amsmtp_52an.htm
4guys Tutorial Attachments with CDO @
http://www.4guysfromrolla.com/webtech/112298-1.shtml
Configure SMNTP server with MMC for CDO @
http://support.microsoft.com/support/kb/articles/Q186/2/04.ASP
PRB: Error: MAPI_E_FAILONEPROVIDER (8004011D) Using CDO @
http://support.microsoft.com/support/kb/articles/Q195/8/49.ASP
ASP101 CDO tutorial @
http://www.asp101.com/samples/email_cdo.asp
A SUPERB, Insightful ADSI/CDO book @
http://www.learnasp.com/books/wroxadsicdoasp.asp
MS CDO Session Object Docs @
http://msdn.microsoft.com/library/psdk/cdo/amsmtp_3qcf.htm
MS Sample of CDO Send Method @
http://msdn.microsoft.com/library/psdk/cdo/amsmtp_4grj.htm
CDO Resources @
http://www.cdolive.com
SlipStick Exchange Resources @
http://www.slipstick.com
send HTML formatted emails w/pictures and attachments @
http://msdn.microsoft.com/library/partbook/asp20/usingcdofornts.htm
Attachments and CDO @
http://www.aspfree.com/devlinks/search.asp?file404=attach;cdo
Checking for Mail with CDO @
http://msdn.microsoft.com/library/psdk/cdo/_olemsg_checking_for_new_mail.htm
PRB: Path Not Found When Using CDONTS with IMC @
http://support.microsoft.com/support/kb/articles/Q235/6/81.ASP
IMAP4 for ASP @
http://www.infradig.com/index.shtml
Sending Automated Newsletters @
http://www.siteexperts.com/tips/backend/ts12/page1.asp
ServerObjects AspMail Tutorial @
http://www.learnasp.com/learn/formsendmail.asp
Jmail @
http://www.dimac.net/
PRB: ASP Running CDONTS Applications Out of Process Fails @
http://support.microsoft.com/support/kb/articles/Q184/2/70.ASP
Accessing Microsoft Exchange and Outlook Data as database @
http://msdn.microsoft.com/library/techart/olexcoutlk.htm
PRB: Problems Sending Many Messages Using Multiple Threads @
http://support.microsoft.com/support/kb/articles/q181/6/97.asp
Where to Acquire CDO Libraries @
http://support.microsoft.com/support/kb/articles/q171/4/40.asp
Scheduled Mailing @
http://swynk.com/friends/jones/articles/manage_web_server.asp
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
Uploading with SA-FileUp -- Simple Example
by David Wihl
Your file upload script(s) will consist of two parts:
To try
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 </TD>
26 </TR>
27 </TABLE>
28 </form>
29 </BODY></HTML>
To enable file upload, include an INPUT tag of
<TYPE="FILE"> in your HTML form.
When using a form to upload files,
you must set the following attributes: The responder to the form will look like this: 1 <HTML><HEAD> To process the upload on the server,
The TotalBytes property contains the size in bytes of the uploaded file.
The directory on the web server must have Read, Write, and Delete
NTFS permissions for the anonymous or authenticated user. Otherwise,
The Server-side Processing
2 <TITLE>Uploadsimplerespond.asp by softwareartisans.com</TITLE>
3 </HEAD><BODY>
4 Thank you for uploading your file.<br>
5 <% Set upl = Server.CreateObject("SoftArtisans.FileUp")
6 upl.Path = Server.Mappath ("/upload/tests")
7 upl.SaveAs "upload.tst"%><BR>
8 Total Bytes Written: <%=upl.TotalBytes%>
9 </BODY></HTML>
<% Set upl = Server.CreateObject("SoftArtisans.FileUp") %>
<% upl.SaveAs "C:\temp\upload.out" %>
Uploading with SA-FileUp -- Accessing Multiple Form Elements
You can usually use ASP's Request.Form object to access form values. However, when uploading files, you must change the form's encoding type to "multipart/form-data". The ASP Request.Form object does not understand data transmitted using this encoding type.
SA-FileUp includes two objects that provide the functionality of the ASP Request.Form object, but can understand the encoding type that is specific to file uploads. The two objects are Form and FormEx.
Form is used to access the values of solitary form elements. FormEx handles collections of form elements (e.g., listboxes, radio buttons, multiple files, etc.). Using FormEx to access solitary form elements may produce an error. To prevent errors, use each object only in its appropriate context. Syntactically, FormEx may only be used as follows,
To submit information with the upload, include additional <INPUT> tags. The form defined below contains a text input for the file description.
1 <html>
2 <head>
3 <title>Please Upload Your File</title>
4 </head>
5 <body>
6 <form enctype=multipart/form-data method=post action=multipartformrespond.asp>
7 <table>
8 <tr>
9 <td>Enter file description:</td>
10 <td><input type=text name=descrip></td>
11 </tr>
12 <tr>
13 <td>Select file:</td>
14 <td><input type=file name=f1></td>
15 </tr>
16 <tr>
17 <td><input type=submit value="Submit"></td>
18 <td></td>
19 </tr>
20 </table>
21 </form>
22 </body>
23 </html>
24
1 <HTML><HEAD>
2 <TITLE>Multipartformrespond.asp by softwareartisans.com</TITLE>
3 </HEAD><BODY>
4 Thank you for uploading your file.<br><br>
5 <%
6 Set upl = Server.CreateObject("SoftArtisans.FileUp")
7 upl.Path = Server.Mappath ("/upload") & "/" & "tests"
8 upl.Save
9 strFilename = Mid(upl.UserFilename, InstrRev(upl.UserFilename, "\") + 1)%>
10 File name: <%=strFilename%><br><br>
11 File description: <%=upl.form("descrip")%>
12 </BODY></HTML>
Note: Since the form contains only one <INPUT> of TYPE="FILE", you do not have to refer to it by name.
Set MaxBytes once and it will apply to all files in the current upload, limiting each of them to the value that you specify.
Using MaxBytes, you can prevent malicious users from filling your web server's hard disk.
1
2 <html>
3 <head>
4 <title>Limit File Size</title>
5 </head>
6 <body>
7 Thank you for uploading your file.<br>
8 <% Set upl = Server.CreateObject(SoftArtisans.FileUp) %>
9 <% upl.MaxBytes = 1000 '--- limit the upload size to 1000 bytes %>
10 The maximum file size that you are permitted to upload is <%=upl.MaxBytes%> bytes.<br>
11 <% upl.SaveAs C:\temp\upload.out %>
12 Total Bytes Written: <%=upl.TotalBytes%><br>
13 Server File Name: <%=upl.ServerName%><br>
14 Total Bytes Transmitted: <%=Request.TotalBytes%>
15 </body>
16 </html>
Use
1 <html>
2 <head>
3 <title>Limit File Type</title>
4 </head>
5 <body>
6 <% Set upl = Server.CreateObject("SoftArtisans.FileUp")
7
8 '--- Parse out the file name
9 FName = Mid(upl.UserFilename, InstrRev(upl.UserFilename, \) + 1)
10
11 '--- Retrieve the file's content type and assign it to a variable
12 FCONT = upl.ContentType
13
14 '--- Restrict the file types saved using a Select condition
15 Select Case LCase(FCONT)
16 Case "image/gif"
17 upl.Save
18 Response.Write <P> & FName & has been saved.
19
20 Case image/pjpeg
21 upl.Save
22 Response.Write <P> & FName & has been saved.
23
24 Case Else
25 upl.delete
26 Response.Write <P> & You may only upload gif and jpeg files.<BR>
27 Response.End
28 End Select
29
30 %>
31 </body>
32 </html>
Uploading with SA-FileUp -- Uploading Multiple Files
To upload multiple files, include multiple <INPUT> tags of TYPE=FILE.
1 <html>
2 <head>
3 <title>Please upload two files</title>
4 </head>
5 <body>
6 <form enctype=multipart/form-data action=multifilerespond.asp method=post>
7 <table>
8 <tr>
9 <td>Enter first file:</td>
10 <td><input type=file name=f1></td>
11 </tr>
12 <tr>
13 <td>Enter second file:</td>
14 <td><input type=file name=f2></td>
15 </tr>
16 <tr>
17 <td></td>
18 <td align=right><input type=submit value="Submit"></td>
19 </tr>
20 </table>
21 </form>
22 </body>
23 </html>
24
When processing the upload of multiple files, refer to each by name, as follows.
1 <html>
2 <head>
3 <title>Multiple File Upload Results</title>
4 </head>
5 <body>
6 Thank you for uploading your files.<br>
7 <% Set upl = Server.CreateObject(SoftArtisans.FileUp) %>
8 <% upl.Form(f1).SaveAs C:\temp\upload1.out %>
9 Total Bytes Written for File 1: <%=upl.Form(f1).TotalBytes%><br>
10 <% upl.Form(f2).SaveAs C:\temp\upload2.out %>
11 Total Bytes Written for File 2: <%=upl.Form(f2).TotalBytes%><br>
12 </body>
13 </html>
14
Related Links:
Upload: Simple Example @
http://www.learnasp.com/learn/uploadsimple.asp
SA File-UP FAQ @
http://www.softartisans.com/softartisans/freqasques.html
SA File-UP Code Samples @
http://www.softartisans.com/softartisans/samcod.html
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
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>The following code displays that monitor:
1 <html><head>Questions about this component can be directed to:
Undergoing renovation - SUB ListServSignup
Authentication & Security
Authenticate: Overview by Kevin Flick (authenticateoverview.asp) - Page 155
Authenticate: Comparison by Kevin Flick (authenticatecomparisons.asp) - Page 156
Authenticate: NT Challenge/Response by Kevin Flick (authenticatentcr.asp) - Page 157
Authenticate: Basic Authentication by Kevin Flick (authenticatebasic.asp) - Page 158
Authenticate: Cookies by Kevin Flick (authenticatecookies.asp) - Page 159
Authenticate: Certificates by Kevin Flick (authenticatecertificate.asp) - Page 160
Authenticate: Build Your Own by Kevin Flick (authenticatebuild.asp) - Page 161
Authenticate: Protect Pages via Login #1 (security.asp) - Page 162
Authenticate: Protect Pages via Login #2 (security2.asp) - Page 163
Authenticate: 3rd Party by Kevin Flick (authenticate3rdparty.asp) - Page 164
Authentix Flicks Support Listserver (aspflicks.asp) - Page 165
Authentication Overview
written and ©1998, 99 by Kevin Flick www.flicks.com
creator of Authentix
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.
Assuming you have the latest and greatest IIS, you have several choices when working with authentication including:
Authentication Comparison
written and ©1998, 99 by Kevin Flick www.flicks.com
creator of Authentix
In deciding which type of Authentication to use, it's important to keep the following points in mind:
| Which Type | Why use it? | Why not use it? | How to use it. |
|---|---|---|---|
| IIS NT Challenge Response | Why |
Why not
|
How |
| IIS Basic Authentication | Why |
Why not
|
How |
| A Third Party Basic Authentication filter | Why |
Why not
|
How |
| Write your own Basic Authentication filter | Why |
Why not
|
How |
| Cookie Based Authentication with ASP pages | Why |
Why not
|
How |
| Self-authenticating scripts | Why |
Why not
|
How |
| Certificate based authentication. | Why |
Why not
|
How |
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:
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.
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.
How to set up IIS Basic Authentication
Setting up IIS Basic Authentication is similar to setting up NTCR.
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 won't want Cookie Based Authentication with ASP pages if
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:
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 won't want Certificate based authentication if :
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.
There are several good references to help understand and use Client Certificate technology. Some articles that are recommended include:
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 won't want to write your own Basic Authentication filter if
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:
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).
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 |
the login screen where someone can enter username/password and confirm security level. It is a form that submits to securityloginrespond.asp |
| securitylogout.asp | the screen to abandon someone's username/password and security level |
| securitylevel1required.asp securitylevel2required.asp securitylevel3required.asp |
which can be included on individual pages to
limit access to people with that security level, i.e/: <!--#include file="securitylevel1required.asp"--> |
| securitytestlevel1.asp securitytestlevel2.asp securitytestlevel3.asp |
which demonstrate how security is implemented. These scripts cannot be seen unless you login. |
| securitynotallowed.asp | which anyone attempting to access a page without appropriate security level is redirected to. |
| /learn/test/customsecurity.mdb Download Database |
a 3 column Access database: username, password,
security level. Sample data is: user=chaz, password=chaz, securitylevel=1 user=chaz2, password=chaz2, securitylevel=2 user=chaz3, password=chaz3, securitylevel=3 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. |
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 <html><head>
2 <title>securitylogin.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <form action="securityloginrespond.asp" method="POST">
5 Sign In Page:<p>
6 Name -> <input NAME="userName" size="20"><br>
7 Password -> <input NAME="userPassword" size="20"><br>
8 <input type="submit"><input type="reset">
9 </form></body></html>
Here is the securityloginrespond.asp script:
1 <html><head>
2 <TITLE>securityloginrespond.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 myname=request.form("username")
6 mypassword=request.form("userpassword")
7 set conntemp=server.createobject("adodb.connection")
8
9 dbname="/learn/test/secret/customsecurity.mdb"
10 myconnect="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE="
11 myconnect=myconnect & server.mappath(dbname)& ";"
12
13 conntemp.Open myconnect
14
15 sqltemp="select * from users where user='"
16 sqltemp=sqltemp & myname & "'"
17 set rstemp=conntemp.execute(SQLTemp)
18 If rstemp.eof then%>
19 we don't have a user named <%=Myname%> on file!<br>
20 Try <A href='securitylogin.asp'>Logging in</a> again
21 <%response.end
22 end if
23 If rstemp("Password")=mypassword then
24 session("name")=rstemp("user")
25 session("securitylevel")=rstemp("securitylevel")
26 response.write "Security Level=" & session("securitylevel")
27 else%>
28 Password Unrecognized<br>
29 Try <A href='securitylogin.asp'>Logging in</a> again
30 <%response.end
31 end if
32 rstemp.close
33 conntemp.close
34 set rstemp=nothing
35 set conntemp=nothing
36 %>
37 </body></html>
Here is the securitylogout.asp script:
1 <html><head>
2 <title>securitylogout.asp</title>&
3 <body>
4 <%
5 session.abandon
6 %>
7 Logged out Now!!!
8 </body>
9 </html>
Here is the securitylevel1required.asp script:
1 <%
2 response.expires=0
3 if session("securitylevel")>0 then
4 ' nothing to do
5 else
6 response.redirect "securityunauthorized.asp"
7 end if
8 %>
Here is the securityunauthorized.asp script:
1 <html><head>
2 <title>unauthorized</title>&
3 <body>
4 You are unauthorized to read that page!
5 </body></html>
Here is the securitytestlevel1.asp script:
1 <!--#include file="securitylevel1required.asp"-->
2 <html><head>
3 <title>New Page </title>
4 <META HTTP-EQUIV="Expires" CONTENT="Tue, 04 Dec 1993 21:29:02 GMT">
5 </head><body>
6 My level 1 secret is Pretty Hot!!!<br>
7 Our president may not be as honest as we believed!
8 </body>
9 </html>
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
Authentix, a third party Basic Authentication filter is the way to go if
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.
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.
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.
Related Links:
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
Troubleshooting, Error Trapping
Errors: Basics (errors1.asp) - Page 167
Errors: More Ways To Trap (errors2.asp) - Page 168
Errors: Resources Online (errormore.asp) - Page 169
Errors: Trapping EVERY Error (dbtablewitherrortrap.asp) - Page 170
Debug variables Easy Way (debug1.asp) - Page 171
Errors: DB Error Information Trapping (dbtroubleshoot.asp) - Page 172
DBFAQ: Operation must use Updatable Query (FAQdbUpdate.asp) - Page 173
DBFAQ: User Entered ' in field (FAQdbSinglequote.asp) - Page 174
DBFAQ: LIKE operator * not working (FAQdbLIKE.asp) - Page 175
DBFAQ: retrieving MEMO/BLOBs generates error (FAQdbMEMO.asp) - Page 176
DBFAQ: Syntax Error in SQL Statement (FAQdbSQLSyntax.asp) - Page 177
SQL Debugging Made Easy (debug2.asp) - Page 178
Errors: Trapping Open Connections (dbtroubleshootopen.asp) - Page 179
Troubleshoot: Getting Help from Lists! (asptroubles.asp) - Page 180
Troubleshoot: Worldwide (asptroubles2.asp) - Page 181
Troubleshoot: Specialized (asptroubles3.asp) - Page 182
Troubleshoot: Version of ASP Sofware (versioncheck.asp) - Page 183
Troubleshoot: Registered Components (componentchecker.asp) - Page 184
Troubleshoot: DB Drivers by Christophe Wille (connectioninfo.asp) - Page 185
PWS: Personal Web Server Introduction (PWS.asp) - Page 186
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 <TITLE>errordivide1.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <%
4 ' ASP program that works if numbers are legit
5 x=7
6 y=2
7 z=x/y
8 response.write z & "<br>"
9 %>
10 </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 <TITLE>errordivide2.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <%
4 ' ASP program that works if numbers are legit
5 x=7
6 y=2 ' if changed to 0 this will crash
7 z=x/y
8 response.write z & "<br>"
9 %>
10 </body></html>
Now we use the VBScript error trapping to present a message instead of a catastrophic script error.
1 <TITLE>errordivide3.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <%
4 ' ASP program that works if numbers are legit
5 on error resume next
6 x=7
7 y=0
8 z=x/y
9 response.write z & "<br>"
10
11 If err.number=0 then
12 response.end
13 end if
14 pad=" "
15 response.write "<b>VBScript Errors Occured!<br>"
16 response.write parm_msg & "</b><br>"
17 response.write pad & "Error Number= #<b>" & err.number & "</b><br>"
18 response.write pad & "Error Desc.= <b>" & err.description & "</b><br>"
19 response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>"
20 response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>"
21 response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>"
22 %>
23 </body></html>
Error Trapping #2 by Charles Carroll
Errors can only be caught if your code explicitly traps them. Right?
Actually, there is an undocumented IIS feature where all errors can be logged at the server level without resorting to page level error trapping.
http://www.15seconds.com/Issue/981015.htm
explains this undocumented feature.
/learn/perfcounters.asp
shows how to use a FREE Softwing Component to actually see that logged data
remotely from a browser.
In general, their debugging section @
http://www.15seconds.com/focus/Debugging.htm
is useful to read up on many deugging techniques.
People debugging various ASP Errors may find Juan Llibre's knowledge base index at http://www.asptracker.com invaluable!
Error-Trapping Debugging Resources
Error-trapping and debugging is handled in much more depth at other sites actually. Here they are:
Easy Debugging Tips by Steve Smith
http://www.asptoday.com/articles/19990421.htmSimple ASP debugging tricks by Steven Schofield
http://www.asptoday.com/articles/19990721.htmUndocumented Logging Features exist in ASP
http://www.15seconds.com/Issue/981015.htmIIS5 has central error handling
http://www.asptoday.com/articles/19990308.htmWriting to the event log
http://www.asptoday.com/articles/19990722.htmDevising an HTTP debugging method for IIS by Marco Gregorini
http://www.asptoday.com/articles/19990324.htmDebugging your ASP Scripts By Abd Shomad
http://www.4guysfromrolla.com/webtech/021099-1.shtmlSyntax Errors from Documentation
http://www.learnasp.com/iishelp/debug/sdbug%5F8.htmDebugging Active Server Objects by Wayne Berry
http://www.15seconds.com/Issue/970316.htm
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 <TITLE>dbtablewitherrortrap.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <!--#include file="lib_errors.asp"-->
4 <%
5 on error resume next
6 attempt="create connection object"
7 set conntemp=server.createobject("adodb.connection")
8 Call ErrorVBScriptReport(attempt)
9
10 attempt="opening DSN"
11 conntemp.open "DSN=Student;uid=student;pwd=magic"
12 Call ErrorVBScriptReport(attempt)
13 Call ErrorADOReport(attempt,conntemp)
14
15 attempt="select * from authors where AU_ID<16"
16 set rstemp=conntemp.execute(attempt)
17 Call ErrorVBScriptReport(attempt)
18 Call ErrorADOReport(attempt,conntemp)
19 If rstemp.eof then
20 response.write "No records matched your query" & "<P>"
21 response.write attempt
22 response.end
23 end if
24
25 attempt="counting fields"
26 howmanyfields=rstemp.fields.count -1
27 Call ErrorVBScriptReport(attempt)
28 Call ErrorADOReport(attempt,conntemp)
29 %>
30 <table border=1>
31 <tr>
32 <% 'Put Headings On The Table of Field Names
33 for i=0 to howmanyfields %>
34 <td><b><%=rstemp(i).name %></B></TD>
35 <% next %>
36 </tr>
37
38 <% ' Now lets grab all the records
39 do while not rstemp.eof %>
40 <tr>
41 <% for i = 0 to howmanyfields%>
42 <td valign=top><%=rstemp.fields(i)%></td>
43 <% next %>
44 </tr>
45 <%
46 rstemp.movenext
47 loop
48 rstemp.close
49 set rstemp=nothing
50 conntemp.close
51 set conntemp=nothing
52 %>
53 </table>
54 </BODY>
55 </HTML>
The error trapping library looks like this:
1 <%
2 SUB ErrorVBScriptReport(parm_msg)
3 If err.number=0 then
4 exit sub
5 end if
6 pad=" "
7 response.write "<b>VBScript Errors Occured!<br>"
8 response.write parm_msg & "</b><br>"
9 response.write pad & "Error Number= #<b>" & err.number & "</b><br>"
10 response.write pad & "Error Desc.= <b>" & err.description & "</b><br>"
11 response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>"
12 response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>"
13 response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>"
14 END SUB
15
16 SUB ErrorADOReport(parm_msg,parm_conn)
17 HowManyErrs=parm_conn.errors.count
18 IF HowManyErrs=0 then
19 exit sub
20 END IF
21 pad=" "
22 response.write "<b>ADO Reports these Database Error(s) executing:<br>"
23 response.write SQLstmt & "</b><br>"
24 for counter= 0 to HowManyErrs-1
25 errornum=parm_conn.errors(counter).number
26 errordesc=parm_conn.errors(counter).description
27 response.write pad & "Error#=<b>" & errornum & "</b><br>"
28 response.write pad & "Error description=<b>"
29 response.write errordesc & "</b><p>"
30 next
31 END SUB
32 %>
Easy Debugging of Variables by Charles Carroll
This page demonstrates how you can
print several variables in one step without resorting to:
<%
response.write "fname=<b>" & fname &
"</b><br>"
response.write "lname=<b>" & lname &
"</b><br>"
response.write "x=<b>" & x &
"</b><br>"
response.write "y=<b>" & y &
"</b><br>"
%>
by taking advantage of VB Eval and encapsulating it into a subroutine to do all the work for you.
1 <html><head>
2 <title>debug1.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 fname="Jennifer"
6 lname="Jones"
7 x=9
8 y=7
9 Call ShowVars("fname,lname,x,y")
10 %>
11 </body></html>
12 <!--#include file="lib_debug1.asp"-->
The library that does the work:
1 <%
2 SUB ShowVars(parmVars)
3 dim myparameters
4 myparameters=SPLIT(parmVars,",")
5 parmcount=ubound(myparameters)
6 for counter=0 to parmcount
7 thisvar=myparameters(counter)
8 strexec=thisvar
9 strexec=eval(strexec)
10 strall=strall & "<b>" & thisvar & "</b>=" & strexec & "<br>"
11 next
12 response.write strall
13 END SUB
14 %>
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 <html><head>
2 <title>dbtroubleshoot.asp</title>&
3 <body>
4 <!--#include file="lib_errors.asp"-->
5 <%
6 on error resume next
7 Set Conn = Server.CreateObject("ADODB.Connection")
8 conn.open "DSN=student;uid=student;password=magic"
9
10 SQLstmt = "INSERT INTO junk (city,state,zip) VALUES ('Rockville','MD','20849')"
11 Set RS = Conn.Execute(SQLStmt)
12
13 Call ErrorVBScriptReport("Insert Statement")
14 Call ErrorADOReport(SQLstmt,conn)
15
16 rs.close
17 set rs=nothing
18 Conn.Close
19 set conn=nothing%>
20
21 </body></html>
Here is the include file that displays appropriate errors:
1 <%
2 SUB ErrorVBScriptReport(parm_msg)
3 If err.number=0 then
4 exit sub
5 end if
6 pad=" "
7 response.write "<b>VBScript Errors Occured!<br>"
8 response.write parm_msg & "</b><br>"
9 response.write pad & "Error Number= #<b>" & err.number & "</b><br>"
10 response.write pad & "Error Desc.= <b>" & err.description & "</b><br>"
11 response.write pad & "Help Context= <b>" & err.HelpContext & "</b><br>"
12 response.write pad & "Help File Path=<b>" & err.helpfile & "</b><br>"
13 response.write pad & "Error Source= <b>" & err.source & "</b><br><hr>"
14 END SUB
15
16 SUB ErrorADOReport(parm_msg,parm_conn)
17 HowManyErrs=parm_conn.errors.count
18 IF HowManyErrs=0 then
19 exit sub
20 END IF
21 pad=" "
22 response.write "<b>ADO Reports these Database Error(s) executing:<br>"
23 response.write SQLstmt & "</b><br>"
24 for counter= 0 to HowManyErrs-1
25 errornum=parm_conn.errors(counter).number
26 errordesc=parm_conn.errors(counter).description
27 response.write pad & "Error#=<b>" & errornum & "</b><br>"
28 response.write pad & "Error description=<b>"
29 response.write errordesc & "</b><p>"
30 next
31 END SUB
32 %>
There is a set of links to Microsoft ADO
knowledge base articles @
http://www.asptracker.com/demo/adokb1.asp
which may prove invaluable.
Database listservers 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://support.microsoft.com/support/kb/articles/Q175/1/68.ASP
shows some other causes besides permissions.
Database listservers 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
Database listservers 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"
Database listservers for help!
FAQ #4: My memo fields are not
working. I get the error message:
Microsoft OLE DB Provider for ODBC Drivers error '80020009'
or other errors
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 fields have the following issues
Issue #1: Memo fields may only be reliably fetched once.
If Len(rstemp("comments"))=0 THEN
....
END IF %>
the comment was <%=rstemp("comments")%>!is likely to fail because an attempt to fetch it more than once was made.
memo_comments=rstemp("comments")
If LEN(memo_comments)=0 THEN
....
END IF %>
the comment was <%=memo_comments%>!
Issue #2: Memo Fields must be listed last in the query.
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.
Database listservers 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.
Debug SQL Easily by Charles Carroll
This page demonstrates how you can format a SQL statement to help pinpoint common errors. Common errors are discussed @
Common SQL Errors
http://www.learnasp.com/learn/dbtroubleshoot2.asp
Syntax Error in SQL Statement
http://www.learnasp.com/learn/FAQdbSQLSyntax.asp
by encapsulating ADO error trapping and display the SQL in an attractive form that separates components onto separate lines and makes debugging simpler (missing commas, single-quotes and like).
1 <html><head>
2 <title>debug2.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 on error resume next
6 myDSN = "DSN=Student;uid=student;pwd=magic"
7 Set Conn = Server.CreateObject("ADODB.Connection")
8 conn.open myDSN
9
10 SQL="update test set fname='Ted',lname='Wilson',city='Rockville',state='MD',zip='20849',rank=7,datehire='1/15/92', SSN='219-92-2677' WHERE personid=7"
11 Conn.Execute SQL,howmany
12 IF howmany="" THEN
13 howmany=0
14 END IF
15 response.write "Affected <b>" & howmany & "</b> records<br>"
16 Call SQLerrorreport(SQL,conn)
17
18 SQL="Insert Into junk (fname,lname,city,state,zip,rank,datehire,ssn) VALUES ('ted','wilson','rockville', 'md', '20849',7,'1/15/92','219-92-2677')"
19 Conn.Execute SQL,howmany
20 IF howmany="" THEN
21 howmany=0
22 END IF
23 response.write "Affected <b>" & howmany & "</b> records</b><br>"
24 Call SQLerrorreport(SQL,conn)
25
26 Conn.Close
27 set conn=nothing
28 %>
29 </body></html>
30 <!--#include file="lib_debug2.asp"-->
The library that does the work:
1 <%
2 SUB SQLErrorReport(parmSQL,parm_conn)
3 HowManyErrs=parm_conn.errors.count
4 IF HowManyErrs=0 then
5 exit sub
6 END IF
7 pad=" "
8 lb="<br>" & vbcrlf
9 comma="<font color=red>"
10 squote="<font color=blue>"
11 SQLstmt=parmSQL
12 SQLstmt=replace(SQLstmt,",", "<b>" & comma & ",</b></font>" & lb)
13 SQLstmt=replace(SQLstmt,"'","<b>" & squote & "'</b></font>")
14 SQLstmt=replace(SQLstmt,"(",lb & "(")
15 SQLstmt=replace(SQLstmt,")",")" & lb)
16
17 response.write "SQL statement attempted:<br>"
18 response.write SQLstmt & "<br>"
19 response.write "ADO Error(s) executing:<br>"
20 for counter= 0 to HowManyErrs-1
21 errornum=parm_conn.errors(counter).number
22 errordesc=parm_conn.errors(counter).description
23 response.write pad & "Error#=<b>" & errornum & "</b><br>"
24 response.write pad & "Error description=<b>"
25 response.write errordesc & "</b><p>"
26 next
27 END SUB
28 %>
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 <html><head>
2 <title>dbtroubleshoot.asp</title>&
3 <body>
4 <%
5 on error resume next
6 Set Conn = Server.CreateObject("ADODB.Connection")
7 my_DSN="DSN=student;uid=student;password=magic2"
8 conn.open my_DSN
9 Call CheckOpen
10
11 Conn.Close
12 set conn=nothing
13
14 SUB CheckOpen
15 If err.number>0 then%>
16 <b>VBScript Errors Occured:</b><br>
17 Error Number=<%=err.number%><br>
18 Error Descr.=<%=err.description%><br>
19 Help Context=<%=err.helpcontext%><br>
20 Help Path=<%=err.helppath%><br>
21 Native Error=<%=err.nativeerror%><br>
22 Source=<%=err.source%><br>
23 SQLState=<%=err.sqlstate%><P>
24 <%else%>
25 No VBScript problems occured!<p>
26 <%end if
27 IF conn.errors.count> 0 then%>
28 <b>ADO Reports these Database Error(s):</b><br>
29 <%
30 maxerrors=conn.errors.count-1
31 for counter= 0 to maxerrors
32 DBErrorNum=conn.errors(counter).number
33 DBErrorDesc=conn.errors(counter).description
34 SELECT CASE DBErrorNum
35 CASE -2147467259
36 response.write "Problem => <b>Bad DSN</b><br>"
37 response.write "DSN => <b>" & my_DSN & "</b><br>"
38 CASE -2147217843
39 response.write "Problem => <b>Bad Login Info</b><br>"
40 response.write "DSN => <b>" & my_DSN & "</b><br>"
41 exit sub
42 CASE ELSE%>
43 Error # = <b><%=DBErrorNum%></b><br>
44 Error description = <b><%=DBerrorDesc%></b><p>
45 <%END SELECT
46 next
47 else%>
48 Everything Went Fine
49 <%
50 end if
51
52 END SUB%>
53 </body></html>
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:
ALL Oracle Lists
ALL RDS (Remote Data Services) Lists
ALL SQL Server Lists
[aspngdata] ASP+/ADO+, Templates, Lists, Repeaters
[aspsqlhowto] SQL: Joins, complex queries, shaping
[aspAccess] MS-Access
[aspAcc2SQL] MS-Access to SQLserver migration
[aspAcc2SQL] Tough ASP + MS-Access Questions only
[aspBtrieve] Btrieve and ASP
[aspCOMTICICS] COMTI and CICS w/ASP
[aspDB2as400] DB2 and/or AS400
[aspDbase] Dbase
[aspFileMaker] FileMaker & ASP
[aspFox] Fox/Visual FoxPro
[aspGenericdb] FREE code to display/edit data
[aspInformix] Informix
[aspMSDE] Asp with free MSDE Engine
[aspmySQL] MySQL and ASP
[aspParadox] Paradox
[aspreports] Reports/Printing (Crystal, PDF, etc.)
[aspSAP] SAP + ASP can mix
[aspSybase] 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
[aspfreeforall] ANY questions
[aspnotnewbie] NO beginners
[aspadvanced] ONLY toughest questions
note- Strict Rules for advanced lists
[aspinstall] Installing,Upgrading PWS & ASP
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.
[aspArabic]
[aspBengali]
[aspChinese]
[aspDanish]
[aspDutch]
[aspFarsi]
[aspFinnish]
[aspFrench]
[aspGerman] German ASP Help
[aspdeJobs] German Jobs
[aspdecoffeehouse] German Coffee House
[aspdebeginners] German ASP Beginners
[aspdedatabase] German ASP Databases
[aspdeadministration] German ASP Server Admin
[aspdeDOTNET] German ASP+ / DOT NET
[aspDEXML] German ASP XML
[aspgreek] Greek
[asphebrew] Hebrew
[aspHindi] Hindi
[aspIndonesian] Indonesian
[aspIcelandic]
[aspItalian]
[aspJapanese]
[aspKorean]
[aspMalay]
[aspNepali]
[aspNorweigan]
[aspPolish]
[aspPortugese]
[aspRussian]
[aspSpanish]
[aspSwedish]
[aspSwedishAdvanced]
[aspTamil]
[aspTurkish]
[aspThai]
[aspUrdu]
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
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>
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 <%response.buffer=true%>
2 <TITLE>componentchecker.asp</TITLE>
3 <body bgcolor="#FFFFFF">
4 <%
5 dim successSTR, FailSTR, checkSTR
6 whichfile=server.mappath("component.ini")
7 Set fs = CreateObject("Scripting.FileSystemObject")
8 Set thisfile = fs.OpenTextFile(whichfile, 1, False)
9
10 counter=0
11
12 do UNTIL thisfile.AtEndOfStream
13 counter=counter+1
14 thisline=thisfile.readline
15 attempt=trim(thisline)
16 pad=" "
17 DO WHILE attempt="" AND thisfile.atendofStream=false
18 thisline=thisfile.readline
19 attempt=trim(thisline)
20 LOOP
21 If mid(thisline,1,1)="[" then
22 ' ignore
23 CheckSTR=CheckSTR & thisline & " "
24 lastcategory=category
25 category=lcase(thisline)
26 oldcategory=mid(category,1,Len(category)-1)
27 category=replace(category,"www.","<a href='http://www.")
28 IF instr(category,"href")>0 then
29 category=mid(category,2)
30 category=category & "'>" & oldcategory & "]</a>"
31 END IF
32 group= "<b>" & category & " component group</b><br>"
33 successcount=0
34 failcount=0
35 thisline=thisfile.readline
36 attempt=thisline
37 response.flush
38 end if
39 on error resume next
40 set tempobject=server.createobject(attempt)
41 eol="<br>" & vbcrlf
42 whicherr=err.number
43 If whicherr=0 then
44 if successcount=0 then
45 successSTR=successSTR & group
46 end if
47 vleft=" (ver="
48 vright=") "
49 SELECT CASE lcase(attempt)
50 CASE "adodb.connection"
51 version= vleft & tempobject.version & vright
52 CASE ELSE
53 version=""
54 END SELECT
55
56 successSTR= successSTR & pad & "<b>" & attempt & version & "</b> successfull!" & eol
57 successcount=successcount+1
58 else
59 if failcount=0 then
60 FailSTR=FailSTR & group
61 end if
62 IF whicherr=-2147221005 THEN
63 msg = " is not registered!"
64 ELSE
65 msg = " failed. Error #" & whicherr
66 END IF
67 FailSTR= failSTR & pad & "<b>" & attempt & "</b>" & msg & eol
68 failcount=failcount+1
69 end if
70 set tempobject=nothing
71 loop
72
73 thisfile.Close
74 set thisfile=nothing
75 set fs=nothing
76
77 response.write "Checked: " & checkSTR & "<hr>"
78 response.write successSTR & "<hr>"
79 response.write failSTR
80 %>
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 [standard]
2 mswc.browsertype
3 mswc.nextlink
4 scripting.dictionary
5 scripting.filesystemobject
6
7 [ado]
8 adodb.recordset
9 adodb.connection
10 adodb.command
11
12 [cdo]
13 CDONTS.NewMail
14
15 [cyscape]
16 cyScape.browserObj
17
18 [indexserver]
19 ixsso.Query
20 ixsso.Util
21
22 [Lyris]
23 Lyris.LCP
24
25 [http://msdn.microsoft.com/scripting]
26 Wscript.Shell
27
28 [msfreebies]
29 iissample.asp2htm
30 iissample.contentrotator
31 iissample.registry
32 iissample.summaryinfos
33 iissample.tracer
34 mswc.adrotator
35 mswc.counters
36 mswc.myinfo
37 MSWC.PageCounter
38 MSWC.PermissionChecker
39 mswc.tools
40 mswc.loadbalance
41
42 [msXML]
43 microsoft.XMLHTTP
44 microsoft.XMLDOM
45
46 [www.aspdb.com]
47 ASPdb.Free
48 ASPdb.View
49 ASPdb.Pro
50 ASPdb.EP
51
52 [www.serverobjects.com]
53 ASPChart.Chart
54 AspConv.Expert
55 AspDNS.Lookup
56 AspFile.FileObj
57 AspHTTP.Conn
58 AspImage.Image
59 AspInet.FTP
60 AspMX.Lookup
61 AspNNTP.Conn
62 AspPager.Pager
63 SMTPsvg.Mailer
64
65 [www.softartisans.com]
66 SoftArtisans.FileUp
67 SoftArtisans.SACheck
68 SoftArtisans.SASessionPro
69 SoftArtisans.FileManager
70 EZsite.Calender
71 EZsite.CalendarManager
72 EZsite.WebNotes
73
74 [www.active4.com]
75 ActiveLaunch.Control
76 ActiveSAR.SearchAndReplace
77 ActiveShopper.Cart
78 ActiveShopper.BasketItem
79 FileTouch.Control
80 PCAuthX.Authorizer
81 Prt2Disk.Control
82 SemClient.Control
83 SPrinterPro.Object
84 TimeSpan.Control
85 WWWPrint.Client
86
87 [Zaks Software]
88 ZaksPop3.Server
89 JavaPop3.Mailer
90
91 [www.persits.com]
92 Persits.MailSender
93
94 [www.oceantek.com]
95 ASPL.Login
96
97 [www.able-consulting.com]
98 ACI.WhoIs
99
100 [www.softwing.com]
101 Softwing.EventLogReader
102 Softwing.OdbcRegTool
103 w3info.w3info.1
104 InetCtls.Inet.1
105 Softwing.AspQPerfCounters
106 SQLOLE.SQLServer
107 SOFTWING.ASPEventlog
108 SOFTWING.ASPtear
109 SOFTWING.EDConverter
110 SOFTWING.EventLogReader
111 SOFTWING.FileCache.1
112 SOFTWING.OdbcRegTool
113 SOFTWING.LocaleFormatter
114 SOFTWING.Profiler
115
116 [www.dougdean.com]
117 EZsite.EZuploadLite
118
119 [www.algonet.se/~jekman]
120 lightcom.xBrowser
121 lightcom.xContent
122 lightcom.xPop3
123 lightcom.xSMTP
124 lightcom.xTree
125 lightcom.xBrowser
126 JESoftware.xContent
127 JESoftware.xPop3
128 JESoftware.xSMTP
129 JESoftware.xTree
130
131 [tech.dimac.net]
132 Socket.TCP
133
134 [www.de-info.com]
135 checkemail.maccheckemail
136
137 [www.pstruh.cz]
138 TCPIP.Trace
139 TCPIP.DNS
140
141 [www.dana-net.com/products/aspcomponents/magicregistry]
142 MagicRegistry.Tricks
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 <html><head>
2 <title>connectioninfo.asp by Christophe Wille http://www.softwing.com</title>
3 </head>
4 <!--#include file="lib_connectioninfo.asp"-->
5 <body>
6 <%
7 response.write "<hr>SQL Server Connection"
8 Call DSNinfo("DSN=student;uid=student;pwd=magic")
9 response.write "<hr>Access Connection Connection"
10 theDSN="DRIVER={Microsoft Access Driver (*.mdb)};DBQ="
11 theDSN=theDSN & server.mappath("/learn/test/biblio.mdb")
12 Call DSNInfo(theDSN)
13 %>
14 </body>
15 </html>
The Include file looks like this:
1 <%
2 SUB DSNInfo(strDSN)
3 Set cnn1 = Server.CreateObject("ADODB.Connection")
4 Set rsQuery = Server.CreateObject("ADODB.RecordSet")
5 cnn1.open strDSN
6
7 response.write "ADO Version: " & cnn1.Version
8 response.write "<BR>" & vbcrlf
9 response.write strVersionInfo & "DBMS Name: " & cnn1.Properties("DBMS Name")
10 response.write "<BR>" & vbcrlf
11 response.write "DBMS Version: " & cnn1.Properties("DBMS Version")
12 response.write "<BR>" & vbcrlf
13 response.write "OLE DB Version: " & cnn1.Properties("OLE DB Version")
14 response.write "<BR>" & vbcrlf
15 response.write "Provider Name: " & cnn1.Properties("Provider Name")
16 response.write "<BR>" & vbcrlf
17 response.write "Provider Version: " & cnn1.Properties("Provider Version")
18 response.write "<BR>" & vbcrlf
19 response.write "Provider Friendly Name: " & cnn1.Properties("Provider Friendly Name")
20 response.write "<BR>" & vbcrlf
21
22 If 0 = Instr(LCase(cnn1.Properties("Provider Name")),"oledb") then
23 ' ### no OLE DB Provider used, therefore :
24 response.write "Driver Name: " & cnn1.Properties("Driver Name")
25 response.write "<BR>" & vbcrlf
26 response.write "Driver Version: " & cnn1.Properties("Driver Version")
27 response.write "<BR>" & vbcrlf
28 response.write "Driver ODBC Version: " & cnn1.Properties("Driver ODBC Version")
29 response.write "<BR><BR>"
30 end if
31
32 Set rsQuery = nothing
33 Set cnn1 = nothing
34
35
36 END SUB
37 %>
Personal Web Server (PWS) by Charles Carroll
The Personal Web Server is a marvellous tool because it lets you develop and test websites
The address of your personal web server is:
It has other aliases, like http://localhost but it true reliable name is the one above.
Code w/all ASP Features. Quality, Re-usable Code
Strings: Core Functions (strings.asp) - Page 188
Strings: SPLIT Function (stringsplit.asp) - Page 189
Strings: REPLACE Function (stringreplace.asp) - Page 190
Strings: JOIN Function (stringjoin.asp) - Page 191
Arrays: Basics (arrays.asp) - Page 192
Arrays: Variable Size (arrays2.asp) - Page 193
Arrays: Best Way To Load (arrays3.asp) - Page 194
Arrays: Resources Online (arraysmore.asp) - Page 195
Dictionary Objects (dictionary.asp) - Page 196
Getrows Ultimate! (getrowsultimate.asp) - Page 197
Subroutine: Working with Dates #1 (subdates.asp) - Page 198
Subroutine: Working with Dates #2 (subdates2.asp) - Page 199
Subroutine: Query2Table (subdbtable.asp) - Page 200
Subroutine: Query2List (subdblist.asp) - Page 201
Subroutine: Highly Reusable (subreusable.asp) - Page 202
Subroutines w/Dictionary Objects (subdictionary.asp) - Page 203
Getrows Ultimate! (getrowsultimate.asp) - Page 204
Subroutine: List Box w/optional params (subDBlistbest.asp) - Page 205
Subroutine: Abstract HTML by Phil Paxton (libhtml.asp) - Page 206
Function: Working Days (functionworkingdays.asp) - Page 207
New Features in VBScript version5 (vbs5.asp) - Page 208
Text Files: Reading Them off Server (txtread.asp) - Page 209
Text Files: Writing Them on Server (txtwrite.asp) - Page 210
Text Files: Meyers-Briggs parsing #1 (mb1.asp) - Page 211
Text Files: Meyers-Briggs parsing #2 (mb2.asp) - Page 212
Text Files: Meyers-Briggs parsing #3 (mb3.asp) - Page 213
XML/XLST Myers-Briggs example (xmlmb.asp) - Page 214
Content Linker: Prev/Next Page (cl.asp) - Page 215
Content Linker: Table of Contents (cl2.asp) - Page 216
Content Linker: Listbox of contents (cl3.asp) - Page 217
Content Linker Library (contentlinker.asp) - Page 218
File Objects: Read Directory (fileobjects.asp) - Page 219
File Objects: Display Directory as Links/Graphics (fileobjects2.asp) - Page 220
File Objects: Read Disk Drive by Steven Harper (fileobjects3.asp) - Page 221
File Objects: Show Dir List by Tim Foster (fileobjects4.asp) - Page 222
Graphic Size Detector (graphicdetect.asp) - Page 223
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 <html><head>
2 <title>citystatezip.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <Form action = "citystatezipRespond.asp" method="post">
5 Enter City <b>,</b> State Zip<p>
6 <Input NAME="CSZ" size ="40"><p>
7 <Input type="submit" value="Here is my Data!">
8 </form>
9 </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 <html><head>
2 <title>citystateziprespond.asp</title>
3 </head><body>
4 <%
5 alldata=request("csz")
6 IF instr(alldata,",")=0 THEN%>
7 You need a comma<br>,<br>between city and state!<p>
8 <%response.end
9 END IF
10
11 findcomma=instr(alldata,",")
12 city=mid(alldata,1,findcomma-1)
13 leftover=trim(mid(alldata,findcomma+1))
14
15 findspace=instr(leftover," ")
16 state=mid(leftover,1,findspace)
17 leftover=mid(leftover,findspace+1)
18
19 zip=leftover
20
21 response.write "city=" & city & "<br>"
22 response.write "state=" & state & "<br>"
23 response.write "zip=" & zip & "<br>"
24
25
26 %>
27 </body></html>
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 <html><head>
2 <title>states.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <form action="statesplitrespond.asp" method="post">
5 Enter State (or many states separated by <b>,<b><p>
6 <input NAME="states" size="40"><p>
7 <input type="submit" value="Get The Publishers!">
8 </form>
9 </body></html>
statesplitrespond.asp
1 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
2 <html><head>
3 <title>statesrespond.asp</title>&
4 <body>
5 <%
6 mySQL="select * from publishers " & whereclause
7 myDSN="DSN=student;uid=student;pwd=magic"
8 public allstates
9 tempinput=request("states")
10 allstates=split(tempinput,",")
11
12 maxcounter=ubound(allstates)
13
14 whereclause=" where state='" & allstates(0) & "'"
15 FOR counter=1 TO maxcounter
16 thisstate=allstates(counter)
17 whereclause=whereclause & " OR state='" & thisstate & "'"
18 NEXT
19 mySQL=mySQL & whereclause
20 Call Query2Table(mySQL,myDSN)
21 %>
22 </body></html>
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 <html><head>
2 <title>statereplace.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <form action="statereplacerespond.asp" method="post">
5 Enter State (or many states separated by <b>,<b><p>
6 <input NAME="states" size="40"><p>
7 <input type="submit" value="Get The Publishers!">
8 </form>
9 </body></html>
statereplacerespond.asp
1 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
2 <html><head>
3 <title>statesrespond.asp</title>&
4 <body>
5 <%
6 mySQL="select * from publishers " & whereclause
7 myDSN="DSN=student;uid=student;pwd=magic"
8
9 tempinput=request("states")
10
11 whereclause=" where state='" & tempinput
12 whereclause=replace(whereclause, ",","' OR state='")
13 whereclause=whereclause & "'"
14
15 mySQL=mySQL & whereclause
16 response.write mySQL
17 Call Query2Table(mySQL,myDSN)
18 %>
19 </body></html>
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 <html><head>
2 <title>statejoin.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <form action="statejoinrespond.asp" method="post">
5 Enter State (or many states separated by <b>,<b><p>
6 <input NAME="states" size="40"><p>
7 <input type="submit" value="Get The Publishers!">
8 </form>
9 </body></html>
statejoinrespond.asp
1 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
2 <html><head>
3 <title>statejoinrespond.asp</title>&
4 <body>
5 <%
6 mySQL="select * from publishers "
7 myDSN="DSN=student;uid=student;pwd=magic"
8 public allstates
9 tempinput=request("states")
10 allstates=split(tempinput,",")
11
12 whereclause=" where state='" & JOIN(allstates, "' OR state='") & "'"
13
14 mySQL=mySQL & whereclause
15 response.write mySQL
16 Call Query2Table(mySQL,myDSN)
17 %>
18 </body></html>
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.
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.
1 <html><head>
2 <title>arraysredim.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 ' this code
6 dim a_array(100)
7
8 ' this code will fail
9 x=100
10 dim my_array(x)
11
12 %>
13 </body></html>
Assigning an array size with a variable produces an error unless the Redim command is used.
1 <html><head>
2 <title>arraysredimcorrect.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 dim my_array()
6 x=100
7 redim preserve my_array(x)
8 my_array(20)="Hi!"
9 my_array(40)="How are You"
10
11 lowcount=lbound(my_array)
12 highcount=ubound(my_array)
13 response.write "lowcount=" & lowcount & ";highcount=" & highcount & "<p>"
14 for counter=lowcount to highcount
15 response.write counter & " "
16 response.write my_array(counter) & "<br>"
17 next
18
19 %>
20 </body></html>
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 <html><head>
2 <title>arraysloadbest.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 dim my_months
6
7 my_months=array("Jan","Feb","Mar","Apr", _
8 "May","Jun","Jul","Aug", _
9 "Sep","Oct","Nov","Dec")
10
11 ' finally here is how you loop through an array
12 lowcount=lbound(my_months)
13 highcount=ubound(my_months)
14 response.write "lowcount=" & lowcount & ";highcount=" & highcount & "<p>"
15 for counter=lowcount to highcount
16 response.write my_months(counter) & "<br>"
17 next
18 %>
19 </body></html>
Arrays Resources
Arrays are handled in much more depth at other sites actually so rather than re-invent the wheel here is a list:
Sorting Arrays
http://4guysfromrolla.com/webtech/012799-2.shtmlSorting 2-D Arrays
http://www.4guysfromrolla.com/webtech/012799-3.shtmlPassing Arrays from Page to Page
http://www.4guysfromrolla.com/webtech/101999-1.shtmlRandomly Re-ordering an Array, for example one from Getrows
http://www.4guysfromrolla.com/webtech/110800-1.shtmlSorting Alogorithms in general @
http://www-lsi.upc.es/~rbaeza/handbook/sort_a.htmlTranslate arrays into javascript arrays @
http://aspfree.com/authors/anandv/vb2jsarray.aspHow can I quickly determine if a string exists within an array?
http://www.aspfaqs.com/aspfaqs/ShowFAQ.asp?FAQID=93Filtering Arrays
http://www.4guysfromrolla.com/webtech/111300-1.shtmlDynamic Arrays Made Easy
http://www.4guysfromrolla.com/webtech/032800-1.shtmlFAQs by Scott Mitchell, Bill Wilkinson, Richard Lowe, and Ben Kubs
http://www.aspfaqs.com/aspfaqs/ShowCategory.asp?CatID=1Remas Wojciechowski Array Notes @
http://www.aspalliance.com/remas/Library/Arrays/
Dictionary objects by Charles Carroll
Dictionary objects are an elegant
object to use in your coding. The dictionary items can be removed
individually (without leaving holes) unlike array elements. Read up on http://www.learnasp.com/advice/threadsafe.asp
if you want to use it at session or application level. The base documentation is
at:
http://www.learnasp.com/iishelp/VBScript/htm/vbs388.htm.
A clever moderately complex
practical dictionary example is @
http://www.4guysfromrolla.com/webtech/072899-1.shtml
This is how to create and place items into a dictionary objects and display the contents:
1 <html><head>
2 <title>dictionarybasics.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 set mysample=server.CreateObject("Scripting.Dictionary")
6
7 mysample.Add "haircolor", "brown"
8 mysample.add "eyecolor" , "blue"
9 mysample.add "dateofbirth", "5/13/64"
10
11 for each whatever in mysample
12 response.write whatever & "="
13 response.write mysample.item(whatever) & "<br>"
14 next
15 set mysample=nothing
16 %>
17 </body></html>
This is a sample of how to make an array of dictionary objects.
1 <html><head>
2 <title>dictionaryarrays.asp</title>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 dim people(3)
6
7 Set people(0) = server.CreateObject("Scripting.Dictionary")
8 people(0).Add "fname", "Jane"
9 people(0).Add "lname", "Doe"
10 people(0).Add "haircolor", "brown"
11 people(0).add "eyecolor" , "blue"
12 people(0).add "dateofbirth", "1/10/60"
13
14 Set people(1) = server.CreateObject("Scripting.Dictionary")
15 people(1).Add "fname", "Reginald"
16 people(1).Add "mname", "Elton"
17 people(1).Add "lname", "Dwight"
18 people(1).Add "haircolor", "red"
19 people(1).add "eyecolor" , "dusty"
20 people(1).add "dateofbirth", "1/10/60"
21
22 Set people(2) = server.CreateObject("Scripting.Dictionary")
23 people(2).Add "fname", "Hitoshi"
24 people(2).Add "lname", "Yoshitsugu"
25
26 ' print out one item
27 for each whatever in people(1)
28 response.write whatever & "="
29 response.write people(1).item(whatever) & "<br>"
30 next
31
32 for counter=0 to 2
33 set people(counter)=nothing
34 next
35 %>
36 </body></html>
Ultimate GetRows by Charles Carroll
Sure GetRows is fast and improves
scalability. I discussed why
http://www.learnasp.com/advice/whygetrows.asp
But it is a pain because it transfers the recordset into a multi-dimensional
array and the code to walk the array is complex and re-usability is low. Well
thanks to the magic of dictionaries we can produce clever templates that
interact with GetRows and never have to worry again.
"The Worlds Fastest Listbox"
http://www.learnasp.com/learn/speedappdata.asp
shows the only faster way to display databases.
Here is the sample that shows publisher data in a table:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 with rsparms
12 .Add "conn", "dsn=student;uid=student;pwd=magic"
13 .add "sql", "select * from publishers where state='NY'"
14 .add "debug", false
15 .add "template_header", "<table border=1>"
16 .add "template_row_header", "<tr>"
17 .add "template_row_footer", "</tr>"
18 .add "template_col_header", "<td>"
19 .add "template_col_footer", "</td>"
20 .add "template_footer", "</table>"
21 .add "fieldnull", " "
22 .add "fieldblank", " "
23 .add "fld_city", "<td bgcolor='lightblue'><b>{0}</b><br></td>"
24 .add "fld_state", "<td><b>{0}</b><br></td>"
25 .add "colnames", "display"
26 end with
27 Call RsFast(rsparms)
28 set rsparms=nothing
29 %>
30 </body>
31 </html>
Here is the sample that shows listboxes drawn from the publisher data:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 WITH rsparms
12
13 .Add "conn", "dsn=student;uid=student;pwd=magic"
14 .add "sql", "select distinct city from publishers"
15 .add "debug", false
16 .add "template_header", "<select name='city'>"
17 .add "template_row_header", "<option>"
18 .add "template_row_footer", "</option>"
19 .add "template_footer", "</select><br>"
20 .add "fieldnull", " "
21 .add "fieldblank", " "
22 Call RsFast(rsparms)
23 response.flush
24
25 .item("sql")="select distinct state from publishers"
26 .item("template_header")="<select name='state'>"
27 Call RsFast(rsparms)
28 response.flush
29
30 .item("sql")="select distinct zip from publishers"
31 .item("template_header")="<select name='zip'>"
32 Call RsFast(rsparms)
33 response.flush
34
35 END WITH
36 set rsparms=nothing
37 %>
38 </body>
39 </html>
Here is a sample that pages the publisher data:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 with rsparms
12 .Add "conn", "dsn=student;uid=student;pwd=magic"
13 .add "sql", "select * from publishers"
14 .add "page", 3
15 .add "pagesize", 4
16
17 .add "debug", false
18 .add "template_header", "Page {page} of {pagemax} <table border=1>"
19 .add "template_row_header", "<tr>"
20 .add "template_row_footer", "</tr>"
21 .add "template_col_header", "<td>"
22 .add "template_col_footer", "</td>"
23 .add "template_footer", "</table>"
24 .add "fieldnull", " "
25 .add "fieldblank", " "
26 .add "fld_city", "<td bgcolor='lightblue'><b>{0}</b><br></td>"
27 .add "fld_state", "<td><b>{0}</b><br></td>"
28 .add "colnames", "display"
29 end with
30 Call RsFast(rsparms)
31 set rsparms=nothing
32 %>
33 </body>
34 </html>
Here is the sample that shows the northwind customer data in a table:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 with rsparms
12 .add "accessdb", "nwind.mdb"
13 .add "sql", "select * from customers"
14 .add "debug", false
15 .add "template_header", "<table border=1>"
16 .add "template_row_header", "<tr>"
17 .add "template_row_footer", "</tr>"
18 .add "template_col_header", "<td>"
19 .add "template_col_footer", "</td>"
20 .add "template_footer", "</table>"
21 .add "fieldnull", " "
22 .add "fieldblank", " "
23 .add "fld_contactname", "<td bgcolor='lightblue'><b>{0}</b></td>"
24 .add "fld_city", "<td bgcolor='orange'><b>{0}</b></td>"
25 .add "colnames", "display"
26 end with
27 Call RsFast(rsparms)
28 set rsparms=nothing
29 %>
30 </body>
31 </html>
Here is the the library lib_rsfast.asp that does all the work:
1 <%
2 SUB RSfast(parmdict)
3 parmConn=parmdict.item("conn")
4 parmSQL=parmdict.item("sql")
5 parmdbg=parmdict.item("debug")
6 fieldnull=parmdict.item("fieldnull")
7 fieldblank=parmdict.item("fieldblank")
8 accdb=parmdict.item("accessdb")
9 page=cint(parmdict.item("page"))
10 pagesize=cint(parmdict.item("pagesize"))
11 If parmdict.item("colnames")="display" THEN
12 coldisplay=true
13 END IF
14
15 If accdb="" THEN
16 ' nothing to do
17 ELSE
18 parmConn="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE="
19 parmConn=parmConn & server.mappath(accdb) & ";"
20 END IF
21
22 If parmdbg=true THEN
23 response.write "parmconn=" & parmConn & "<br>"
24 response.write "parmSQL=" & parmSQL & "<br>"
25 END IF
26
27 response.flush
28
29 ' Open and check for EOF
30 set conntemp=server.createobject("adodb.connection")
31 conntemp.open parmConn
32 IF pagesize>0 THEN
33 set rstemp=Server.CreateObject("ADODB.Recordset")
34 aduseclient=3
35 rstemp.cursorlocation=aduseclient
36 rstemp.cachesize=pagesize
37 rstemp.open parmSQL,parmconn
38 rstemp.absolutepage=page
39 pagemax=cint(rstemp.pagecount)
40 parmdict.add "pagemax", pagemax
41 paged=true
42 ELSE
43 set rstemp=conntemp.execute(parmSQL)
44 END IF
45 If rstemp.eof then
46 response.write "No records matched<br>"
47 response.write mySQL & "<br>So cannot make table..."
48 rstemp.close
49 set rstemp=nothing
50 conntemp.close
51 set conntemp=nothing
52 response.end
53 end if
54 template_header=parmdict.item("template_header")
55 template_footer=parmdict.item("template_footer")
56 template_header=replace(template_header,"{page}",cstr(page))
57 template_footer=replace(template_footer,"{page}",cstr(page))
58 template_header=replace(template_header,"{pagemax}",cstr(pagemax))
59 template_footer=replace(template_footer,"{pagemax}",cstr(pagemax))
60
61 response.write template_header
62 If coldisplay THEN
63 response.write parmdict.item("template_row_header")
64 END IF
65 ' fill dictionary with field names/numbers
66 howmany=rstemp.fields.count
67 set rsinfo=server.CreateObject("Scripting.Dictionary")
68 for counter=0 to howmany-1
69 thename=rstemp(counter).name
70 If coldisplay THEN
71 response.write parmdict.item("template_col_header")
72 END IF
73 rsinfo.add lcase(thename), counter
74 If coldisplay THEN
75 response.write "<b>" & thename & "</b>"
76 response.write parmdict.item("template_col_footer")
77 END IF
78 next
79 If coldisplay THEN
80 response.write parmdict.item("template_row_footer")
81 END IF
82
83 ' Now lets grab all the records
84 If paged=true THEN
85 alldata=rstemp.getrows(pagesize)
86 ELSE
87 alldata=rstemp.getrows()
88 END IF
89 rstemp.close
90 set rstemp=nothing
91 conntemp.close
92 set conntemp=nothing
93 rowcount=ubound(alldata,2)
94 colcount=ubound(alldata,1)
95
96 If parmdbg=true THEN
97 response.write "rowcount=" & rowcount & "<br>"
98 response.write "colcount=" & colcount & "<br>"
99 response.flush
100 END IF
101
102 FOR therow=0 TO rowcount
103 response.write parmdict.item("template_row_header")
104 FOR EACH whatever IN rsinfo
105 fldname=whatever
106 fldnumb=rsinfo.item(fldname)
107 fldvalue=alldata(fldnumb,therow)
108 IF isnull(fldvalue) THEN
109 fldvalue=fieldnull
110 END IF
111 IF trim(fldvalue)="" THEN
112 fldvalue=fieldblank
113 END IF
114
115 fldtemplate=parmdict.item("fld_" & fldname)
116
117 If fldtemplate<>"" THEN
118 fldvalue=replace(fldtemplate,"{0}",fldvalue)
119 response.write fldvalue
120 ELSE
121 response.write parmdict.item("template_col_header")
122 response.write fldvalue
123 response.write parmdict.item("template_col_footer")
124 END IF
125 NEXT
126 response.write parmdict.item("template_row_footer")
127 NEXT
128 response.write template_footer
129 set rsinfo=nothing
130 END SUB
131 %>
132
Subroutines - Choosing/Validating Dates by Charles Carroll
Subroutines can be used to provide handy date entry list boxes.
1 <HEAD><TITLE>subdates.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <form action="subdatesrespond.asp">
4 Depart:
5 <%call showdateform("depart")%>
6 <br>
7 Arrive:
8 <%call showdateform("arrive")%>
9 <input type="submit" value="Ready To Travel">
10 </form>
11 <%
12 sub showdateform(mylistname)
13 call showmonth(mylistname)
14 call showday(mylistname)
15 call showyear(mylistname)
16 end sub
17 %>
18
19 <%sub showmonth(listname)%>
20 <select name="<%=listname%>month">
21 <%
22 dim monthname
23 monthname=array("Jan","feb","Mar","Apr", _
24 "May","Jun","Jul","Aug", _
25 "Sep","Oct","Nov","Dec")
26 for counter=0 to 11
27 temp=monthname(counter)
28 response.write "<option value='" & counter+1
29 response.write "'>" & temp & "</option>"
30 next%>
31 </select>
32 <%end sub%>
33
34 <%sub showday(listname)%>
35 <select name="<%=listname%>day">
36 <%for counter=1 to 31
37 response.write "<option>" & counter & "</option>"
38 next%>
39 </select>
40 <%end sub%>
41
42 <%sub showyear(listname)%>
43 <select name="<%=listname%>year">
44 <%for counter=1964 to 2005
45 response.write "<option>" & counter & "</option>"
46 next%>
47 </select>
48 <%end sub%>
49
50
51 </BODY></HTML>
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 <HEAD><TITLE>subdatesrespond.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 dday=request.querystring("departday")
5 dmonth=request.querystring("departmonth")
6 dyear=request.querystring("departyear")
7 departdate=dday & "/" & dmonth & "/" & dyear
8
9 aday=request.querystring("arriveday")
10 amonth=request.querystring("arrivemonth")
11 ayear=request.querystring("arriveyear")
12 arrivedate=aday & "/" & amonth & "/" & ayear
13
14 If isdate(departdate) then
15 response.write "Departure Date is Valid Date<br>"
16 else
17 response.write "Departure Date is INVALID<br>"
18 end if
19
20 If isdate(arrivedate) then
21 response.write "Arrival Date is Valid Date<br>"
22 else
23 response.write "Arrival Date is INVALID<br>"
24 end if
25 %>
26 </BODY></HTML>
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 <HEAD><TITLE>subdbtable.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select * from publishers"
6 call query2table(mySQL,myDSN)
7 %>
8 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
9 </BODY></HTML>
1 <HEAD><TITLE>subdbtable2.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select * from titles"
6 call query2table(mySQL,myDSN)
7 %>
8 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
9 </BODY></HTML>
1 <HEAD><TITLE>subdbtable3.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select * from authors"
6 call query2table(mySQL,myDSN)
7 %>
8 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
9 </BODY></HTML>
1 <HEAD><TITLE>subdbtable4.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL= "SELECT Publishers.Name, Titles.Title "
6 mySQL= mySQL & "FROM Publishers "
7 mySQL= mySQL & "INNER JOIN Titles ON Publishers.PubID = Titles.PubID "
8 mySQL= mySQL & "order by Name"
9
10 call query2table(mySQL,myDSN)
11 %>
12 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
13 </BODY></HTML>
1 <HEAD><TITLE>subdbtable5.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select * from title_author"
6 call query2table(mySQL, myDSN)
7 %>
8 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
9 </BODY></HTML>
1 <HEAD><TITLE>subdbtable6.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN="DSN=student;uid=student;pwd=magic"
5 mySQL="select name,type from sysobjects"
6 call query2table(mySQL,myDSN)
7 %>
8 <!--#include virtual="/learn/test/lib_dbtable.asp"-->
9 </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%>
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 <html><head>
2 <TITLE>subdblist.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <form>
5 <%
6 theDSN="DSN=student;uid=student;pwd=magic"
7 call query2list("select distinct city from publishers","cy",theDSN)
8 call query2list("select distinct state from publishers","st",theDSN)
9 call query2list("select distinct zip from publishers","zp",theDSN)
10 %>
11 </form>
12 <!--#include virtual="/learn/test/subdblist.inc"-->
13 </body></html>
The include file lib_dblist.asp looks like:
1 <%sub query2list(myquery,myname,myDSN)
2 dim conntemp, rstemp
3 set conntemp=server.createobject("adodb.connection")
4 conntemp.open myDSN
5 set rstemp=conntemp.execute(myquery)
6 %>
7 <Select name="<%=myname%>">
8 <%
9 do while not rstemp.eof
10 thisfield=trim(RStemp(0))
11 if isnull(thisfield) or thisfield="" then
12 ' ignore
13 else
14 response.write "<option>" & thisfield & "</option>"
15 end if
16 rstemp.movenext
17 loop
18 %>
19 </select>
20 <%rstemp.close
21 set rstemp=nothing
22 conntemp.close
23 set conntemp=nothing
24 end sub%>
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 <HEAD><TITLE>subreusabledataform.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <!--#include virtual="/learn/test/subflexible.asp"-->
4 <%
5 call query2entryform("select * from publishers where pubid=16")
6 %>
7 </BODY></HTML>
1 <HEAD><TITLE>subreusabledatalist.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <!--#include virtual="/learn/test/lib_subflexible.asp"-->
4 <%
5 call query2list("select distinct state from publishers","thestate")
6 call query2list("select distinct city from publishers","thecity")
7 call query2list("select distinct zip from publishers","thezip")
8 %>
9 </BODY></HTML>
10
1 <HEAD><TITLE>subreusabledatatable.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <!--#include virtual="/learn/test/subflexible.asp"-->
4 <%
5 call query2table("select * from publishers")
6 %>
7 </BODY></HTML>
1 <HEAD><TITLE>subreusableform.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <!--#include virtual="/learn/test/subflexible.asp"-->
4 <%
5 call query2form("select * from publishers")
6 %>
7 </BODY></HTML>
The library file lib_subflexible.asp looks like:
1 <%
2 dim htmlstart, htmlend
3 dim rowstart, rowend
4 dim fieldstart, fieldend
5 dim namestart, nameend
6 dim fieldnames
7 fieldnames=false
8
9 sub query2list(myquery,listname)
10 htmlstart="<select name='" & listname & "'>"
11 htmlend="</select>"
12 rowstart="<option>"
13 rowend="</option>"
14 fieldstart=""
15 fieldend=""
16 call query2html(myquery)
17 end sub
18
19 sub query2table(myquery)
20 htmlstart="<table border=1>"
21 htmlend="</table>"
22 rowstart="<tr>"
23 rowend="</tr>"
24 fieldstart="<td valign=top>"
25 fieldend="</td>"
26 call query2html(myquery)
27 end sub
28
29 sub query2form(myquery)
30 htmlstart=""
31 htmlend=""
32 rowstart=""
33 rowend="<hr>"
34 fieldstart=""
35 fieldend="<br>"
36 fieldnames=true
37 namestart=""
38 nameend=" = "
39 call query2html(myquery)
40 end sub
41
42 sub query2entryform(myquery)
43 htmlstart=""
44 htmlend=""
45 rowstart=""
46 rowend=""
47 fieldstart="%name% = <input type='text name='%name%' value='"
48 fieldend="' size='%size%'><br>"
49 fieldnames=false
50 namestart=""
51 nameend=" ="
52 call query2html(myquery)
53 end sub
54
55 sub query2html(inputquery)
56 set conntemp=server.createobject("adodb.connection")
57 conntemp.open "DSN=Student;uid=student;pwd=magic"
58 set rstemp=conntemp.execute(inputquery)
59 howmanyfields=rstemp.fields.count -1
60 redim fsa(howmanyfields)
61 redim fea(howmanyfields)
62 for i = 0 to howmanyfields
63 tempstart=replace(fieldstart,"%name%",rstemp(i).name)
64 tempend=replace(fieldend,"%name%",rstemp(i).name)
65 tempstart=replace(tempstart,"%size%",rstemp(i).actualsize)
66 tempend=replace(tempend,"%size%",rstemp(i).actualsize)
67 fsa(i)=tempstart
68 fea(i)=tempend
69 next
70 response.write htmlstart & vbcrlf
71 counter=0
72 do until rstemp.eof
73 response.write rowstart & vbcrlf
74 for i = 0 to howmanyfields
75 if fieldnames=true then
76 response.write namestart & rstemp(i).name & nameend
77 end if
78 response.write fsa(i) & rstemp(i) & fea(i) & vbcrlf
79 next
80 response.write rowend & vbcrlf
81 counter=counter+1
82 rstemp.movenext
83 if response.isclientconnected=false then
84 exit do
85 end if
86 loop
87 rstemp.close
88 set rstemp=nothing
89 conntemp.close
90 set conntemp=nothing
91 response.write htmlend
92 end sub
93 %>
Subroutines w/Dictionary Objects by Charles Carroll
Subroutines using traditional parameters cannot
support optional or variable parameters. Thanks to the wonders of dictionary
objects, see:
http://www.learnasp.com/learn/dictionary.asp
subroutines can accept merely one dictionary objects which can contain
simple variables, objects and other items to pass in.
1 <!--#include file="lib_mailtool.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>MailTool Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set mailparms=server.CreateObject("Scripting.Dictionary")
11 mailparms.Add "goodmailmsg", ""
12
13 mailparms.Add "who", "Sith Lord"
14 mailparms.Add "whoemail", "darthcarroll@asplists.com"
15
16 mailparms.Add "whofrom","Anakin Skywalker"
17 mailparms.Add "whofromemail", "jedi@senate.com"
18
19 mailparms.Add "subject", "need help?"
20
21 BodyOfMail="I am thinking about"
22 BodyOfMail=BodyOfMail & vbcrlf & "the dark side!!!"
23 BodyOfMail=BodyOfMail & vbcrlf & "Let me know if you need a hand!"
24
25 mailparms.Add "body", BodyOfMail
26
27 Call MailThat(mailparms)
28 set mailparms=nothing
29 %>
30 </body>
31 </html>
32
The Include file lib_mailtool.asp looks like this:
1 <%
2 SUB MailThat(Dictparm)
3 goodmailmsg=Dictparm.item("goodmailmsg")
4 who=Dictparm.item("who")
5 whoemail=Dictparm.item("whoemail")
6
7 whofrom=Dictparm.item("whofrom")
8 whofromemail=Dictparm.item("whofromemail")
9
10 whobcc=Dictparm.item("whobcc")
11 whobccemail=Dictparm.item("whobccemail")
12
13 subject=Dictparm.item("subject")
14 mailbody=Dictparm.item("body")
15
16
17 IF instr(whoemail,"@") >0 THEN
18 goodemail=true
19 ELSE
20 goodemail=false
21 reason="bad target mail:" & whoemail & " "
22 tempSUBJ="bad signup"
23 END IF
24
25 Set Mailer = Server.CreateObject("SMTPsvg.Mailer")
26 Mailer.RemoteHost = "mail.innerhost.com"
27 Mailer.FromName = whofrom
28 Mailer.FromAddress = whofromemail
29 Mailer.AddRecipient who, whoemail
30 Mailer.AddBCC whobcc,whobccemail
31 mailer.subject = subject
32 Mailer.BodyText = mailbody
33 If goodemail=false THEN
34 response.write "<p align='left'><font face='Comic Sans MS' color='#8000FF'>"
35 response.write "<big>Errors in processing request!<br>"
36 response.write "Your email address was invalid<br>"
37 response.write "<a href='/search'>Search Is Here</a> If You Wanted That!<br>"
38 response.write "OR Enter Correct Email address in previous form</big></font></p>"
39 END IF
40
41 IF Mailer.SendMail and goodemail=TRUE THEN
42 If goodmailmsg="" THEN
43 response.write "mail sent to " & who & "(" & whoemail & ")"
44 ELSE
45 response.write goodmailmsg
46 END IF
47 ELSE
48 IF goodemail=TRUE THEN
49 badmailsend=TRUE
50 END IF
51 END IF
52
53
54 IF badmailsend=TRUE THEN
55 response.write "Error Sending Mail!<br>"
56 response.write mailer.response & reason
57 response.write "<br>Sorry! Try Later...<br>"
58 END IF
59 End Sub
60 %>
Ultimate GetRows by Charles Carroll
Sure GetRows is fast and improves
scalability. I discussed why
http://www.learnasp.com/advice/whygetrows.asp
But it is a pain because it transfers the recordset into a multi-dimensional
array and the code to walk the array is complex and re-usability is low. Well
thanks to the magic of dictionaries we can produce clever templates that
interact with GetRows and never have to worry again.
"The Worlds Fastest Listbox"
http://www.learnasp.com/learn/speedappdata.asp
shows the only faster way to display databases.
Here is the sample that shows publisher data in a table:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 with rsparms
12 .Add "conn", "dsn=student;uid=student;pwd=magic"
13 .add "sql", "select * from publishers where state='NY'"
14 .add "debug", false
15 .add "template_header", "<table border=1>"
16 .add "template_row_header", "<tr>"
17 .add "template_row_footer", "</tr>"
18 .add "template_col_header", "<td>"
19 .add "template_col_footer", "</td>"
20 .add "template_footer", "</table>"
21 .add "fieldnull", " "
22 .add "fieldblank", " "
23 .add "fld_city", "<td bgcolor='lightblue'><b>{0}</b><br></td>"
24 .add "fld_state", "<td><b>{0}</b><br></td>"
25 .add "colnames", "display"
26 end with
27 Call RsFast(rsparms)
28 set rsparms=nothing
29 %>
30 </body>
31 </html>
Here is the sample that shows listboxes drawn from the publisher data:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 WITH rsparms
12
13 .Add "conn", "dsn=student;uid=student;pwd=magic"
14 .add "sql", "select distinct city from publishers"
15 .add "debug", false
16 .add "template_header", "<select name='city'>"
17 .add "template_row_header", "<option>"
18 .add "template_row_footer", "</option>"
19 .add "template_footer", "</select><br>"
20 .add "fieldnull", " "
21 .add "fieldblank", " "
22 Call RsFast(rsparms)
23 response.flush
24
25 .item("sql")="select distinct state from publishers"
26 .item("template_header")="<select name='state'>"
27 Call RsFast(rsparms)
28 response.flush
29
30 .item("sql")="select distinct zip from publishers"
31 .item("template_header")="<select name='zip'>"
32 Call RsFast(rsparms)
33 response.flush
34
35 END WITH
36 set rsparms=nothing
37 %>
38 </body>
39 </html>
Here is a sample that pages the publisher data:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 with rsparms
12 .Add "conn", "dsn=student;uid=student;pwd=magic"
13 .add "sql", "select * from publishers"
14 .add "page", 3
15 .add "pagesize", 4
16
17 .add "debug", false
18 .add "template_header", "Page {page} of {pagemax} <table border=1>"
19 .add "template_row_header", "<tr>"
20 .add "template_row_footer", "</tr>"
21 .add "template_col_header", "<td>"
22 .add "template_col_footer", "</td>"
23 .add "template_footer", "</table>"
24 .add "fieldnull", " "
25 .add "fieldblank", " "
26 .add "fld_city", "<td bgcolor='lightblue'><b>{0}</b><br></td>"
27 .add "fld_state", "<td><b>{0}</b><br></td>"
28 .add "colnames", "display"
29 end with
30 Call RsFast(rsparms)
31 set rsparms=nothing
32 %>
33 </body>
34 </html>
Here is the sample that shows the northwind customer data in a table:
1 <!--#include file="lib_rsfast.asp"-->
2 <%response.buffer=true%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <title>RsFast Demo</title>
7 </head>
8 <body bgcolor="#FFFFFF">
9 <%
10 set rsparms=server.CreateObject("Scripting.Dictionary")
11 with rsparms
12 .add "accessdb", "nwind.mdb"
13 .add "sql", "select * from customers"
14 .add "debug", false
15 .add "template_header", "<table border=1>"
16 .add "template_row_header", "<tr>"
17 .add "template_row_footer", "</tr>"
18 .add "template_col_header", "<td>"
19 .add "template_col_footer", "</td>"
20 .add "template_footer", "</table>"
21 .add "fieldnull", " "
22 .add "fieldblank", " "
23 .add "fld_contactname", "<td bgcolor='lightblue'><b>{0}</b></td>"
24 .add "fld_city", "<td bgcolor='orange'><b>{0}</b></td>"
25 .add "colnames", "display"
26 end with
27 Call RsFast(rsparms)
28 set rsparms=nothing
29 %>
30 </body>
31 </html>
Here is the the library lib_rsfast.asp that does all the work:
1 <%
2 SUB RSfast(parmdict)
3 parmConn=parmdict.item("conn")
4 parmSQL=parmdict.item("sql")
5 parmdbg=parmdict.item("debug")
6 fieldnull=parmdict.item("fieldnull")
7 fieldblank=parmdict.item("fieldblank")
8 accdb=parmdict.item("accessdb")
9 page=cint(parmdict.item("page"))
10 pagesize=cint(parmdict.item("pagesize"))
11 If parmdict.item("colnames")="display" THEN
12 coldisplay=true
13 END IF
14
15 If accdb="" THEN
16 ' nothing to do
17 ELSE
18 parmConn="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE="
19 parmConn=parmConn & server.mappath(accdb) & ";"
20 END IF
21
22 If parmdbg=true THEN
23 response.write "parmconn=" & parmConn & "<br>"
24 response.write "parmSQL=" & parmSQL & "<br>"
25 END IF
26
27 response.flush
28
29 ' Open and check for EOF
30 set conntemp=server.createobject("adodb.connection")
31 conntemp.open parmConn
32 IF pagesize>0 THEN
33 set rstemp=Server.CreateObject("ADODB.Recordset")
34 aduseclient=3
35 rstemp.cursorlocation=aduseclient
36 rstemp.cachesize=pagesize
37 rstemp.open parmSQL,parmconn
38 rstemp.absolutepage=page
39 pagemax=cint(rstemp.pagecount)
40 parmdict.add "pagemax", pagemax
41 paged=true
42 ELSE
43 set rstemp=conntemp.execute(parmSQL)
44 END IF
45 If rstemp.eof then
46 response.write "No records matched<br>"
47 response.write mySQL & "<br>So cannot make table..."
48 rstemp.close
49 set rstemp=nothing
50 conntemp.close
51 set conntemp=nothing
52 response.end
53 end if
54 template_header=parmdict.item("template_header")
55 template_footer=parmdict.item("template_footer")
56 template_header=replace(template_header,"{page}",cstr(page))
57 template_footer=replace(template_footer,"{page}",cstr(page))
58 template_header=replace(template_header,"{pagemax}",cstr(pagemax))
59 template_footer=replace(template_footer,"{pagemax}",cstr(pagemax))
60
61 response.write template_header
62 If coldisplay THEN
63 response.write parmdict.item("template_row_header")
64 END IF
65 ' fill dictionary with field names/numbers
66 howmany=rstemp.fields.count
67 set rsinfo=server.CreateObject("Scripting.Dictionary")
68 for counter=0 to howmany-1
69 thename=rstemp(counter).name
70 If coldisplay THEN
71 response.write parmdict.item("template_col_header")
72 END IF
73 rsinfo.add lcase(thename), counter
74 If coldisplay THEN
75 response.write "<b>" & thename & "</b>"
76 response.write parmdict.item("template_col_footer")
77 END IF
78 next
79 If coldisplay THEN
80 response.write parmdict.item("template_row_footer")
81 END IF
82
83 ' Now lets grab all the records
84 If paged=true THEN
85 alldata=rstemp.getrows(pagesize)
86 ELSE
87 alldata=rstemp.getrows()
88 END IF
89 rstemp.close
90 set rstemp=nothing
91 conntemp.close
92 set conntemp=nothing
93 rowcount=ubound(alldata,2)
94 colcount=ubound(alldata,1)
95
96 If parmdbg=true THEN
97 response.write "rowcount=" & rowcount & "<br>"
98 response.write "colcount=" & colcount & "<br>"
99 response.flush
100 END IF
101
102 FOR therow=0 TO rowcount
103 response.write parmdict.item("template_row_header")
104 FOR EACH whatever IN rsinfo
105 fldname=whatever
106 fldnumb=rsinfo.item(fldname)
107 fldvalue=alldata(fldnumb,therow)
108 IF isnull(fldvalue) THEN
109 fldvalue=fieldnull
110 END IF
111 IF trim(fldvalue)="" THEN
112 fldvalue=fieldblank
113 END IF
114
115 fldtemplate=parmdict.item("fld_" & fldname)
116
117 If fldtemplate<>"" THEN
118 fldvalue=replace(fldtemplate,"{0}",fldvalue)
119 response.write fldvalue
120 ELSE
121 response.write parmdict.item("template_col_header")
122 response.write fldvalue
123 response.write parmdict.item("template_col_footer")
124 END IF
125 NEXT
126 response.write parmdict.item("template_row_footer")
127 NEXT
128 response.write template_footer
129 set rsinfo=nothing
130 END SUB
131 %>
132
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 sub db2list(mydelim,myparm)
3
4 dim myparameters
5 myparameters=SPLIT(myparm,mydelim)
6 parmcount=ubound(myparameters)
7 myquery=myparameters(0)
8 label=myparameters(1)
9 default=myparameters(2)
10 if parmcount>2 then
11 format=lcase(myparameters(3))
12 end if
13 if parmcount>3 then
14 connstring=myparameters(4)
15 else
16 connstring="DSN=Student;uid=student;pwd=magic"
17 end if
18
19 set conntemp=server.createobject("adodb.connection")
20 conntemp.open connstring
21 set rstemp=conntemp.execute(myquery)
22 If format="table" then%>
23 <table width="100%" border="0" cellspacing="1"><td>
24 <%end if
25 response.write label
26 If format="table" then%>
27 </td><td>
28 <%end if%>
29 <Select>
30 <option value="<%=default%>" selected><%=default%></option>
31 <%
32 do while not rstemp.eof %>
33 <option><%=RStemp(0)%></option>
34 <%
35 rstemp.movenext
36 loop
37 conntemp.close
38 %>
39 </select>
40 <%If format="table" then%>
41 </td><tr></table>
42 <%end if
43 end sub%>
44
Library of HTML Commands by Phil
Paxton
©1999,2000 by Phil Paxton
Subroutines and Functions can be used, for example, to provide a layer of abstraction over HTML.
1 <!--#include virtual="/learn/test/lib_htmlstuff.asp"-->
2 <html><head>
3 <title>libhtmldemo.asp by Phil Paxton</title>&
4 <body>
5 <form action="lib_htmldemorespond.asp">
6 <%
7 Call Form_TextBox("first name","Fname",20,20,"")
8 response.write "<br>"
9 Call Form_TextBox("Last Name","Lname",20,20,"")
10 response.write "<br>"
11 Call Form_TextBox("City","cy",20,20,"")
12 response.write "<br>"
13 Call Form_TextBox("State","st",2,2,"")
14 response.write "<br>"
15 Call Form_TextBox("Zip Code","zp",10,10,"")
16 response.write "<br>"
17 Call Form_SubmitButton("Register Me","register")
18 %>
19 </form>
20 </body>
21 </html>
The library that enables this (named lib_htmlstuff.asp) looks like:
1 <%
2 Sub Display( Text )
3 Response.Write( Text )
4 End Sub
5
6 '----------------------------------------------------------------
7
8 Sub HTML( Text )
9 Response.Write( Text )
10 End Sub
11
12 '----------------------------------------------------------------
13
14 Sub Test( Text )
15 Response.Write( Text )
16 End Sub
17
18 '----------------------------------------------------------------
19
20 Sub Form_HiddenField( Name, Value )
21
22 HTML "<INPUT "
23 Form_Parm_Type "Hidden"
24 Form_Parm_Name Name
25 Form_Parm_Value Value
26 HTML ">"
27
28 End Sub
29
30 '----------------------------------------------------------------
31
32 Sub Form_Label( Label, Control )
33
34 If Len(Label) > 0 Then
35 HTML "<label "
36 HTML "for=" & Control
37 HTML ">"
38 HTML "<strong>"
39 Display Label
40 HTML "</strong>"
41 HTML "</label>"
42 End If
43
44 End Sub
45
46 '----------------------------------------------------------------
47
48 Sub Form_TextBox( Label, Name, MaxLength, Size, Value )
49
50 Form_Label Label, Name
51
52 HTML "<input "
53 Form_Parm_Type "text"
54 Form_Parm_Name Name
55 Form_Parm_Size Size
56 Form_Parm_ID Name
57 Form_Parm_MaxLength MaxLength
58 Form_Parm_Value Value
59 HTML ">"
60
61 End Sub
62
63 '----------------------------------------------------------------
64
65 Sub Form_Password( Label, Name, MaxLength, Size, Value )
66
67 Form_Label Label, Name
68
69 HTML "<input "
70 Form_Parm_Type "password"
71 Form_Parm_Name Name
72 Form_Parm_Size Size
73 Form_Parm_ID Name
74 Form_Parm_MaxLength MaxLength
75 Form_Parm_Value Value
76 HTML ">"
77
78 End Sub
79
80 '----------------------------------------------------------------
81
82 Sub Form_ScrollingText( Label, Name, Rows, Cols, Value )
83
84 Form_Label Label, Name
85
86 HTML "<textarea "
87 Form_Parm_Name Name
88 If Len(Rows) > 0 Then
89 HTML "rows=" & Rows & " "
90 End If
91 If Len(Cols) > 0 Then
92 HTML "cols=" & Cols & " "
93 End If
94 Form_Parm_ID Name
95 HTML ">"
96
97 If Len(Value) > 0 Then
98 Display Value
99 End If
100
101 HTML "</textarea>"
102
103 End Sub
104
105 '----------------------------------------------------------------
106
107 Sub Form_ResetButton( Name, Value )
108
109 HTML "<input "
110 Form_Parm_Type "reset"
111 Form_Parm_Value Value
112 Form_Parm_Name Name
113 HTML ">"
114
115 End Sub
116
117 '----------------------------------------------------------------
118
119 Sub Form_CommandButton( Name, Value )
120
121 HTML "<input "
122 Form_Parm_Type "button"
123 Form_Parm_Value Value
124 Form_Parm_Name Name
125 HTML ">"
126
127 End Sub
128
129 '----------------------------------------------------------------
130
131 Sub Form_SubmitButton( Name, Value )
132 HTML "<input "
133 Form_Parm_Type "submit"
134 Form_Parm_Value Value
135 Form_Parm_Name Name
136 HTML ">"
137 End Sub
138
139 '----------------------------------------------------------------
140
141 Sub Form_RadioButton( Label, Name, Value, Checked )
142
143 HTML "<input "
144 Form_Parm_Type "radio"
145 Form_Parm_Value Value
146 Form_Parm_Name Name
147 Form_Parm_ID Name & Value
148 If Len(Checked) > 0 Then
149 If Checked Then
150 HTML " checked "
151 End If
152 End If
153 HTML ">"
154
155 Form_Label Label, Name & Value
156
157 End Sub
158
159 '----------------------------------------------------------------
160
161 Sub Form_Checkbox( Label, Name, Value, Checked )
162
163 Form_Label Label, Name
164
165 HTML "<INPUT "
166 Form_Parm_Type "checkbox"
167 Form_Parm_Name Name
168 Form_Parm_Value Value
169 If Len( Checked ) > 0 Then
170 If Checked = True Then
171 HTML " checked "
172 End If
173 End If
174 HTML ">"
175 '
176 End Sub
177
178 '----------------------------------------------------------------
179
180 Sub Form_Begin( Action )
181
182 HTML "<form "
183 HTML "method=post "
184 HTML "action =" & Chr(39) & Action & Chr(39) & " "
185 HTML ">"
186
187 End Sub
188
189 '----------------------------------------------------------------
190
191 Sub Form_End( Name, Value )
192
193 Form_HiddenField Name, Value
194 HTML "</FORM>"
195
196 End Sub
197
198 '----------------------------------------------------------------
199
200 Sub Form_Table_Begin( Border, Width )
201 HTML "<table "
202 If Len(Border) > 0 Then
203 HTML "border=" & Chr(39) & Border & Chr(39) & " "
204 End If
205 Form_Parm_Width Width
206 HTML ">"
207 End Sub
208
209 '----------------------------------------------------------------
210
211 Sub Form_Table_End()
212 HTML "</table>"
213 End Sub
214
215 '----------------------------------------------------------------
216
217 Sub Form_Table_Row_Begin( Dummy, Align, VAlign )
218 HTML "<tr "
219 Form_Parm_Align Align
220 Form_Parm_VAlign VAlign
221 HTML ">"
222 End Sub
223
224 '----------------------------------------------------------------
225
226 Sub Form_Table_Row_End( Dummy )
227 HTML "</tr>"
228 End Sub
229
230 '----------------------------------------------------------------
231
232 Sub Form_Table_Cell_Begin( Dummy, Width, Align, VAlign )
233 HTML "<td "
234 Form_Parm_Width Width
235 Form_Parm_Align Align
236 Form_Parm_VAlign VAlign
237 HTML ">"
238 End Sub
239
240 '----------------------------------------------------------------
241
242
243 Sub Form_Table_Cell_End( Dummy )
244 HTML "</td>"
245 End Sub
246
247
248 '----------------------------------------------------------------
249
250
251 Sub Form_ComboBox_Begin( Label, Name, Size, Multiple )
252 Form_Label Label, Name
253 HTML "<select "
254 Form_Parm_Name Name
255 Form_Parm_Size Size
256 If Len(Multiple) > 0 Then
257 If Multiple Then
258 HTML " multiple "
259 End If
260 End If
261 HTML ">"
262 End Sub
263
264 '----------------------------------------------------------------
265
266 Sub Form_ComboBox_Item( Value, Selected )
267 HTML "<option "
268 Form_Parm_Value Value
269 If Len(Selected) > 0 Then
270 If Selected Then
271 HTML " selected "
272 End If
273 End If
274 HTML ">"
275 End Sub
276
277 '----------------------------------------------------------------
278
279 Sub Form_ComboBox_End()
280 HTML "</select>"
281 End Sub
282
283 '----------------------------------------------------------------
284
285 Sub Form_Title( Title )
286 HTML "<title>"
287 Display Title
288 HTML "</title>&
289 End Sub
290
291
292 '----------------------------------------------------------------
293
294 Sub Form_Center( Text )
295 HTML "<p align=" & Chr(39) & "center" & Chr(39) & ">"
296 Display Text
297 HTML "</p>"
298 End Sub
299
300 '----------------------------------------------------------------
301
302 Sub Form_Left( Text )
303 HTML "<p align=" & Chr(39) & "left" & Chr(39) & ">"
304 Display Text
305 HTML "</p>"
306 End Sub
307
308 '----------------------------------------------------------------
309
310 Sub Form_Right( Text )
311 HTML "<p align=" & Chr(39) & "right" & Chr(39) & ">"
312 Display Text
313 HTML "</p>"
314 End Sub
315
316 '----------------------------------------------------------------
317
318 Sub Form_Parm_Align( Align )
319 If Len(Align) > 0 Then
320 Select Case UCase(Align)
321 Case "L", "LEFT"
322 Display " align=" & Chr(39) & "left" & Chr(39) & " "
323 Case "C", "CENTER"
324 Display " align=" & Chr(39) & "center" & Chr(39) & " "
325 Case "R", "RIGHT"
326 Display " align=" & Chr(39) & "right" & Chr(39) & " "
327 Case Else
328 End Select
329 End If
330 End Sub
331
332 '----------------------------------------------------------------
333
334 Sub Form_Parm_VAlign( VAlign )
335 If Len(VAlign) > 0 Then
336 Select Case UCase(VAlign)
337 Case "T", "TOP"
338 Display " align=" & Chr(39) & "top" & Chr(39) & " "
339 Case "C", "CENTER"
340 Display " align=" & Chr(39) & "center" & Chr(39) & " "
341 Case "B", "BOTTOM"
342 Display " align=" & Chr(39) & "bottom" & Chr(39) & " "
343 Case Else
344 End Select
345 End If
346 End Sub
347
348 '----------------------------------------------------------------
349
350 Sub Form_Parm_Name( Name )
351 If Len(Name) > 0 Then
352 Display " name=" & Chr(39) & Name & Chr(39) & " "
353 End If
354 End Sub
355
356 '----------------------------------------------------------------
357
358 Sub Form_Parm_Value( Value )
359 If Len(Value) > 0 Then
360 Display " value=" & Chr(39) & Value & Chr(39) & " "
361 End If
362 End Sub
363
364 '----------------------------------------------------------------
365
366 Sub Form_Parm_Type( TypeValue )
367 If Len(TypeValue) > 0 Then
368 Display " type=" & Chr(39) & TypeValue & Chr(39) & " "
369 End If
370 End Sub
371
372 '----------------------------------------------------------------
373
374 Sub Form_Parm_Size( Size )
375 If Len(Size) > 0 Then
376 Display " size=" & Size & " "
377 End If
378 End Sub
379
380 '----------------------------------------------------------------
381
382 Sub Form_Parm_ID( ID )
383 If Len(ID) > 0 Then
384 Display " id=" & Chr(39) & ID & Chr(39) & " "
385 End If
386 End Sub
387
388 '----------------------------------------------------------------
389
390 Sub Form_Parm_MaxLength( MaxLength )
391 If Len(MaxLength) > 0 Then
392 Display " maxlength=" & MaxLength
393 End If
394 End Sub
395
396 '----------------------------------------------------------------
397
398 Sub Form_Parm_Length( Length )
399 If Len(Length) > 0 Then
400 Display " length=" & Length
401 End If
402 End Sub
403
404 '----------------------------------------------------------------
405
406 Sub Form_Parm_Width( Width )
407 If Len(Width) > 0 Then
408 Display " width=" & Width
409 End If
410 End Sub
411
412 '----------------------------------------------------------------
413
414 Sub Anchor_Display( TextToDisplay, HRef )
415 HTML "<a href=" & Chr(39) & HRef & Chr(39) & ">"
416 Display TextToDisplay
417 HTML "</a>"
418 End Sub
419
420 '----------------------------------------------------------------
421
422 Sub MenuItem ( TextToDisplay, HRef )
423 HTML "<ul>"
424 HTML "<li>"
425 HTML "<p "
426 Form_Parm_Align "Left"
427 Form_Parm_VAlign "Bottom"
428 HTML ">"
429 Anchor_Display TextToDisplay, HRef
430 HTML "</p>"
431 HTML "</li>"
432 HTML "</ul>"
433 End Sub
434
435 '----------------------------------------------------------------
436
437 Function FormatMoney( Amount )
438 '
439 ' Standard constants from the MS web site but not built
440 ' into VBScript's default constants.
441 '
442 Const TristateTrue = -1
443 Const TristateFalse = 0
444 Const TristateUseDefault = -2
445 '
446 If IsNull( Amount ) Then
447 FormatMoney = vbNullString
448 Else
449 FormatMoney = FormatCurrency( Amount, 2, TristateTrue _
450 , False, TristateTrue)
451 End If
452 '
453 End Function
454
455 '----------------------------------------------------------------
456 %>
Functions -- The WorkingDays function
This page demonstrates how to make a function and display it's results in your page.
1 <title>functionworkingdays.asp</title>
2 <body bgcolor="#FFFFFF">
3 <%
4 response.write "3 working days from today is " & dtaddWorkingDays(now(),3) & "<p>"
5 %>
6 2 working days from today is <%=dtaddWorkingDays(now(),2)%>
7 </body>
8 <%Function dtAddWorkingDays(dtStartDate, nDaystoAdd)
9 'Adds working days based on a five day week
10
11 Dim dtEndDate
12 Dim iLoop
13
14 'First add whole weeks
15 dtEndDate=DateAdd("ww",Int(nDaysToAdd/5),dtStartDate)
16
17 'Add any odd days
18 For iLoop = 1 To (nDaysToAdd Mod 5)
19 dtEndDate=DateAdd("d",1,dtEndDate)
20 'If Saturday increment to following Monday
21 If WeekDay(dtEndDate)=vbSaturday Then
22 'Increment date to following Monday
23 dtEndDate=DateAdd("d",2,dtEndDate)
24 End If
25 Next
26 dtAddWorkingDays=dtEndDate
27 End Function
28 %>
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 <html><head>
2 <title>vbs5eval.asp</title>
3 </head>
4 <body>
5 <%
6 x="2+2*3"
7 response.write eval(x)
8 %>
9 </body>
10 </html>
Classes:
1 <html><head>
2 <title>vb5classes.asp</title>
3 </head>
4 <body>
5 <%
6 ' Create a myCustomer variable
7 Dim myCustomer
8 ' Create a new instance of the Customer Class
9 ' and set the value of myCustomer to be that instance
10 set myCustomer = new Customer
11 ' Add a new customer
12 myCustomer.Add "Charles","Carroll"
13 ' Set their Email address
14 myCustomer.EmailName = "charlescarroll@aspalliance.com"
15 ' Set their credit limit
16 myCustomer.CreditLimit = 5000
17 ' Display the customers fullname
18 response.write myCustomer.FullName
19
20 Class Customer
21 Public FirstName, LastName
22 Private nCreditLimit
23 Private strEmailName
24 Property Get EmailName
25 EmailName = strEmailName
26 End Property
27 Property Let EmailName ( strName)
28 StrEmailName = strName
29 End Property
30 Property Get FullName
31 FullName= FirstName & " " & LastName
32 End Property
33 Property Let CreditLimit ( s )
34 if s >= 0 then
35 nSalary = s
36 End If
37 End Property
38 Property Get CreditLimit
39 Salary = nSalary
40 End Property
41 Sub Add( First, Last )
42 FirstName = First
43 LastName = Last
44 End Sub
45 Function RaiseCreditLimit( Amount )
46 nCreditLimit = nCreditLimit + Amount
47 RaiseSalary = nSalary
48 End Function
49 End Class
50 %>
51 </body>
52 </html>
Execute Function:
1 <html><head>
2 <title>vbs5execute.asp</title>
3 </head>
4 <body>
5 <%
6 S = "Sub Hi" & vbCrLf
7 S = S & " Response.write ""Hi""" & vbCrLf
8 S = S & "End Sub"
9 Execute S
10 Call Hi()
11 %>
12 </body>
13 </html>
Regular Expressions
1 <html><head>
2 <title>vbs5reg.asp</title>&
3 <body>
4 <%
5
6 address="joe@aol.com"
7 validmail=checkemail(address)
8 IF validmail THEN
9 response.write address & " is good!"
10 ELSE
11 response.write address & " is bad!"
12 END IF
13
14 address="sallyaol.com"
15 validmail=checkemail(address)
16 IF validmail THEN
17 response.write address & " is good!"
18 ELSE
19 response.write address & " is bad!"
20 END IF
21
22
23 FUNCTION CheckEmail(parmaddress)
24 set myRegExp = new RegExp
25 ' Set the pattern to check for a word followed by
26 ' an @ followed by a word
27 myRegExp.pattern = "\w+\@[.\w]+"
28 if myRegExp.Test(parmaddress) then
29 CheckEmail=True
30 else
31 CheckEmail=false
32 end if
33 END FUNCTION
34 %>
35 </body>
36 </html>
With
1 <html><head>
2 <title>vbs5with.asp</title>
3 </head>
4 <body>
5 <%
6 with response
7 .write "Hi<br>"
8 .write "how are you doing?<br>"
9 .write "see you around"
10 end with
11 %>
12 </body>
13 </html>
Text File Reading
1 <html><head>
2 <TITLE>txtread.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 whichfile=server.mappath("/aspheader.asp")
6
7 Set fs = CreateObject("Scripting.FileSystemObject")
8 Set thisfile = fs.OpenTextFile(whichfile, 1, False)
9
10 counter=0
11 do while not thisfile.AtEndOfStream
12 counter=counter+1
13 thisline=thisfile.readline
14 response.write thisline & "<br>"
15 loop
16
17 thisfile.Close
18 set thisfile=nothing
19 set fs=nothing
20 %>
21 </body></html>
Text File Writing by Charles Carroll
The following code snippets adds several lines to an ASCII file.
1 <html><head>
2 <TITLE>txtwrite.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 whichFN=server.mappath("/upload/tests/tempfile.txt")
6
7 ' first, create the file out of thin air
8 Set fstemp = server.CreateObject("Scripting.FileSystemObject")
9 Set filetemp = fstemp.CreateTextFile(whichFN, true)
10 ' true = file can be over-written if it exists
11 ' false = file CANNOT be over-written if it exists
12
13 filetemp.WriteLine("This is a brand new file!!!!")
14 filetemp.writeblanklines(3)
15 filetemp.WriteLine("This is the last line of the file we created!")
16 filetemp.Close
17
18 ' Now open it and add some lines
19 forappending =8
20 set filetemp=fstemp.OpentextFile(whichFN, forappending)
21 filetemp.writeline "a line we added later"
22 filetemp.writeline "another line we added later..."
23 filetemp.close
24
25 set filetemp=nothing
26 set fstemp=nothing
27
28 If err.number=0 then
29 response.write "File was appended sucessfully!"
30 else
31 response.write "VBScript Errors Occured!<br>"
32 response.write "Error Number=#<b>" & err.number & "</b><br>"
33 response.write "Error Desc. =<b>" & err.description & "</b><br>"
34 response.write "Help Path =<b>" & err.helppath & "</b><br>"
35 response.write "Native Error=<b>" & err.nativeerror & "</b><br>"
36 response.write "Error Source =<b>" & err.source & "</b><br>"
37 response.write "SQL State=#<b>" & err.sqlstate & "</b><br>"
38 end if
39
40
41 %>
42 </body></html>
This code displays the file we created:
1 <html><head>
2 <TITLE>txtwritedisplay.asp</TITLE>
3 </head><body bgcolor="#FFFFFF">
4 <%
5 whichname="tempfile.txt"
6 whichdir=Server.Mappath ("/upload/tests/")
7 whichFN=whichdir & whichname
8 forreading=1
9
10 Set fs = CreateObject("Scripting.FileSystemObject")
11 Set thisfile = fs.OpenTextFile(whichFN, forreading, False)
12 counter=0
13 do while not thisfile.AtEndOfStream
14 counter=counter+1
15 thisline=thisfile.readline
16 response.write thisline & "<br>"
17 loop
18 thisfile.Close
19
20 set thisfile=nothing
21 set fs=nothing
22
23 %>
24 </body></html>
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 At a party do you - interact with many, including strangers / interact with a few, known to you
2 SN Are you more - realistic than speculative / speculative than realistic
3 SN It is worse to - have your "head in the clouds" / be "in a rut"
4 TF Are you more impressed by - principles / emotions
5 TF Are you more drawn toward the - convincing / touching
6 JP Do you prefer to work - to deadlines / just "whatever"
7 JP Do you tend to choose - rather carefully / somewhat impulsively
8 EI At parties do you - stay late, with increasing energy / leave early, with decreased energy
9 SN 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 TF Which do you wish more for yourself - clarity of reason / strength of compassion
67 TF Which is the greater fault - being indiscriminate / being critical
68 EI Do you prefer the - planned event / unplanned event
69 JP Do you tend to be more - deliberate than spontaneous / spontaneous than deliberate
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 <%option explicit%>
2 <html>
3
4 <head>
5 <title>mb.asp</title>
6 </head>
7
8 <body bgcolor="#FFFFFF">
9
10 <form method="post" action="mbrespond.asp">
11 <%
12 dim answer1, answer2
13 dim char1, char2, counter
14 Dim fs, findslash, findhyphen
15 dim rest
16 Dim thisfile, thisline
17 dim question
18 dim whichfile
19 whichfile=server.mappath("mb.txt")
20 Set fs = CreateObject("Scripting.FileSystemObject")
21 Set thisfile = fs.OpenTextFile(whichfile, 1, False)
22 counter=0
23 do while not thisfile.AtEndOfStream
24 counter=counter+1
25 thisline=thisfile.readline
26 char1=mid(thisline,1,1)
27 char2=mid(thisline,2,1)
28 rest=mid(thisline,3)
29
30 findhyphen=instr(thisline,"-")
31 question=mid(rest,1,findhyphen-2)
32
33 rest=mid(rest,findhyphen)
34 findslash=instr(rest,"/")
35 answer1=mid(rest,1,findslash-1)
36 answer2=mid(rest,findslash+1)
37
38 'response.write char1 & "<br>"
39 'response.write char2 & "<br>"
40 'response.write rest & "<p>"
41 response.write question & "<br>"
42 'response.write answer1 & "<br>"
43 'response.write answer2 & "<p>"
44 %>
45 <p><input TYPE="radio" name="Q<%=counter%>" VALUE="U" CHECKED>Undecided<br>
46 <input TYPE="radio" name="Q<%=counter%>" VALUE="<%=char1%>"><%=answer1%><br>
47 <input TYPE="radio" name="Q<%=counter%>" VALUE="<%=char2%>"><%=answer2%></p>
48 <p><%
49 loop
50 thisfile.Close
51 set fs=nothing
52 %> <input type="submit"></p>
53 </form>
54 </body>
55 </html>
Reading/Parsing an ASCII File #3 by Charles Carroll
Here is one implementation of scoring the HTML file.
1 <%option explicit%>
2 <html>
3
4 <head>
5 <title>mbrespond.asp</title>
6 </head>
7 <%
8 dim key
9 dim ecount, icount
10 dim scount, ncount
11 dim tcount, fcount
12 dim jcount, pcount
13 dim ucount
14 For Each Key in Request.Form
15 SELECT CASE request.form(key)
16 CASE "E"
17 ecount=ecount+1
18 CASE "I"
19 icount=icount+1
20 CASE "S"
21 scount=scount+1
22 CASE "N"
23 ncount=ncount+1
24 CASE "T"
25 tcount=tcount+1
26 CASE "F"
27 fcount=fcount+1
28 CASE "J"
29 jcount=jcount+1
30 CASE "P"
31 pcount=pcount+1
32 CASE "U"
33 ucount=ucount+1
34 END SELECT
35 Next
36 Response.write "E=" & ecount & "<br>"
37 Response.write "I=" & icount & "<br>"
38 Response.write "S=" & scount & "<br>"
39 Response.write "N=" & ncount & "<br>"
40 Response.write "T=" & tcount & "<br>"
41 Response.write "F=" & fcount & "<br>"
42 Response.write "J=" & jcount & "<br>"
43 Response.write "P=" & pcount & "<br>"
44 Response.write "U=" & ucount & "<br>"
45 %>
46
47 <body bgcolor="#FFFFFF">
48 </body>
49 </html>
Myers Brigg Implemented with XLST
by Jelks Cabaniss jelks@jelks.nu
Parsing an ASCII file ala:
is a process improved considerably by XML as this replacement example written with XLST demonstrates.
You need MSXML3. The May version was released yesterday: http://msdn.microsoft.com/downloads/webtechnology/xml/msxml.asp Click on the link that says "Download the May 2000 MSXML Technology Preview Release" (don't bother with the SDK from the other link). It will download a file called "msxmlwr.exe", a self-extracting archive. Right-click on it and extract the files into a temp folder. From that temp folder, run "xmlinst.exe". Reboot. That will allow XSLT 1.0 stylesheets to run (replacing the old MS-XSL preview in IE5).
mbxml.asp is the main script. Simple enough.
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml">
4 <head>
5 <title>mbxml.asp</title>
6 <style type="text/css"><!--
7 @media screen, projection {
8 body { font-family: verdana, sans-serif; margin: 2% 5%; }
9 h1 { font: 2.3em garamond, georgia, serif; color: maroon; }
10 p { font-size: .9em; margin-left: 2em; color: navy; }
11 }
12 --></style>
13
14 </head>
15 <body>
16 <h1>Myer-Briggs Test</h1>
17 <form method="post" action="mbrespond.asp">
18 <%
19 Call ShowTest("mb.xml","mb.xsl")
20
21 Function ShowTest(strXML,strStyleSheet)
22 Set objXML = CreateObject("MSXML.DOMDocument")
23 Set objXSL = CreateObject("MSXML.DOMDocument")
24 objXML.load(Server.MapPath(strXML))
25 objXSL.load(Server.MapPath(strStyleSheet))
26 Response.Write objXML.transformNode (objXSL)
27 Set objXML = Nothing
28 Set objXSL = Nothing
29 End Function
30 %>
31 <p><input type="submit" value="Check Scores!" /></p>
32 </form>
33 </body>
34 </html>
35
36
mb.xsl is the style sheet to style the questionare.
1 <?xml version="1.0"?>
2 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 version="1.0">
4
5 <xsl:output method="xml" indent="yes"
6 omit-xml-declaration="yes" />
7
8 <xsl:template match="/">
9 <xsl:for-each select="/questionairre/item">
10 <xsl:variable name="Pos" select="position()" />
11 <xsl:variable name="Num" select="concat('Q',$Pos)" />
12 <p><xsl:value-of select="concat($Pos,'. ', question)" />
13 —<br /><br />
14 <input type="radio" name="{$Num}" value="U"
15 checked="checked" />Undecided<br />
16 <xsl:for-each select="answer">
17 <input type="radio" name="{$Num}" value="{@code}" />
18 <xsl:value-of select="." /><br />
19 </xsl:for-each>
20 </p>
21 </xsl:for-each>
22 </xsl:template>
23
24 </xsl:stylesheet>
25
mb.xml is the data that powers the questionare.
1 <?xml version="1.0"?>
2 <questionairre type="MB">
3 <item>
4 <question>At a party do you</question>
5 <answer code="E">interact with many, including strangers</answer>
6 <answer code="I">interact with a few, known to you</answer>
7 </item>
8 <item>
9 <question>Are you more</question>
10 <answer code="S">realistic than speculative</answer>
11 <answer code="N">speculative than realistic</answer>
12 </item>
13 <item>
14 <question>It is worse to</question>
15 <answer code="S">have your "head in the clouds"</answer>
16 <answer code="N">be "in a rut"</answer>
17 </item>
18 <item>
19 <question>Are you more impressed by</question>
20 <answer code="T">principles</answer>
21 <answer code="F">emotions</answer>
22 </item>
23 <item>
24 <question>Are you more drawn toward the</question>
25 <answer code="T">convincing</answer>
26 <answer code="F">touching</answer>
27 </item>
28 <item>
29 <question>Do you prefer to work</question>
30 <answer code="J">to deadlines</answer>
31 <answer code="P">just "whatever"</answer>
32 </item>
33 <item>
34 <question>Do you tend to choose</question>
35 <answer code="J">rather carefully</answer>
36 <answer code="P">somewhat impulsively</answer>
37 </item>
38 <item>
39 <question>At parties do you</question>
40 <answer code="E">stay late, with increasing energy</answer>
41 <answer code="I">leave early, with decreased energy</answer>
42 </item>
43 <item>
44 <question>Are you more attracted to</question>
45 <answer code="S">sensible people</answer>
46 <answer code="N">imaginative people</answer>
47 </item>
48 <item>
49 <question>Are you more interested in</question>
50 <answer code="S">what is actual</answer>
51 <answer code="N">what is possible</answer>
52 </item>
53 <item>
54 <question>In judging others are you more swayed by</question>
55 <answer code="T">laws than circumstances</answer>
56 <answer code="F">circumstances than laws</answer>
57 </item>
58 <item>
59 <question>In approaching others is your inclination to be</question>
60 <answer code="T">objective</answer>
61 <answer code="F">personal</answer>
62 </item>
63 <item>
64 <question>Are you more</question>
65 <answer code="J">punctual</answer>
66 <answer code="P">leisurely</answer>
67 </item>
68 <item>
69 <question>Does it bother you more having things</question>
70 <answer code="J">incomplete</answer>
71 <answer code="P">completed</answer>
72 </item>
73 <item>
74 <question>In your social groups do you</question>
75 <answer code="E">keep abreast of other's happenings</answer>
76 <answer code="I">get behind on the news</answer>
77 </item>
78 <item>
79 <question>In doing ordinary things are your more likely to</question>
80 <answer code="S">do it the usual way</answer>
81 <answer code="N">do it your own way</answer>
82 </item>
83 <item>
84 <question>Writers should</question>
85 <answer code="S">say what they mean and mean what they say</answer>
86 <answer code="N">express things more by use of analogy</answer>
87 </item>
88 <item>
89 <question>Which appeals to you more</question>
90 <answer code="T">consistency of thought</answer>
91 <answer code="F">harmonious human relationships</answer>
92 </item>
93 <item>
94 <question>Are you more comfortable in making</question>
95 <answer code="T">logical judgments</answer>
96 <answer code="F">value judgmants</answer>
97 </item>
98 <item>
99 <question>Do you want things</question>
100 <answer code="J">settled and decided</answer>
101 <answer code="P">unsettled and undecided</answer>
102 </item>
103 <item>
104 <question>Would you say you are more</question>
105 <answer code="J">serious and determined</answer>
106 <answer code="P">easy-going</answer>
107 </item>
108 <item>
109 <question>In phoning do you</question>
110 <answer code="E">rarely question that it will all be said</answer>
111 <answer code="I">rehearse what you'll say</answer>
112 </item>
113 <item>
114 <question>Facts</question>
115 <answer code="S">speak for themselves</answer>
116 <answer code="N">illustrate principles</answer>
117 </item>
118 <item>
119 <question>Are visionaries</question>
120 <answer code="S">somewhat annoying</answer>
121 <answer code="N">rather fascinating</answer>
122 </item>
123 <item>
124 <question>Are you more often</question>
125 <answer code="T">a cool-headed person</answer>
126 <answer code="F">a warm-hearted person</answer>
127 </item>
128 <item>
129 <question>Is it worse to be</question>
130 <answer code="T">unjust</answer>
131 <answer code="F">merciless</answer>
132
133 </item>
134 <item>
135 <question>Should one usually let events occur</question>
136 <answer code="J">by careful selection and choice</answer>
137 <answer code="P">randomly and by chance</answer>
138 </item>
139 <item>
140 <question>Do you feel better about</question>
141 <answer code="J">having purchased</answer>
142 <answer code="P">having the option to buy</answer>
143 </item>
144 <item>
145 <question>In company do you</question>
146 <answer code="E">initiate conversation</answer>
147 <answer code="I">wait to be approached</answer>
148 </item>
149 <item>
150 <question>Common sense is</question>
151 <answer code="S">rarely questionable</answer>
152 <answer code="N">frequently questionable</answer>
153 </item>
154 <item>
155 <question>Children often do not</question>
156 <answer code="S">make themselves useful enough</answer>
157 <answer code="N">exercise their fantasy enough</answer>
158 </item>
159 <item>
160 <question>In making decisions do you feel more comfortable with</question>
161 <answer code="T">standards</answer>
162 <answer code="F">feelings</answer>
163 </item>
164 <item>
165 <question>Are you more</question>
166 <answer code="T">firm than gentle</answer>
167 <answer code="F">gentle than firm</answer>
168 </item>
169 <item>
170 <question>Which is more admirable</question>
171 <answer code="J">the ability to organize and be methodical</answer>
172 <answer code="P">the ability to adapt and make do</answer>
173 </item>
174 <item>
175 <question>Do you put more value on the</question>
176 <answer code="J">definite</answer>
177 <answer code="P">open-ended</answer>
178 </item>
179 <item>
180 <question>Does new and non routine interaction with others</question>
181 <answer code="E">stimulate and energize you</answer>
182 <answer code="I">tax your reserves</answer>
183 </item>
184 <item>
185 <question>Are you more frequently</question>
186 <answer code="S">a practical sort of person</answer>
187 <answer code="N">a fanciful sort of person</answer>
188 </item>
189 <item>
190 <question>Are you more likely to</question>
191 <answer code="S">see how others are useful</answer>
192 <answer code="N">see how others see</answer>
193 </item>
194 <item>
195 <question>Which is more satisfying</question>
196 <answer code="T">to discuss an issue thoroughly</answer>
197 <answer code="F">to arrive at agreement on an issue</answer>
198 </item>
199 <item>
200 <question>Which rules you more</question>
201 <answer code="T">your head</answer>
202 <answer code="F">your heart</answer>
203 </item>
204 <item>
205 <question>Are you more comfortable with work that is</question>
206 <answer code="J">contracted</answer>
207 <answer code="P">done on a casual basis</answer>
208 </item>
209 <item>
210 <question>Do you tend to look for</question>
211 <answer code="J">the orderly</answer>
212 <answer code="P">whatever turns up</answer>
213 </item>
214 <item>
215 <question>Do you prefer</question>
216 <answer code="E">many friends with brief contact</answer>
217 <answer code="I">a few friends with more lengthy contact</answer>
218 </item>
219 <item>
220 <question>Do you go more by</question>
221 <answer code="S">facts</answer>
222 <answer code="N">principles</answer>
223 </item>
224 <item>
225 <question>Are you more interested in</question>
226 <answer code="S">production and distribution</answer>
227 <answer code="N">design and research</answer>
228 </item>
229 <item>
230 <question>Which is more of a compliment</question>
231 <answer code="T">There is a very logical person.</answer>
232 <answer code="F">There is a very sentimental person.</answer>
233 </item>
234 <item>
235 <question>Do you value in yourself more that you are</question>
236 <answer code="T">unwavering</answer>
237 <answer code="F">devoted</answer>
238 </item>
239 <item>
240 <question>Do you more often prefer the</question>
241 <answer code="J">final and unalterable statement</answer>
242 <answer code="P">tentative and preliminary statement</answer>
243 </item>
244 <item>
245 <question>Are you more comfortable</question>
246 <answer code="J">after a decision</answer>
247 <answer code="P">before a decision</answer>
248 </item>
249 <item>
250 <question>Do you</question>
251 <answer code="E">speak easily and length with strangers</answer>
252 <answer code="I">find little to say to strangers</answer>
253 </item>
254 <item>
255 <question>Are you more likely to trust your</question>
256 <answer code="S">experience</answer>
257 <answer code="N">hunch</answer>
258 </item>
259 <item>
260 <question>Do you feel</question>
261 <answer code="S">more practical than ingenious</answer>
262 <answer code="N">more ingenious than practical</answer>
263 </item>
264 <item>
265 <question>Which person is more to be complimented</question>
266 <answer code="T">one of clear reason</answer>
267 <answer code="F">strong feeling</answer>
268 </item>
269 <item>
270 <question>Are you inclined more to be</question>
271 <answer code="T">fair minded</answer>
272 <answer code="F">sysmpathetic</answer>
273 </item>
274 <item>
275 <question>Is it preferable mostly to</question>
276 <answer code="J">make sure things are arranged</answer>
277 <answer code="P">just let things happen</answer>
278 </item>
279 <item>
280 <question>In relationships should most things to</question>
281 <answer code="J">renegotiable</answer>
282 <answer code="P">random and circumstantial</answer>
283 </item>
284 <item>
285 <question>When the phone rings do you</question>
286 <answer code="E">hasten to get to it first</answer>
287 <answer code="I">hope someone else will answer</answer>
288 </item>
289 <item>
290 <question>Do you prize more in yourself</question>
291 <answer code="S">a strong sense of reality</answer>
292 <answer code="N">a vivid imagination</answer>
293 </item>
294 <item>
295 <question>Are you drawn more to</question>
296 <answer code="S">fundamentals</answer>
297 <answer code="N">overtones</answer>
298 </item>
299 <item>
300 <question>Which seems the greater error</question>
301 <answer code="T">to be too passionate</answer>
302 <answer code="F">to be too objective</answer>
303 </item>
304 <item>
305 <question>Do you see yourself as basically</question>
306 <answer code="J">the structured and scheduled</answer>
307 <answer code="P">the unstructured and unscheduled</answer>
308 </item>
309 <item>
310 <question>Are you a person that is more</question>
311 <answer code="J">routinized than whimsical</answer>
312 <answer code="P">whimsical than routinized</answer>
313 </item>
314 <item>
315 <question>Are you inclined to be</question>
316 <answer code="E">easy to approach</answer>
317 <answer code="I">somewhat reserved</answer>
318 </item>
319 <item>
320 <question>In writings do you prefer</question>
321 <answer code="S">the more literal</answer>
322 <answer code="N">the more figurative</answer>
323 </item>
324 <item>
325 <question>Is it harder for you to</question>
326 <answer code="S">identify with others</answer>
327 <answer code="N">utilize others</answer>
328 </item>
329 <item>
330 <question>Which do you wish more for yourself</question>
331 <answer code="T">clarity of reason</answer>
332 <answer code="F">strength of compassion</answer>
333 </item>
334 <item>
335 <question>Which is the greater fault</question>
336 <answer code="T">being indiscriminate</answer>
337 <answer code="F">being critical</answer>
338 </item>
339 <item>
340 <question>Do you prefer the</question>
341 <answer code="E">planned event</answer>
342 <answer code="I">unplanned event</answer>
343 </item>
344 <item>
345 <question>Do you tend to be more</question>
346 <answer code="J">deliberate than spontaneous</answer>
347 <answer code="P">spontaneous than deliberate</answer>
348 </item>
349 </questionairre>
Content Linking Prev/Next
1 <%
2 Set NL = Server.CreateObject ("MSWC.NextLink")
3 tocname="/learn/learn.txt"
4 nextref=NL.GetNextURL(tocname)
5 nextdes=NL.GetNextDescription(tocname)
6 If (NL.GetListIndex (tocname)>1) Then
7 prevref=NL.GetPreviousURL(tocname)
8 prevdes=NL.GetPreviousDescription(tocname)
9 %>
10 Prev:<a href="<%=prevref%>"><%=prevdes%></a> Next:
11 <% End If %>
12 <a href="<%=nextref%>"><%=nextdes%></a>
Content Linking TOC
1 <TITLE>cl2.asp</TITLE>
2 <body bgcolor="#FFFFFF">
3 <%
4 Set TL = Server.CreateObject ("MSWC.NextLink")
5 for i=1 to cint(TL.GetListCount("/learn/learn.txt"))%>
6 Description:
7 <%=TL.GetNthDescription ("/learn/learn.txt",i)%>,
8 (URL=<%=TL.GetNthURL ("/learn/learn.txt",i)%>).
9 Page <%=i%>.<p>
10 <% next%>
11 </body>
12 </html>
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 <HTML><HEAD><TITLE>cljump.asp</TITLE></HEAD>
2 <body bgcolor="#FFFFFF">
3 <FORM ACTION="cljumprespond.asp">
4 <%
5 Set TL = Server.CreateObject ("MSWC.NextLink")
6 maxi= cint(TL.GetListCount("/learn/learn.txt"))
7 %>
8 <SELECT name="whichtopic">
9 <OPTION SELECTED VALUE="">Select a Topic...
10 <%for i=1 to maxi%>
11 <OPTION value=
12 <%=TL.GetNthURL("/learn/learn.txt",i)%>
13 >
14 <%
15 desc=TL.GetNthDescription("/learn/learn.txt",i)
16 if mid(desc,1,1)="*" then
17 desc=mid(desc,2)
18 else
19 desc=" " & desc
20 end if
21 %>
22 <%=desc%>
23 <%next%>
24 </SELECT> <INPUT VALUE="Jump to Lesson" TYPE=submit></FORM>
25 </BODY>
26 </HTML>
The script named cljumprespond.asp that implements the jump looks like this:
1 <%
2 response.redirect request.querystring("whichtopic")
3 %>
Content Linker Enhanced w/Library by Charles Carroll
The Microsoft Content Linker component, see:
http://www.learnasp.com/iishelp/iis/htm/asp/comp7pmc.htm
allows you to use an ASCII file that can be used to setup previous-next page
style presentations. I like it so much I created a whole top-level library to
simplify using it.
Here is a sample of the library being used:
1 <!--#include file="lib_toc_v4.asp"-->
2 <%
3 ' The Below Code is used to Test The Library if in doubt
4 Call TOCpretty("/learn/learn.toc")
5 ' Call TOC2Joust("/learn/learn.toc")
6 ' Call TOC2Joust("/asplists/asplists.toc")
7 ' x Call TOC2ColumnTable("/learn/learn.toc")
8 ' Call TOCGrabSection("/learn/learn.toc","core.asp")
9 ' Call TOCGrabSectionPretty("/learn/learn.toc","core.asp")
10 ' Call TOCGrabSectionLimit("/learn/learn.toc","core.asp",6)
11 ' Call TOCGrabSectionRandom("/learn/learn.toc","core.asp")
12 ' Call TOCGrabSectionRandomLimit("/learn/learn.toc","core.asp",4)
13 ' Call TOCList("/learn/learn.toc","/library/jump.asp")
14 ' response.write TOCPageType("/learn/core.asp")
15 ' response.write TOCPageType("/learn/dbtable.asp")
16 ' Call TOCSection2ListBox("/learn/learn.toc","core.asp")
17 %>
The Include file lib_toc_formats.asp looks like this:
1 <%
2 SELECT CASE lcase(parmformat)
3 CASE "2coltoc"
4 pad=" "
5 leftcell="<td bgcolor='#99CCFF'>"
6 rightcell="<td bgcolor='#CCCCFF'>"
7 linklook="<strong><B>%%linkhref%%</strong></b>"
8
9 L1format="<tr>" & leftcell & linklook & "<td></tr>"
10 L2format="<tr><td>" & pad & "%%linkhref%%</td></tr>"
11 L1eformat="<tr>" & rightcell & linklook & "<td></tr>"
12
13 TOCprefix="<table cols='1' border='1' width='50%'>"
14 TOCsuffix="</table>"
15 CASE "joust"
16 q = chr(34)
17 linebreak=vbcrlf ' & "<br>"
18
19 TOCprefix="<script language='JavaScript'>" & linebreak
20 TOCprefix=TOCprefix & "function initialise() {" & linebreak
21 TOCprefix=TOCprefix & "// Tell joust where to find the various index files it needs" & linebreak
22 TOCprefix=TOCprefix & "index1 = ""index.htm"";" & linebreak
23 TOCprefix=TOCprefix & "index2 = ""index2.htm"";" & linebreak
24 TOCprefix=TOCprefix & "index3 = ""index3.htm"";" & linebreak
25 TOCprefix=TOCprefix & "theBrowser.hasDHTML=false;" & linebreak
26 TOCprefix=TOCprefix & "// Set up parameters to control menu behaviour" & linebreak
27 TOCprefix=TOCprefix & "theMenu.autoScrolling = true;" & linebreak
28 TOCprefix=TOCprefix & "theMenu.modalFolders = false;" & linebreak
29 TOCprefix=TOCprefix & "theMenu.linkOnExpand = false;" & linebreak
30 TOCprefix=TOCprefix & "theMenu.toggleOnLink = false;" & linebreak
31 TOCprefix=TOCprefix & "theMenu.showAllAsLinks = false;" & linebreak
32 TOCprefix=TOCprefix & "theMenu.focusOnLink = true;" & linebreak
33 TOCprefix=TOCprefix & "theMenu.savePage = true;" & linebreak
34 TOCprefix=TOCprefix & "theMenu.tipText = ""status"";" & linebreak
35 TOCprefix=TOCprefix & "theMenu.name = ""theMenu"";" & linebreak
36 TOCprefix=TOCprefix & "theMenu.container = ""self.menu"";" & linebreak
37 TOCprefix=TOCprefix & "theMenu.reverseRef = ""parent"";" & linebreak
38 TOCprefix=TOCprefix & "theMenu.contentFrame = 'text';" & linebreak
39 TOCprefix=TOCprefix & "theMenu.defaultTarget = 'text';" & linebreak
40 TOCprefix=TOCprefix & "// Initialise all the icons" & linebreak
41 TOCprefix=TOCprefix & "initOutlineIcons(theMenu.imgStore);" & linebreak
42 TOCprefix=TOCprefix & "// Now set up the menu with a whole lot of addMenu and addChild function calls" & linebreak
43
44 TOCsuffix= "}" & linebreak & "</script>"
45
46 L1format=linebreak & "var level%%sectioncount%%ID=-1;" & linebreak
47 L1format=L1format & "theMenu.addEntry(-1, "
48 L1format=L1format & q & "folder" & q & ","
49 L1format=L1format & q & "%%linkdesc%%" & q & ","
50 L1format=L1format & q & q & ","
51 L1format=L1format & q & "%%linkdesc%%" & " help" & q & ");"
52
53 L2format="theMenu.addChild(level%%sectioncount%%" & "ID,"
54 L2format=L2format & q & "Document" & q & ","
55 L2format=L2format & q & "%%linkdesc%%" & q & ","
56 L2format=L2format & q & "%%fullurl%%?view=joust" & q & ","
57 L2format=L2format & q & "%%linkdesc%%" & " help" & q & ");"
58
59 L1eformat=L1eformat & linebreak & "var level%%sectioncount%%ID=-1;" & linebreak
60 L1eformat=L1eformat & "theMenu.addEntry(-1, "
61 L1eformat=L1eformat & q & "document" & q & ","
62 L1eformat=L1eformat & q & "%%linkdesc%%" & q & ","
63 L1eformat=L1eformat & q & "%%fullurl%%?view=joust" & q & ","
64 L1eformat=L1eformat & q & "%%linkdesc%%" & " help" & q & ");"
65 CASE "section"
66 L1format=""
67 L2format=" %%linkhref%%<br>"
68 CASE "sectionpretty"
69 pad=" "
70
71 L1format="<P><strong><B>%%linkhref%%</strong></b><br>"
72 L2format=pad & "%%linkhref%% (%%linkurl%%)<br>"
73 CASE "sectionplain"
74 L1format=""
75 L2format=" %%linkhref%%<br>"
76
77 CASE "listwhichtopic"
78 TOCprefix="<form action='/library/where.asp'>"
79 TOCprefix=TOCprefix & "<select name='whichtopic'>"
80 TOCsuffix="</select>"
81
82 L1format=""
83 L2format="<option value='%%fullurl%%'>%%linkdesc%%</option>" & vbcrlf
84 CASE "listonly"
85 L1format=""
86 L2format="<option value='%%fullurl%%'>%%linkdesc%%</option>" & vbcrlf
87 CASE "pretty"
88 pad=" "
89 L1format="<P><strong><B>%%linkhref%%</strong></b><br>"
90 L2format=pad & "%%linkhref%% (%%linkurl%%)<br>"
91 CASE ELSE
92 response.write "unknown format"
93 END SELECT
94 %>
95
The Include file lib_toc_v4.asp looks like this:
1 <%
2 ' version 98
3 ' bug: LimitRandom is sometimes one entry short
4 ' draft: solution to caching issue, each call needs a moniker
5 ' SUB TOCProcess is the Powerhouse here
6 ' Almost every routine calls it
7 ' It can return a string or response.write
8 ' any content linker file and format output
9 ' It can clip number of entries show and/or randomly arrange them
10
11
12 FUNCTION printview()
13 printview=False
14 printsession=lcase(session("printview"))
15 printrequest=lcase(request("printstatus"))
16 If printsession="y" OR printrequest="y" then
17 printview=True
18 end if
19 END FUNCTION
20
21 SUB ShowTOC(parmTOC)
22 Call TOCPretty(parmTOC)
23 END SUB
24
25 SUB TOC2ColumnTable(parmTOC)
26 Call TOCProcess(parmTOC,"","2coltoc",0,false,false,false)
27 END SUB
28
29 SUB TOC2Joust(parmTOC)
30 Call TOCProcess(parmTOC,"","joust",0,false,false,false)
31 END SUB
32
33
34 SUB TOCGrabSection(parmTOC,parmTarget)
35 Call TOCProcess(parmTOC,parmTarget,"section",0,false,false,false)
36 END SUB
37
38 SUB TOCGrabSectionLimit(parmTOC,parmTarget,parmHowMany)
39 Call TOCProcess(parmTOC,parmTarget,"section",parmHowMany,false,false,false)
40 END SUB
41
42 SUB TOCGrabSectionPretty(parmTOC,parmTarget)
43 Call TOCProcess(parmTOC,parmTarget,"sectionpretty",0,false,false,false)
44 END SUB
45
46 SUB TOCGrabSectionRandom(parmTOC,parmTarget)
47 Call TOCProcess(parmTOC,parmTarget,"sectionplain",0,true,false,false)
48 END SUB
49
50 SUB TOCGrabSectionRandomLimit(parmTOC,parmTarget,parmHowmany)
51 Call TOCProcess(parmTOC,parmTarget,"sectionplain",parmHowMany,true,false,false)
52 END SUB
53
54 SUB TOCLevel1(parmTOC)
55 Call TOCPretty(parmTOC)
56 END SUB
57
58 SUB TOCList(parmTOC,parmForm)
59 Call TOCProcess(parmTOC,parmTarget,"listwhichtopic",0,true,false,false)
60 END SUB
61
62 SUB TOClistshort(tocname,jumpname)
63 ' Legacy Code, rewrite or ditch
64 Set TL = Server.CreateObject ("MSWC.NextLink")
65 maxi= cint(TL.GetListCount(tocname))-1
66 adinfo="<a href='http://www.activeserverpages.com/contactus.asp'><strong>Contact Us...</strong></a>"
67 adinfo=""
68 response.write "<FORM ACTION='" & jumpname & "'>"
69 response.write "<a href='/search/'>"
70 response.write "<img src='/images/search.gif' alt='search' border='0' WIDTH='74' HEIGHT='24'></a>"
71 response.write " <a href='/contactus/index.asp'>"
72 response.write "<img src='/images/contact.gif' alt='contact' border='0' WIDTH='74' HEIGHT='24'></a>"
73 response.write " " & adinfo
74 response.write " <SELECT name='whichtopic'><OPTION SELECTED VALUE='/search>Search</option>"
75 for i=1 to maxi
76 desc=TL.GetNthDescription(tocname,i)
77 if mid(desc,1,1)="*" then
78 desc=mid(desc,2)
79 temp="<OPTION value='" & TL.GetNthURL(tocname,i) & "'>" & desc & "</option>"
80 response.write temp
81 end if
82 next
83 set TL=nothing
84 response.write "</SELECT> <INPUT VALUE='go!' TYPE='submit'>"
85 response.write "<a href='http://www.charlescarroll.com'><img src='/images/cc.gif' border='0' width='150' height='27' alt='Charles Carroll'></a></FORM>"
86 END SUB
87
88 SUB TOCListSection(parmTOC,parmTarget)
89 Call TOCProcess(parmTOC,parmTarget,"listwhichtopic",0,false,false,false)
90 END SUB
91
92 SUB TOCPretty(parmTOC)
93 allformat=L1format & L2Format
94 Call TOCProcess(parmTOC,"","pretty",0,false,false,false)
95 END SUB
96
97 SUB TOCSection2ListBox(parmTOC,parmTarget)
98 Call TOCProcess(parmTOC,parmTarget,"listonly",0,false,false,false)
99 END SUB
100
101 SUB TOCshow(tocname)
102 printer="<img src='http://www.activeserverpages.com/learn/printer.gif' WIDTH='33' HEIGHT='29' BORDER='0'>"
103 printerlink="<a href='/learn/printswitch.asp'>" & printer & "</a> "
104
105 barcolor="#CCCCFF"
106
107 title=printer
108 title=title & "<font face='Arial'><small><strong>Tutorial Questions? write <a href='mailto:aspquicklessons@activeserverpages.com'>aspquicklessons@activeserverpages.com</a> for help!"
109 title=title & "</font></small></strong>"
110 sn=request.servervariables("script_name")
111
112 tocname=lcase(tocname)
113 printstatus=lcase(session("printview"))
114 If request("printstatus")="y" then
115 printstatus="y"
116 end if
117
118 if printstatus="y" then
119 imgnext="<img src='/learn/arrowright.gif' WIDTH='33' HEIGHT='14' BORDER='0'>"
120 imgprev="<img src='/learn/arrowleft.gif' WIDTH='33' HEIGHT='14' BORDER='0'>"
121 else
122 imgnext="<img src='http://www.activeserverpages.com/learn/next.gif' BORDER='0'>"
123 imgprev="<img src='http://www.activeserverpages.com/learn/previous.gif' BORDER='0'> "
124 end if
125
126
127 Set NL = Server.CreateObject ("MSWC.NextLink")
128 thispage=NL.GetListIndex(tocname)
129 lastpage=NL.GetListCount(tocname)
130 'response.write "thispage=" & thispage & "<br>"
131 If thispage=0 then
132 thisrefdesc=""
133 ELSE
134 thisrefDESC=NL.GetNthDescription(tocname,thispage)
135 END IF
136
137 If thispage<>lastpage AND thispage<>0 then
138 nextref=NL.GetNextURL(tocname)
139 nextrefdesc=NL.GetNextDescription(tocname)
140 nextreflink="<a href='" & nextref & "'>" & nextrefdesc & " " & imgnext & "</a>"
141 nextlink="<a href='" & nextref & "'>" & imgnext & "</a>"
142 Else
143 imgnext=""
144 nextref=""
145 nextrefdesc=""
146 nextreflink=""
147 end if
148
149 If (thispage>1) Then
150 prevrefdesc=NL.GetPreviousDescription(tocname)
151 prevref=NL.GetPreviousURL(tocname)
152 prevreflink="<a href='" & prevref & "'>" & imgprev & prevrefdesc & "</a>"
153 prevlink="<a href='" & prevref & "'>" & imgprev & "</a>"
154 else
155 imgprev=""
156 prevref=""
157 prevrefdesc=""
158 prevreflink=""
159 end if
160
161 SELECT CASE printstatus
162 CASE "y"
163 ' print view!
164 host=request.servervariables("http_host")
165 host="http://www.learnASP.com"
166 response.write "<table border='0' width='100%' bgcolor='#CCCCFF'>"
167 response.write "<tr><td align='center'>" & printerlink
168 response.write "<font face='Arial'> <strong>"
169 response.write host & sn & " by Charles M. Carroll</strong></font><br>"
170 response.write prevlink & " "
171 response.write "<font face='Arial' size='+1'><strong>Page " & thispage & "</strong></font>"
172 response.write nextlink
173 response.write "</td></tr></table>"
174 CASE ELSE
175 response.write "<table border='0' width='100%'>"
176 response.write "<tr><td width='50%' bgcolor='#FFCC66'>"
177 response.write "<font size='+1'><strong>" & thisrefdesc & "</strong>"
178 response.write "</td>"
179 response.write "<td width='50%' bgcolor='#FFCC66'>"
180 response.write "<strong><small>"
181 customTOC=false
182 IF instr(tocname,"learn.toc")>0 THEN
183 customTOC=TRUE%>
184 <!--#include virtual="/learn/toolbar.asp"-->
185 <%END IF
186 IF instr(tocname,"asplists.toc")>0 THEN
187 customTOC=TRUE%>
188 <!--#include virtual="/asplists/toolbar.asp"-->
189 <%END IF
190 if customTOC=false THEN
191 response.write "<a href='toc.asp'>Table of Contents</a> "
192 response.write "<a href='/library/printswitch.asp'>PrintView</a>"
193 END IF
194 response.write "</small></strong></td></tr>"
195
196 response.write "<tr>" & "<td width='50%' bgcolor='" & barcolor & "'>"
197 response.write "<strong>" & prevreflink & "</strong></td>"
198
199 response.write "<td width='50%' bgcolor='" & barcolor & "' align='right'>"
200 response.write "<strong>" & nextreflink & "</strong>"
201 response.write "</td></tr></table>"
202 END SELECT
203 set NL=nothing
204 end sub
205
206 FUNCTION TOCPageType(parmPageURL)
207 ' Returns "page" or "toc"
208 whichfile=server.mappath(parmpageURL)
209 Set fs = CreateObject("Scripting.FileSystemObject")
210 If fs.fileexists(whichfile) THEN
211 ' do nothing
212 ELSE
213 response.write "Error, Non-existent File="
214 response.write whichfile & "<br>" & vbcrlf
215 exit function
216 END IF
217 Set thisfile = fs.OpenTextFile(whichfile, 1, False)
218 tempSTR=lcase(thisfile.readall)
219 TOCPageType="page"
220 IF instr("tocsubject.asp",tempSTR)>0 THEN
221 TOCpageType="toc"
222 END IF
223 IF instr(tempSTR,"mutanttoc.asp")>0 THEN
224 TOCpageType="toc"
225 END IF
226 IF instr(tempSTR,"mutantsection.asp")>0 THEN
227 TOCpageType="toc"
228 END IF
229 thisfile.Close
230 set thisfile=nothing
231 set fs=nothing
232 END FUNCTION
233
234 SUB TOCProcess(parmDIR,parmTargets,parmFormat,parmLimit,parmRandom,byref parmString,parmDebug)
235 ' parmDIR can be "/learn" or "/learn/learn.toc"
236 ' parmtarget can be "" or a filename i.e. "test.asp"
237 ' parmFormat
238 ' L1-<b><strong>-</b></strong><p>-
239 ' L2- -<br>-
240 ' parmLimit
241 ' maximum items (0= all)
242 ' parmRandom
243 ' True = Randomize order
244 ' False = original order
245 ' parmString
246 ' True = Assign output to passed variable
247 ' False = DisplayOutput normally
248
249 DIM count, countmax, FullURL, Issection
250 DIM Level, Linker, LinkDesc, LinkURL, LinkHREF
251 DIM NameSection, pad
252
253 ' First deal with parmDIR
254 tocname=lcase(parmdir)
255 IF instr(tocname,".toc")=0 THEN
256 tocname=parmDIR & parmDIR & ".toc"
257 TOCDIR=parmDIR
258 ELSE
259 tocname=parmDIR
260 END IF
261 If parmdebug=true THEN
262 response.write "TOCname=" & TOCname & "<br>"
263 END IF
264
265 ' Now extract TOCDIR
266 TOCDir=replace(TOCDIR,".toc","")
267 findslash=instr(2,TocName,"/")
268 tocDIR=mid(TocName,1,findslash-1)
269 If parmdebug=true THEN
270 response.write "TOCdir=" & tocDIR & "<br>"
271 END IF
272
273 ' Now extract section target
274 Sectiontarget=lcase(parmTargets)
275 If parmdebug=true THEN
276 response.write "sectiontarget=" & sectiontarget & "<br>"
277 END IF
278
279 ' Now extract formats
280 %>
281 <!--#include file="lib_toc_formats.asp"-->
282 <%
283 IF L1format="" THEN
284 skipL1=TRUE
285 END IF
286 L1emptystring=L1eformat
287 L1string=L1format
288 L2string=L2format
289 IF L1eformat="" THEN
290 L1emptystring=L1string
291 END IF
292
293 If parmdebug=true THEN
294 response.write "L1string=" & server.htmlencode(L1string) & "<br>"
295 response.write "L2string=" & server.htmlencode(L2string) & "<br>"
296
297 'response.end
298 END IF
299
300 displayoutput=true
301 If parmLimit>0 THEN
302 displayoutput=false
303 ELSE
304 parmLimit=0
305 END IF
306 If parmString=TRUE OR parmRandom=TRUE THEN
307 displayoutput=false
308 END IF
309
310 ' Now work on the items
311 Set Linker = Server.CreateObject ("MSWC.NextLink")
312 countmax=cint(Linker.GetListCount(tocname))
313 redim preserve thelinks(countmax)
314 thelinkscount=0
315
316 If displayoutput=TRUE THEN
317 response.write TOCprefix
318 END IF
319 for counter=1 to countmax
320 ' SETUP
321 LinkDesc=Linker.GetNthDescription(tocname,counter)
322 LinkURL =Linker.GetNthURL(tocname,counter)
323 FullURL =TocDir & "/" & LinkURL
324
325 IF mid(Linkdesc,1,1)="*" THEN
326 linkDesc=mid(linkDesc,2)
327 NameSection=lcase(linkURL)
328 docType="L1"
329 If counter<>countmax THEN
330 LinkDescNext=Linker.GetNthDescription(tocname,counter+1)
331 IF mid(LinkdescNext,1,1)="*" THEN
332 doctype="L1empty"
333 END IF
334 END IF
335 sectioncount=sectioncount+1
336 ELSE
337 docType="L2"
338 END IF
339 IF SectionTarget="" THEN
340 ' nothing to do
341 ELSE
342 IF SectionTarget<>NameSection THEN
343 doctype="skip"
344 END IF
345 END IF
346
347 IF doctype="L1" AND skipL1=TRUE THEN
348 doctype="skip"
349 END IF
350
351 LinkHREF="<a href='" & FullURL & "'>" & linkDesc & "</a>"
352 pagecounter=pagecounter+1
353
354 ' Fixes " problem inside Desc
355 linkdesc=replace(linkdesc,"""",""")
356
357 ' Now stuff the variables
358 L1output=replace(L1string,"%%linkhref%%",LinkHREF)
359 L1output=replace(L1output,"%%linkdesc%%",LinkDesc)
360 L1output=replace(L1output,"%%linkurl%%",LinkURL)
361 L1output=replace(L1output,"%%fullurl%%",fullURL)
362 L1output=replace(L1output,"%%pagecounter%%",pagecounter)
363 L1output=replace(L1output,"%%sectioncount%%",sectioncount)
364
365 L1emptyoutput=replace(L1emptystring,"%%linkhref%%",LinkHREF)
366 L1emptyoutput=replace(L1emptyoutput,"%%linkdesc%%",LinkDesc)
367 L1emptyoutput=replace(L1emptyoutput,"%%linkurl%%",LinkURL)
368 L1emptyoutput=replace(L1emptyoutput,"%%fullurl%%",fullURL)
369 L1emptyoutput=replace(L1emptyoutput,"%%pagecounter%%",pagecounter)
370 L1emptyoutput=replace(L1emptyoutput,"%%sectioncount%%",sectioncount)
371
372 L2output=replace(L2string,"%%linkhref%%",LinkHREF)
373 L2output=replace(L2output,"%%linkdesc%%",LinkDesc)
374 L2output=replace(L2output,"%%linkurl%%",LinkURL)
375 L2output=replace(L2output,"%%fullurl%%",fullURL)
376 L2output=replace(L2output,"%%pagecounter%%",pagecounter)
377 L2output=replace(L2output,"%%sectioncount%%",sectioncount)
378
379 SELECT CASE lcase(doctype)
380 CASE "l1"
381 If displayoutput=TRUE THEN
382 response.write L1output & vbcrlf
383 END IF
384 thelinks(thelinkscount)=L1output
385 thelinkscount=thelinkscount+1
386 CASE "l1empty"
387 If displayoutput=TRUE THEN
388 response.write L1emptyoutput & vbcrlf
389 END IF
390 thelinks(thelinkscount)=L1emptyoutput
391 thelinkscount=thelinkscount+1
392 CASE "l2"
393 IF displayoutput=TRUE THEN
394 response.write L2output & vbcrlf
395 END IF
396 thelinks(thelinkscount)=L2output
397 thelinkscount=thelinkscount+1
398 CASE "skip"
399 ' nothing to do
400 END SELECT
401 NEXT
402 If displayoutput=TRUE THEN
403 response.write TOCsuffix
404 END IF
405 set linker=nothing
406
407
408 ' Re-arrange the output array if requested
409 IF parmRandom=TRUE THEN
410 FOR shuffler=1 TO 3
411 FOR counter=0 to thelinkscount-1
412 randomize
413 randomnum=int(rnd*thelinkscount)
414 randchoice=thelinks(randomnum)
415 lastchoice=thelinks(thelinkscount)
416 thelinks(thelinkscount)=randchoice
417 thelinks(randomnum)=lastchoice
418 NEXT
419 NEXT
420 END IF
421
422 If parmString=TRUE THEN
423 displayoutput=false
424 END IF
425
426 ' some calls want the string set and no display output
427 IF parmstring=TRUE THEN
428 IF parmLimit>0 THEN
429 parmstring=TOCprefix
430 FOR counter=0 TO parmLimit-1
431 parmString=parmString & thelinks(counter)
432 NEXT
433 parmString=ParmString & TOCsuffix
434 END IF
435 IF parmLimit=0 THEN
436 parmString=TOCprefix
437 FOR counter=0 to thelinkscount-1
438 parmString=parmString & thelinks(counter)
439 NEXT
440 parmString=ParmString & TOCsuffix
441 END IF
442 EXIT SUB
443 END IF
444
445 ' Since they don't want a string lets display what they want
446 IF parmLimit>0 AND displayoutput=false THEN
447 response.write TOCprefix
448 FOR counter=0 TO parmLimit-1
449 response.write thelinks(counter) & vbcrlf
450 NEXT
451 response.write TOCsuffix
452 END IF
453 ' Show All Output If Needed
454 IF parmLimit=0 AND displayoutput=false THEN
455 response.write TOCprefix
456 FOR counter=0 TO thelinkscount-1
457 response.write thelinks(counter) & vbcrlf
458 NEXT
459 response.write TOCsuffix
460 END IF
461 END SUB
462 %>
Here is what the ASCII file it uses looks like:
1 index.asp *ASP Quick Lessons - Table of Contents
2
3 credits.asp *Credits
4
5 core.asp *Core Ideas
6 whatis.asp What is ASP? Obtaining The Software
7 aspinstall.asp AspInstall listserver
8 whatisexample.asp Simple ASP Page, Server Scripting
9 docs.asp MS Online Documentation
10 res.asp Response: Basics
11 res2.asp Response: Buffers, Redirect
12 res3.asp Response: Redirection
13 res4.asp Response: Quotes & Special Characters
14 res5.asp Response: Encoding URLs, HTML
15 inc.asp Include: Basics
16 includedynamic.asp Include: Dynamic FileName
17 includeasphttp.asp Includes: Other Sites, Dynamic FileNames
18 incwin2k.asp Include/Redirects: New Win2k Commands
19 booksample.asp Include: Books Sample Exercise
20 booksample2.asp More Book Sample Exercises
21 formatnumbers.asp Format: Numbers #1
22 formatnumbers2.asp Format: Numbers #2
23 formatdates.asp Format: Dates #1
24 datetime.asp Date/Time on ASP Pages by Tony Arguelles
25 DoLoop.asp Loops: DO WHILE/UNTIL #1
26 DoLoop2.asp Loops: Timeouts #2
27 DoLoop3.asp Loops: Intercepting Timeouts #3
28 server.asp Server Variables: Popular Ones
29 server2.asp Server Variables: Domain/Host Name
30 serverall.asp Server Variables: Displaying All
31 randomadvice.asp Random Content/Rotating Info
32 bc.asp Browscap: Basics
33 bcdetails.asp Browscap: Intricate Details
34 aspbrowserheck.asp Listserver for Browser Problems
35
36 statemanagement.asp *State Management
37 stateintro.asp State Management Introduction
38 sessionswhat.asp What are ASP Sessions?
39 sessionsapps.asp Application Data
40 speedappdata.asp Application Data: Worlds Fastest ListBox
41 xmlfastlist.asp XML, Database Caches - Fast Retrieval
42 nodbsession.asp Say No To Databases w/Sessions or Application scope
43 sessionoverview.asp Session Overview & Myths
44 globalproblems.asp Sessions: Global.asa and Scalability
45 global.asp Sessions: Global.asa Events
46 statemore.asp Global.asa, Sessions, Custom Stats Resources
47 stateproscons.asp State Methods: Pros and Cons
48 hidden.asp Pass Data w/Hidden Fields
49 cookies.asp Pass Data w/Cookies
50 statesessions.asp Pass Data w/Session Vars
51 statedb.asp Pass Data w/ID tied to database
52 aspstatemanagement.asp [aspStateManagement] Listserver
53
54 Form.asp *Forms/Decisions
55 formintro.asp Forms: Introduction
56 formtextbox.asp Forms: Text Box
57 formtextarea.asp Forms: Text Area
58 formcheckbox.asp Forms: Check Box
59 formradio.asp Forms: Radio Buttons
60 formlistbox.asp Forms: List Box
61 case.asp Forms: CASE syntax #1
62 case2.asp Forms: CASE syntax #2
63 if.asp Forms: IF syntax #1
64 if2.asp Forms: IF syntax #2
65 if3.asp Forms: IF syntax #3
66 if4.asp Forms: IF syntax #4
67 formforeach.asp Forms: For Each Iteration
68 formsubmitself.asp Form - Submit To Self'
69 formactionchange.asp Form - Change Action on Fly
70
71
72 database.asp *Databases
73 dbsimple.asp Displaying Table w/Simple Code
74 dblist.asp List Box Displayed Generically
75 dblistmore.asp Database to ListBox Online Resources
76 dbopen.asp DSNLess Connections
77 dsn1.asp DSN Setup #1 by Rob Martinson
78 dsn2.asp DSN Setup #2 by Rob Martinson
79 dsn3.asp DSN Setup #3 by Rob Martinson
80 dsn4.asp DSN Setup #4 by Rob Martinson
81 dsn5.asp DSN Setup #5 by Rob Martinson
82 dsn6.asp DSN Setup #6 by Rob Martinson
83 dbfull1.asp Full Cycle #1 Show/Edit/Update
84 dbfull2.asp Full Cycle #2 Show/Edit/Update
85 dbfull3.asp Full Cycle #3 Show/Edit/Update
86 dbtroubleshoot2.asp SQL Mistakes Everyone Makes
87 dbtable.asp DB: Table Displayed Generically
88 dbtablegetstring.asp Getstring to display database table
89 dbtablegetrows.asp Getrows to display database table
90 dbtablegetrowsnonum.asp GetRows w/no Numbers
91 dbtabledisconnected.asp Disconnected Recordsets, Display Table
92 dbtablemore.asp DB: More ways To Display Tables
93 genericdb.asp DB: Generic DB by Eli Robillard
94 aspgenericdb.asp Generic DB Listserver
95 dbconvert.asp DB: Converting a DB to a Comma-Delimited file
96 dbSQLdelete.asp DB: Deleting a Record w/SQL
97 accesstest.asp DB: Access Scalability
98 dbtablepaged.asp ADO: Paging Records
99 dbmaxrecs.asp ADO: Limiting Number of Records
100 dbcount.asp ADO: Count Records in Query
101 adocursortypes.asp ADO: Cursor Types by Phil Paxton
102 dbnewrec.asp ADO: Input Form
103 dbnewSQL.asp ADO: Input Form, added w/SQL
104 dbnewADO.asp ADO: Input Form, Added w/ADO .addnew
105 dbtablelists.asp ADO: Tables within Databases
106 dbschemas.asp ADO: Schemas to access table lists
107 dbschemasall.asp ADO: Schemas to access All Data
108 db1parm.asp ADO: Show Table,1 param
109 dbupdate.asp ADO: Update/edit Record
110 dbtroubles.asp DB: Troubleshooting Part 1
111 dbtroubles2.asp DB: Troubleshooting Part 2
112
113 SQL.asp *SQL Basics, Searching Databases
114 SQLtroubles.asp SQL Troubles
115 SQLexamples.asp SQL: Example Tables
116 SQLwhere.asp SQL: Where Clause Basics
117 SQLwhere2.asp SQL: Where Clause Examples
118 SQLwhereform1.asp SQL: Search Forms #1
119 SQLwhereform2.asp SQL: Search Forms #2
120 SQLwhereform3.asp SQL: Search Forms #3
121 SQLandor.asp SQL: Search AND/OR Operators
122 SQLandor2.asp SQL: Search AND/OR Examples
123 SQLcount.asp SQL: COUNT, GROUPBY
124 SQLaggregate.asp SQL: SUM, MIN, AVE, MAX
125 dbjoin.asp SQL Joins by Aaron Alexander
126
127 rsfast.asp *RSFAST: Lightning Fast Database Library
128 rsfast-intro.asp RSFast Library Introduction
129 rsfast-table.asp Table Display Fast
130 rsfast-table-cached.asp Table Display Fast + Caching
131 rsfast-lists.asp Listbox Display Fast
132 rsfast-lists-cached.asp Listbox Display Fast + Caching
133 rsfast-templates.asp Templates for any look Fast
134 rsfast-lists-debug.asp Debug Info helps troubleshoot
135 rsfast-lib.asp Library Source Code
136 rsfast-cache.asp caching Method Explained
137 rsfast-newfeatures.asp New Features for Future Versions
138
139 editors.asp *Editors Used With ASP
140 aspexpress.asp ASPExpress: HOT ASP Editor
141 admunsen.asp Visual Interdev + Admunsen Resources
142 aspvisualinterdev.asp Visual Interdev Listserver
143 homesite.asp Homesite: HTML editor
144 dreamweaver.asp DreamWeaver: HTML and Script Editor
145
146 components.asp *Essential Commercial Components
147 aspdb1.asp ASPDB: Displaying Data
148 aspdb2.asp ASPDB: Editing, Adding Data
149 bhbrowtype.asp BrowserHawk: Determing Browser Type
150 bhaol.asp AOL detection w/BrowserHawk
151 bhwallet.asp MS-Wallet w/BrowserHawk
152 bhresolveip.asp Reverse DNS lookups w/BrowserHawk
153 bhframes.asp BrowserHawk - Frame support
154 bhflash.asp Flash Detection w/BrowserHawk
155 serverobjectsmail.asp ServerObject Mail: Simple Example
156 formsendmail.asp ServerObject: Mailing Form w/ASPMail
157 aspmail.asp 3rd Party Mail, CDO/CDONTS Listserver
158 uploadsimple.asp SA: File Upload, Simple Example
159 uploadmultipart.asp SA: File Upload, Multi-part form
160 uploadlimitsize.asp SA: File Upload, Limit Size
161 uploadmanyfiles.asp SA: File Upload, Many Files
162 aspsoftartisans.asp Upload/Soft-Artisans Listserver
163 perfcounters.asp Perf Counters on ASP page
164
165 authenticate.asp *Authentication & Security
166 authenticateoverview.asp Authenticate: Overview by Kevin Flick
167 authenticatecomparisons.asp Authenticate: Comparison by Kevin Flick
168 authenticatentcr.asp Authenticate: NT Challenge/Response by Kevin Flick
169 authenticatebasic.asp Authenticate: Basic Authentication by Kevin Flick
170 authenticatecookies.asp Authenticate: Cookies by Kevin Flick
171 authenticatecertificate.asp Authenticate: Certificates by Kevin Flick
172 authenticatebuild.asp Authenticate: Build Your Own by Kevin Flick
173 security.asp Authenticate: Protect Pages via Login #1
174 security2.asp Authenticate: Protect Pages via Login #2
175 authenticate3rdparty.asp Authenticate: 3rd Party by Kevin Flick
176 aspflicks.asp Authentix Flicks Support Listserver
177
178 troubles.asp *Troubleshooting, Error Trapping
179 errors1.asp Errors: Basics
180 errors2.asp Errors: More Ways To Trap
181 errormore.asp Errors: Resources Online
182 dbtablewitherrortrap.asp Errors: Trapping EVERY Error
183 debug1.asp Debug variables Easy Way
184 dbtroubleshoot.asp Errors: DB Error Information Trapping
185 FAQdbUpdate.asp DBFAQ: Operation must use Updatable Query
186 FAQdbSinglequote.asp DBFAQ: User Entered ' in field
187 FAQdbLIKE.asp DBFAQ: LIKE operator * not working
188 FAQdbMEMO.asp DBFAQ: retrieving MEMO/BLOBs generates error
189 FAQdbSQLSyntax.asp DBFAQ: Syntax Error in SQL Statement
190 debug2.asp SQL Debugging Made Easy
191 dbtroubleshootopen.asp Errors: Trapping Open Connections
192 asptroubles.asp Troubleshoot: Getting Help from Lists!
193 asptroubles2.asp Troubleshoot: Worldwide
194 asptroubles3.asp Troubleshoot: Specialized
195 versioncheck.asp Troubleshoot: Version of ASP Sofware
196 componentchecker.asp Troubleshoot: Registered Components
197 connectioninfo.asp Troubleshoot: DB Drivers by Christophe Wille
198 PWS.asp PWS: Personal Web Server Introduction
199
200 qualitycode.asp *Code w/all ASP Features. Quality, Re-usable Code
201 strings.asp Strings: Core Functions
202 stringsplit.asp Strings: SPLIT Function
203 stringreplace.asp Strings: REPLACE Function
204 stringjoin.asp Strings: JOIN Function
205 arrays.asp Arrays: Basics
206 arrays2.asp Arrays: Variable Size
207 arrays3.asp Arrays: Best Way To Load
208 arraysmore.asp Arrays: Resources Online
209 dictionary.asp Dictionary Objects
210 getrowsultimate.asp Getrows Ultimate!
211 subdates.asp Subroutine: Working with Dates #1
212 subdates2.asp Subroutine: Working with Dates #2
213 subdbtable.asp Subroutine: Query2Table
214 subdblist.asp Subroutine: Query2List
215 subreusable.asp Subroutine: Highly Reusable
216 subdictionary.asp Subroutines w/Dictionary Objects
217 getrowsultimate.asp Getrows Ultimate!
218 subDBlistbest.asp Subroutine: List Box w/optional params
219 libhtml.asp Subroutine: Abstract HTML by Phil Paxton
220 functionworkingdays.asp Function: Working Days
221 vbs5.asp New Features in VBScript version5
222 txtread.asp Text Files: Reading Them off Server
223 txtwrite.asp Text Files: Writing Them on Server
224 mb1.asp Text Files: Meyers-Briggs parsing #1
225 mb2.asp Text Files: Meyers-Briggs parsing #2
226 mb3.asp Text Files: Meyers-Briggs parsing #3
227 xmlmb.asp XML/XLST Myers-Briggs example
228 cl.asp Content Linker: Prev/Next Page
229 cl2.asp Content Linker: Table of Contents
230 cl3.asp Content Linker: Listbox of contents
231 contentlinker.asp Content Linker Library
232 fileobjects.asp File Objects: Read Directory
233 fileobjects2.asp File Objects: Display Directory as Links/Graphics
234 fileobjects3.asp File Objects: Read Disk Drive by Steven Harper
235 fileobjects4.asp File Objects: Show Dir List by Tim Foster
236 graphicdetect.asp Graphic Size Detector
237
238 speedscale.asp *High Speed Code, Scalable Code...
239 speedtimer.asp Time Tasks with Millisecond Accuracy
240 speedtips.asp Speed: Coding Tips
241 whybuffer.asp Why Buffer?
242 whygetrows.asp Why GetRows or Getstring to get Data
243 speedserver.asp Speed: Server Optimization
244 speedmore.asp Speed/Optimize Resources
245 speedresearch.asp Speed: [aspfastcode] listserver
246 speedtables.asp Speed: Database Percieved Speed
247 speedtablesall.asp Database Retrieval Speed
248 speedtablesdrivers.asp OLEDB & ODBC Drivers differences
249 isclientconnected.asp IsClientConnected & Stray Tasks
250 nothing.asp Scale: Virtues of Nothing
251 dbpooling.asp Scale: Connection Pooling
252 threads.asp Thread Basics: What is a Thread?
253 threadsafe.asp Thread Safety Issues
254 roundrobin.asp Round-Robin Code Execution
255 aspscalability.asp ASP Scalability Listserver
256
257 buildcomponents.asp *ASP Components Building
258 buildc.asp C++/ATL: Component Building
259 buildjava.asp Java ASP Components Building
260 buildvbsimple.asp VB: Simple Component
261 buildregister.asp VB: Registering Component
262 FAQvbDLLoverwrite.asp VB: DLL overwrite problems
263 buildvbado.asp VB: ADO, Run It!
264 buildvbado2.asp VB: ADO, Build It!
265 buildvbguidelines.asp VB: Warnings/Guidelines
266 buildvb.asp VB: General Building Guidelines
267 buildvb2.asp VB: Installation Requirements
268 buildvbthreads.asp VB: Threading Models
269
270 buildmtx.asp *MTS - Microsoft Transaction Server
271 buildmtxoverview.asp MTS: Overview
272 buildmtx2.asp MTS: Essentials
273 buildmtxasp.asp MTS: Transactional ASP pages
274 booksmtx.asp MTS: Book
275 booksmtx2.asp MTS: Book
276 buildmtxregister.asp MTS: Registering Components
277
278 advice.asp *Advice For Better Coding!
279 dbsessionapp.asp Database in Session or App. Say NO!
280 cachenomore.asp advice: Cache No More by Phil Paxton
281 explicit.asp advice:Option Explicit
282 encode.asp advice: Encode with Redirects
283 sqlwrite.asp advice: Write Your SQL
284 namedconstants.asp advice: Named constants for ADO are better
285 cleanup.asp advice: Clean Up Your Room, I mean Objects
286 pathmap.asp advice: Server.MapPath is Good
287 nosessionobjects.asp advice: Just Say No to Session COM objects
288 propertyexpense.asp advice: Don't Read COM Properties Twice
289 securecode.asp advice: Secure Code and Data
290 encapsulate.asp advice: Encaspulate Code!
291 caseisbetter.asp advice: CASE reads better than IF
292 errorstrategies.asp advice: Error Trapping Strategies
293 errorsecrets.asp advice: Error Trapping Secrets
294 shoulds.asp advice: You Should...
295
296
297 overview.asp *Appendix A: Overview of ASP Objects
298 aspobjects.asp ASP Objects: Built In
299 aspobjects2.asp ASP Objects: Created when Needed
300
301 webcom.asp *Appendix B: Related Web/Com Technologies
302 indexserver.asp Index Server via ADO
303 commerce.asp Commerce and ASP
304 javascript.asp Server JavaScript: Resources
305 validationmore.asp Validation Resources
306 listdynamic.asp Listboxes: Linked Dynamically w/JavaScript
307 listdynamicmore.asp Dynamic ListBox Online Examples
308 listdynamicdb.asp Listboxes: Linked Dynamically from Database w/JavaScript
309 listdual.asp Listboxes: Easy Choices by Bill Wilkinson
310 perlscript.asp Server Perlscript: Resources
311 remotescripting.asp Remote Scripting Simple Example
312 remotescriptinglist.asp Remote Scripting Listbox
313 remotescriptingms.asp Remote Scripting Microsoft Example
314 aspremotescripting.asp [aspRemoteScript] list
315 rds.asp RDS: Remote Data Services Intro
316 prothman.asp RDS Resources by Carl Prothman
317 ADSI.asp ADSI: Active Directory Services Interface Intro
318 MSMQ.asp MSMQ: Overview
319 usability.asp Usability: Resources
320 safecolors.asp Usability: Safe Color Pallete
321
322 oracle.asp *Appendix C: Oracle and ASP
323 FAQOracleconnect.asp Oracle: I can't connect
324 asporacle.asp Oracle: Getting Help from Listserver
325 FAQOraclestoredproc.asp Oracle: Calling Stored Procs
326 oracleoledbpooling.asp Oracle: OLEDB Resource(Session) Pooling
327 oraclerecordsetsfromsp.asp Oracle: Recordsets from Stored Procedures using REF CURSORs
328 oraclerecordsetsado.asp Oracle: Returning Recordsets via ADO
329 FAQOraclebooks.asp Oracle: Know any good books?
330
331 research.asp *Appendix D: ASP Books & Online Resources
332 bookcomponents.asp Must Buy Component Building Book
333 asp101.asp ASP101.com Scripts for your site
334 4guysfromrolla.asp 4GuysFromRolla.com Tons of ASP Material
335 asptoday.asp ASPToday.com from WROX
336
337 faqs.asp *Appendix E: Frequently Asked Questions
338 FAQCommerceCertif.asp Commerce: certificates, https://
339 FAQCommerceCharge.asp Commerce: online charging
340 FAQCommerceCarts.asp Commerce: components, shopping carts
341 FAQJscriptCleanUp.asp Jscript: closing DB Connections
342 FAQJscriptRefs.asp Jscript: online references
343 FAQJscriptDB.asp Jscript: display databases
344 FAQvbBooks.asp VB: Recommended books
345
346
347 alphaindex.asp *Alphabetical Index
348
349 comingsoon.asp *Coming Soon/Very Rough Drafts!
350 types.asp Data Types: VBScript
351 convert.asp Data Types: Conversion
352 ForNext.asp Loops: FOR NEXT #1
353 ForNext2.asp Loops: FOR NEXT #2
354 ad.asp Ad Rotator
355 cr.asp Content Rotator
356 command.asp DB: Command Object
357 commandquery.asp DB: Command Object/Queries
358 commandcreate.asp DB: Command Object/Create Tables
359 reportsimple.asp Reporting: Simple Example
360 reportpowerful.asp Reporting: Powerful Example
361 dictionaryadvanced.asp Dictionaries: Different Approach #1 By Paul Rigor
362 dictionaryadvanced2.asp Dictionaries: Different Approach #2 by Paul Rigor
363 validate.asp Validate data
364 webjam.asp 3rd Party: WebJam
365 asptime.asp Time Tasks: VB Component by Sunny Yu #1
366 asptimer.asp Time Tasks: VB Component by Sunny Yu #2
367 cookiesform.asp Cookies: Reading Them
368 cookiesformrespond.asp Cookies: Writing Them
369 cookiesforget.asp Cookies: Deleting Them
370 cookiesub.asp Cookies: Simplified by Paul Rigor
371
FileObjects by Charles Carroll
The file object is in newer versions of VBScript.
1 <html><head>
2 <title>fileobjects.asp</title>
3 </head><body>
4 <%
5 mypath="/learn/test"
6
7 Set filesystem = CreateObject("Scripting.FileSystemObject")
8 Set folder = filesystem.GetFolder(server.mappath(mypath))
9
10 Set filecollection = folder.Files
11 For Each file in filecollection
12 response.write file.name & "<br>"
13 Next
14
15 set filesystem=nothing
16 set folder=nothing
17 set filecollection=nothing
18 %>
19 </body></html>
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 <html><head>
2 <title>fileobjectslinks.asp</title>
3 </head><body>
4 <%
5 dirtowalk="/learn/test"
6 Set fs = CreateObject("Scripting.FileSystemObject")
7 Set f = fs.GetFolder(server.mappath(dirtowalk))
8 Set fc = f.Files
9 For Each whatever in fc
10 response.write "<A HREF='"
11 response.write whatever.name
12 response.write "'>"
13 response.write whatever.name
14 response.write "</A><br>"
15 Next
16 %>
17 </body></html>
Now we will display graphics in a directory.
1 <html><head>
2 <title>fileobjectsgraphics.asp</title>
3 </head><body>
4 <%
5 dirtowalk="/images"
6 Set fs = CreateObject("Scripting.FileSystemObject")
7 Set f = fs.GetFolder(server.mappath(dirtowalk))
8 Set fc = f.Files
9 For Each whatever in fc
10 response.write "<IMG SRC='/images/"
11 response.write whatever.name
12 response.write "'>"
13 response.write whatever.name & "<br>"
14 Next
15 %>
16 </body></html>
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 <html><head>
2 <title>fileobjectsinfo.asp</title>
3 </head><body>
4 <%
5 disktoexamine="C:"
6
7 set fs = Server.CreateObject("Scripting.FileSystemObject")
8 set f = fs.GetDrive(disktoexamine)
9
10 Response.Write(" Root Folder : ")
11 Response.Write(f.RootFolder)
12 Response.Write("<BR>")
13 Response.Write(" Type of Drive : ")
14 if f.DriveType=2 then
15 Response.Write("Fixed")
16 end if
17 if f.DriveType=1 then
18 Response.Write("Removable")
19 end if
20 Response.Write("<BR>")
21 Response.Write(" File System : ")
22 Response.Write(f.FileSystem)
23 Response.Write("<BR>")
24 Response.Write(" Total Size on Server's C: ")
25 Response.Write(f.TotalSize)
26 Response.Write("<BR>")
27 Response.Write(" Drive Space on Server's C: ")
28 Response.Write(f.freespace)
29 Response.Write("<BR>")
30 Response.Write(" Serial Number : ")
31 Response.Write(f.SerialNumber)
32
33 set f=nothing
34 set fs=nothing
35
36 %>
37 </body></html>
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 <html><head>
2 <title>fileobjectsplusdir.asp</title>
3 </head><body>
4 <%
5 additional = request.querystring("pathh")
6 folderspec = "/learn/"
7
8 if additional & "x" <> "x" then
9 additional = additional & "/"
10 folderspec = folderspec & additional
11 end if
12
13 Set fs = CreateObject("Scripting.FileSystemObject")
14 Set f = fs.GetFolder(server.mappath(folderspec))
15 Set fd = f.subfolders
16
17 response.write "<h2>FOLDERS</h2><blockquote>"
18 For Each whatever in fd
19 response.write "<A HREF='"
20 response.write request.servervariables("script_name")
21 response.write "?pathh=" & whatever.name
22 response.write "'>"
23 response.write whatever.name & " - " & whatever.datecreated
24 response.write "</A><br>"
25 Next
26
27 response.write "</blockquote><hr>"
28
29
30 response.write "<h2>FILES</h2><blockquote>"
31
32 Set fc = f.files
33
34 For Each whatever in fc
35 response.write "<A HREF='"
36 response.write folderspec & whatever.name
37 response.write "'>"
38 response.write whatever.name & " - " & whatever.datecreated
39 response.write "</A><br>"
40 Next
41
42 response.write "</blockquote><hr>"
43
44
45 %>
46 </body></html>
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 <!--#include virtual="/learn/test/lib_graphicdetect.asp"-->
2 <html><head>
3 <TITLE>dbtable.asp</TITLE>
4 </head>
5 <body bgcolor="#FFFFFF">
6 <%
7 graphic="images/learnaspiconmain.gif"
8 HW = ReadImg(graphic)
9 Response.Write graphic & " Dimensions: " & HW(0) & "x" & HW(1) & "<br>"
10 response.write "<img src=""/" & graphic & """"
11 response.write height=""" & HW(0) & """
12 response.write width=""" & HW(0) & "">"
13 %>
14 </body></html>
15
The library that is included is:
1 <%
2 Dim HW
3
4 Function AscAt(s, n)
5 AscAt = Asc(Mid(s, n, 1))
6 End Function
7
8 Function HexAt(s, n)
9 HexAt = Hex(AscAt(s, n))
10 End Function
11
12
13 Function isJPG(fichero)
14 If inStr(uCase(fichero), ".JPG") <> 0 Then
15 isJPG = true
16 Else
17 isJPG = false
18 End If
19 End Function
20
21
22 Function isPNG(fichero)
23 If inStr(uCase(fichero), ".PNG") <> 0 Then
24 isPNG = true
25 Else
26 isPNG = false
27 End If
28 End Function
29
30
31 Function isGIF(fichero)
32 If inStr(uCase(fichero), ".GIF") <> 0 Then
33 isGIF = true
34 Else
35 isGIF = false
36 End If
37 End Function
38
39
40 Function isBMP(fichero)
41 If inStr(uCase(fichero), ".BMP") <> 0 Then
42 isBMP = true
43 Else
44 isBMP = false
45 End If
46 End Function
47
48
49 Function isWMF(fichero)
50 If inStr(uCase(fichero), ".WMF") <> 0 Then
51 isWMF = true
52 Else
53 isWMF = false
54 End If
55 End Function
56
57
58 Function isWebImg(f)
59 If isGIF(f) Or isJPG(f) Or isPNG(f) Or isBMP(f) Or isWMF(f) Then
60 isWebImg = true
61 Else
62 isWebImg = true
63 End If
64 End Function
65
66
67 Function ReadImg(fichero)
68 If isGIF(fichero) Then
69 ReadImg = ReadGIF(fichero)
70 Else
71 If isJPG(fichero) Then
72 ReadImg = ReadJPG(fichero)
73 Else
74 If isPNG(fichero) Then
75 ReadImg = ReadPNG(fichero)
76 Else
77 If isBMP(fichero) Then
78 ReadImg = ReadPNG(fichero)
79 Else
80 If isWMF(fichero) Then
81 ReadImg = ReadWMF(fichero)
82 Else
83 ReadImg = Array(0,0)
84 End If
85 End If
86 End If
87 End If
88 End If
89 End Function
90
91
92 Function ReadJPG(fichero)
93 Dim fso, ts, s, HW, nbytes
94 HW = Array("","")
95 Set fso = CreateObject("Scripting.FileSystemObject")
96 Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1)
97 s = Right(ts.Read(167), 4)
98 HW(0) = HexToDec(HexAt(s,3) & HexAt(s,4))
99 HW(1) = HexToDec(HexAt(s,1) & HexAt(s,2))
100 ts.Close
101 ReadJPG = HW
102 End Function
103
104
105 Function ReadPNG(fichero)
106 Dim fso, ts, s, HW, nbytes
107 HW = Array("","")
108 Set fso = CreateObject("Scripting.FileSystemObject")
109 Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1)
110 s = Right(ts.Read(24), 8)
111 HW(0) = HexToDec(HexAt(s,3) & HexAt(s,4))
112 HW(1) = HexToDec(HexAt(s,7) & HexAt(s,8))
113 ts.Close
114 ReadPNG = HW
115 End Function
116
117
118 Function ReadGIF(fichero)
119 Dim fso, ts, s, HW, nbytes
120 HW = Array("","")
121 Set fso = CreateObject("Scripting.FileSystemObject")
122 Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1)
123 s = Right(ts.Read(10), 4)
124 HW(0) = HexToDec(HexAt(s,2) & HexAt(s,1))
125 HW(1) = HexToDec(HexAt(s,4) & HexAt(s,3))
126 ts.Close
127 ReadGIF = HW
128 End Function
129
130
131 Function ReadWMF(fichero)
132 Dim fso, ts, s, HW, nbytes
133 HW = Array("","")
134 Set fso = CreateObject("Scripting.FileSystemObject")
135 Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1)
136 s = Right(ts.Read(14), 4)
137 HW(0) = HexToDec(HexAt(s,2) & HexAt(s,1))
138 HW(1) = HexToDec(HexAt(s,4) & HexAt(s,3))
139 ts.Close
140 ReadWMF = HW
141 End Function
142
143
144 Function ReadBMP(fichero)
145 Dim fso, ts, s, HW, nbytes
146 HW = Array("","")
147 Set fso = CreateObject("Scripting.FileSystemObject")
148 Set ts = fso.OpenTextFile(Server.MapPath("/" & fichero), 1)
149 s = Right(ts.Read(24), 8)
150 HW(0) = HexToDec(HexAt(s,4) & HexAt(s,3))
151 HW(1) = HexToDec(HexAt(s,8) & HexAt(s,7))
152 ts.Close
153 ReadBMP = HW
154 End Function
155
156
157 Function isDigit(c)
158 If inStr("0123456789", c) <> 0 Then
159 isDigit = true
160 Else
161 isDigit = false
162 End If
163 End Function
164
165
166 Function isHex(c)
167 If inStr("0123456789ABCDEFabcdef", c) <> 0 Then
168 isHex = true
169 Else
170 ishex = false
171 End If
172 End Function
173
174
175 Function HexToDec(cadhex)
176 Dim n, i, ch, decimal
177 decimal = 0
178 n = Len(cadhex)
179 For i=1 To n
180 ch = Mid(cadhex, i, 1)
181 If isHex(ch) Then
182 decimal = decimal * 16
183 If isDigit(c) Then
184 decimal = decimal + ch
185 Else
186 decimal = decimal + Asc(uCase(ch)) - Asc("A")
187 End If
188 Else
189 HexToDec = -1
190 End If
191 Next
192 HexToDec = decimal
193 End Function
194 %>
195
High Speed Code, Scalable Code...
Time Tasks with Millisecond Accuracy (speedtimer.asp) - Page 225
Speed: Coding Tips (speedtips.asp) - Page 226
Why Buffer? (whybuffer.asp) - Page 227
Why GetRows or Getstring to get Data (whygetrows.asp) - Page 228
Speed: Server Optimization (speedserver.asp) - Page 229
Speed/Optimize Resources (speedmore.asp) - Page 230
Speed: [aspfastcode] listserver (speedresearch.asp) - Page 231
Speed: Database Percieved Speed (speedtables.asp) - Page 232
Database Retrieval Speed (speedtablesall.asp) - Page 233
OLEDB & ODBC Drivers differences (speedtablesdrivers.asp) - Page 234
IsClientConnected & Stray Tasks (isclientconnected.asp) - Page 235
Scale: Virtues of Nothing (nothing.asp) - Page 236
Scale: Connection Pooling (dbpooling.asp) - Page 237
Thread Basics: What is a Thread? (threads.asp) - Page 238
Thread Safety Issues (threadsafe.asp) - Page 239
Round-Robin Code Execution (roundrobin.asp) - Page 240
ASP Scalability Listserver (aspscalability.asp) - Page 241
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:
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 <html><head>
2 <TITLE>timedbtable.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <!--#include file="lib_timethis.asp"-->
6 <%
7 Set HttpObj = Server.CreateObject("AspHTTP.Conn")
8 HttpObj.Url = "http://www.learnasp.com/learn/test/dbtable.asp"
9 timeThen = milliDif()
10 strResult = HttpObj.GetURL
11 timeNow = milliDif()
12 SET HTTPobj = nothing
13 elapsed=timeNow-timeThen
14 msg="<br>Process time in ms: " & elapsed & "<br>" & elapsedpretty(elapsed)
15 bodytag="<body bgcolor=""#FFFFFF"">"
16 STRresult=replace(STRResult,bodytag,bodytag & msg)
17
18 response.write STRresult
19
20 %>
21 </body></html>
Here we retrieve data by fetching all the data into an array in one "gulp" (/learn/dbtablegetrows.asp):
1 <html><head>
2 <TITLE>timedbtablegetrows.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <!--#include file="lib_timethis.asp"-->
6 <%
7 Set HttpObj = Server.CreateObject("AspHTTP.Conn")
8 HttpObj.Url = "http://www.learnasp.com/learn/test/dbtablegetrows.asp"
9 timeThen = milliDif()
10 strResult = HttpObj.GetURL
11 timeNow = milliDif()
12 SET HTTPobj = nothing
13 elapsed=timeNow-timeThen
14 msg="<br>Process time in ms: " & elapsed & "<br>" & elapsedpretty(elapsed)
15 bodytag="<body bgcolor=""#FFFFFF"">"
16 STRresult=replace(STRResult,bodytag,bodytag & msg)
17
18 response.write STRresult
19
20 %>
21 </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 <html><head>
2 <TITLE>timedbtablegetstring.asp</TITLE>
3 </head>
4 <body bgcolor="#FFFFFF">
5 <!--#include file="lib_timethis.asp"-->
6 <%
7 Set HttpObj = Server.CreateObject("AspHTTP.Conn")
8 HttpObj.Url = "http://www.learnasp.com/learn/test/dbtablegetstring.asp"
9 timeThen = milliDif()
10 strResult = HttpObj.GetURL
11 timeNow = milliDif()
12 SET HTTPobj = nothing
13 elapsed=timeNow-timeThen
14 msg="<br>Process time in ms: " & elapsed & "<br>" & elapsedpretty(elapsed)
15 bodytag="<body bgcolor=""#FFFFFF"">"
16 STRresult=replace(STRResult,bodytag,bodytag & msg)
17
18 response.write STRresult
19
20 %>
21 </body></html>
The library that accomplishes this:
1 <SCRIPT LANGUAGE=JScript RUNAT=Server>
2 function y2k(number) {
3 return (number < 1000) ? number + 1900 : number;
4 }
5 function milliDif() {
6 var d = new Date();
7 return d.getTime()
8 }
9
10 function elapsedpretty(parm1)
11 {
12 var elapsedsecs = 0
13 var elapsedmins = 0
14
15 elapsedsecs=Math.floor(parm1/1000)
16 parm1=parm1%1000
17
18 elapsedmins=Math.floor(elapsedsecs/60)
19 elapsedsecs=elapsedsecs%60
20
21
22 elapsedpretty=elapsedmins + " minute"
23 if(elapsedmins!=1)
24 elapsedpretty=elapsedpretty+"s"
25
26 elapsedpretty = elapsedpretty+" " + elapsedsecs+" second"
27 if(elapsedsecs!=1)
28 elapsedpretty=elapsedpretty+"s"
29
30 elapsedpretty = elapsedpretty+ " "+parm1+" millisecond"
31 if(parm1!=1)
32 elapsedpretty=elapsedpretty+"s"
33
34 return elapsedpretty;
35 }
36 </script>
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
#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:
#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.
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 trick got
it down to 3/10 of a second!!!! Why?????
Lets tell the waiter analogy....
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.
Chaos, not Order
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:
A Simple Change to Speed Up Your Server
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.
When Good Pets Go Bad, err I mean...
When response.flush goes bad
Two of my students would like to add to this advice.
Rob Reno from Florida found too many response.flushes slows down his page and has diminishing returns. Code like this
<%response.buffer=true%>
... 1k of HTML and/or ASP ...
<%do until rstemp.eof
... process data ...
rstemp.movenext
response.flush
LOOP
will show output often BUT if there is 1000 records that is 1000 response.flushes.
Change the above code to:
<%response.buffer=true%>
... 1k of HTML and/or ASP ...
<%do until rstemp.eof
counter=counter+1
... process data ...
rstemp.movenext
If counter MOD 200=0 THEN
response.flush
END IF
LOOP
will now flush at record 200, 400,600,800,1000 -- 5 flushes total.
Doug Cannon from Utah writes....
The one thing that you may not have tested for this article is how response.flush behaves on a very slow internet connection (28.8 bps, for example). Our audience on www.myfamily.com still uses a lot of 28.8 and 33.6 modems to attach to our site. We were noticing some VERY slow speeds on many of our pages. We religiously used RESPONSE.BUFFER = TRUE on every page, and two RESPONSE.FLUSH commands per page. We found out, and Microsoft finally admitted, that the response.flush waits for the client browser to acknowledge the flush before continuing to process the ASP code. One a very fast internet connection, you don't notice the problem, but a slower modem takes longer to perform that task, and therefore a flush can be bad. We still use response.buffer=true, of course. However, we have removed all response.flush commands from the site, and we saw an instant and dramatic speed improvement.
My comment: I have used several response.flushes on 28.8 connections with success and speed BUT my servers weren't as busy as www.myfamily.com . Due to the round-robin nature of script execution (see /advice/roundrobin.asp) their servers may take longer for a response.flush than lightly loaded servers!
GetRows! ... Don't retrieve data any other way!

Why LOOP and Movenext? They just slow things down...
Most people write database retrieval code like his:
<%
' Open Database
Do UNTIL rs.eof
city=rs("city")
st=rs("state")
zip=rs("zip")
rs.movenext
... process and format data ....
LOOP
' Close database
%>
An example of such code is at:
http://www.learnasp.com/learn/dbtable.asp
and
http://www.learnasp.com/learn/dbsimple.asp
If there are 700 records and 3 columns for example, we have 3,500 database read requests over the wire.
+2,100 ... Each field read is a request
+700 ..... Each .movenext is +1 request
+700 ..... Each .eof test is +1 request
====
3,500 requests
Lots of round-trips. Actually I am fudging a little here.... the recordset object actually will maintain buffers in chunk sizes defined by rstemp.cachesize -- setting it will determine how many rows of data it buffers when 1 record is requested. A cachesize for example of 50 would reduce the previous examples trips to the backend database to 14 since when you asked for the first record you got 50. Until the MOVENEXT triggers record 51-101 being retrieved. But those buffers, and their attendant structures ain't free either.
How about 1 transfer instead
of 3500?
A better alternative code approach is GetRows!
dim myarray
myarray=rstemp.GetRows
One transfer for seven-hundred records x 3 fields for example. We can even close Recordset and Connection BEFORE formatting or calculating and massaging our data.
Imagine the backend gets to make 1 transfer into a 2,100 element array and hand the array back
Very efficient.
Here is a real world sample:
1 <%@enablesessionstate=false%>
2 <%response.buffer=true%>
3 <html><head>
4 <TITLE>dbtablegetrows.asp</TITLE>
5 </head>
6 <body bgcolor="#FFFFFF">
7 <%
8 ' displays a database in table form via GetRows
9 myDSN="DSN=Student;uid=student;pwd=magic"
10 mySQL="select * from publishers where state='NY'"
11 showblank=" "
12 shownull="-null-"
13
14 set conntemp=server.createobject("adodb.connection")
15 conntemp.open myDSN
16 set rstemp=conntemp.execute(mySQL)
17 If rstemp.eof then
18 response.write "No records matched<br>"
19 response.write mySQL & "<br>So cannot make table..."
20 Call CloseAll
21 response.end
22 end if
23
24 response.write "<table border='1'><tr>" & vbcrlf
25 'Put Headings On The Table of Field Names
26 for each whatever in rstemp.fields
27 response.write "<td><b>" & whatever.name & "</B></TD>" & vbcrlf
28 next
29 response.write "</tr>" & vbcrlf
30
31 ' Now lets grab all the records
32 alldata=rstemp.getrows
33 Call CloseAll
34
35 numcols=ubound(alldata,1)
36 numrows=ubound(alldata,2)
37 FOR rowcounter= 0 TO numrows
38 response.write "<tr>" & vbcrlf
39 FOR colcounter=0 to numcols
40 thisfield=alldata(colcounter,rowcounter)
41 if isnull(thisfield) then
42 thisfield=shownull
43 end if
44 if trim(thisfield)="" then
45 thisfield=showblank
46 end if
47 response.write "<td valign=top>"
48 response.write thisfield
49 response.write "</td>" & vbcrlf
50 NEXT
51 response.write "</tr>" & vbcrlf
52 NEXT
53 response.write "</table>"
54 %>
55 </body></html>
56 <%
57 SUB CloseAll
58 rstemp.close
59 set rstemp=nothing
60 conntemp.close
61 set conntemp=nothing
62 END SUB
63 %>
64
Read:
http://www.learnasp.com/advice/roundrobin.asp
to get the full sense for the importance of closing resources early.
Get Some Real Code to Use!
If your data formatting is simple:
http://www.learnasp.com/learn/dbtablegetstring.asp
can accomplish even faster results.
Old Habits Die Hard... Do you want to be an old dog that won't learn new tricks?
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.
Kyle Dyer writes us... "What about Jscript?"
And he is kind enough to supply us with the results of his research:
strSQL = "SELECT times FROM ...";
recordSet.Open(strSQL, conn);
recordSet.GetString(2,-1,"column-delim","row-delim","null");
parameters:
1: string format: has to be 2 (must be there in JavaScript)
2: number rows: -1 gets you all of them (must be there in JavaScript)
3: column delim
4: row delim
5: nullExper
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.
Is there any faster way to retrieve data?
"The Worlds Fastest Listbox"
http://www.learnasp.com/learn/speedappdata.asp
shows the only faster way to display databases.
Aren't numbered arrays harder for people to read?
Sure so I have prepared an example where we number the fields with variables and make the code easier to read for people. see: http://www.learnasp.com/learn/dbtablegetrowsnonum.asp
A Better MouseTrap:
A Library I call Ultimate Getrows
Finally I hunkered down and encapsulated the speed of getrows and the elegance of named field and
flexible formatting ala:
http://www.learnasp.com/learn/getrowsultimate.asp
I would argue that it is the best code samples at our entire site.
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.comImproving the Performance of Data Access Components with IIS 4.0
http://msdn.microsoft.com/workshop/server/components/daciisperf.aspMike Moore's Tuning IIS
http://www.microsoft.com/isn/whitepapers/tuningiis.aspIIS4 Tuning Parameters for High Volume Sites
http://msdn.microsoft.com/workshop/server/feature/tune.aspHans Hugli's Seminar:
Managing Microsoft Internet Information Server 4.0 for Performance @
http://www.microsoft.com/Seminar/1033/199811131-01MaxIISPerfor(HH/Portal.htmBackstage at Microsoft.com
http://www.microsoft.com/backstage/whitepaper.htmIIS Research starts @
http://www.microsoft.com/technet/iis/default.htmMuch ASP coding tips and advice related to scalability can be found at:
http://www.learnasp.com/advice
Speed and Optimization Resources
I can't say that I agree with all the conclusions and focus of the following articles as there is a lot of micro-management and some big-picture optimization techniques are missed. But the research is often very good if applied within context.
Top WinDNA Performance Mistakes and How to Avoid
Making Them @
http://msdn.microsoft.com/msdn-online/start/features/windnamistakes.asp
Enhancing Performance in ASP - Part I By Wayne Plourde
@
http://www.asptoday.com/articles/20000113.htm
Enhancing Performance in ASP - Part I By Wayne Plourde
http://www.asptoday.com/articles/20000113.htm
Tips to Improve ASP Application Performance By Srinivasa Sivakumar
http://www.15seconds.com/issue/000106.htm
Speed Is The Essence By Mo Morgan Part 1
http://www.4guysfromrolla.com/webtech/010300-1.shtml
Speed Is The Essence By Mo Morgan Part 2
http://www.4guysfromrolla.com/webtech/010300-1.2.shtml
Optimizing ADO Calls Using the Set Statement By Mike Shaffer
http://www.4guysfromrolla.com/webtech/120899-1.shtml
Optimizing ADO Calls By Mike Shaffer
http://www.4guysfromrolla.com/webtech/120299-1.shtml
Cursor & LockType Performance Issues
http://www.4guysfromrolla.com/webtech/062799-3.shtml
Cursor & LockType Performance Report
http://www.4guysfromrolla.com/webtech/062799-3.report.shtml
Are Script Engines Compilers or Not by Juan LLibre @
http://x32.deja.com/getdoc.xp?AN=557994116&CONTEXT=947880637.319225894&hitnum=16
Benchmarking Different Approaches to Updating a Database By Geoffrey Pennington
http://www.asptoday.com/articles/19990610.htm
Improving MDAC Application Performance @
http://msdn.microsoft.com/library/psdk/dasdk/impr8l2m.htm
Tuning Your Web Server's .ASP Queue and Thread Pool
http://www.15seconds.com/howto/pg003223.htm
Server Performance and Scalability Killers by George V. Reilly
http://msdn.microsoft.com/workshop/server/iis/tencom.asp
15 ASP Tips to Improve Performance and Style
http://msdn.microsoft.com/workshop/server/asp/ASPtips.asp
Listboxes. Its all about performance @
http://niblack.com/kbase/listbox_x.asp
Caching Data by Ian Stallings
http://www.4guysfromrolla.com/webtech/052099-1.shtml
Got Any Cache?
http://msdn.microsoft.com/workshop/server/feature/cache.asp
.Filter property vs. SQL Query Performance
http://msdn.microsoft.com/isapi/msdnlib.idc?theURL=/library/psdk/dasdk/mdae2dmg.htm
http://www.microsoft.com/Data/ado/ADOTechInfo/dao2ado_3.htm
Increasing Speed of Your ASP Scripts
http://www.4guysfromrolla.com/webtech/121398-1.shtml
Optimizing Your ASP Scripts
http://www.4guysfromrolla.com/webtech/110898-1.shtml
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.
Undergoing renovation - SUB ListServSignup
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:
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 <%response.buffer=true%>
2 <HEAD><TITLE>dbtablefast.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <%
5 myDSN = "DSN=student;UID=student;pwd=magic"
6
7 mySQL="select * from authors order by author"
8 call query2table(mySQL,myDSN)
9 %>
10 <!--#include virtual="/learn/test/lib_dbtablefast.asp"-->
11 </BODY></HTML>
12
13
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 thisvalue=rstemp(i)
22 If isnull(thisvalue) then
23 thisvalue=" "
24 end if
25 response.write "<td valign=top>" & thisvalue & "</td>" & vbcrlf
26 next
27 response.write "</tr>"
28 rstemp.movenext
29 IF counter mod 50=0 THEN
30 If response.isclientconnected()=false THEN
31 EXIT DO
32 END IF
33 response.write "</table>" & TableStart
34 response.flush
35 END IF
36
37 loop%>
38 </table>
39 <%
40 rstemp.close
41 set rstemp=nothing
42 conntemp.close
43 set conntemp=nothing
44 end sub%>
45
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 <HEAD><TITLE>dbtableslow.asp</TITLE></HEAD>
2 <HTML><body bgcolor="#FFFFFF">
3 <%
4 myDSN = "DSN=student;uid=student;pwd=magic"
5
6 mySQL= "SELECT * from authors order by Author"
7 call query2table(mySQL,myDSN)
8 %>
9 <!--#include virtual="/learn/test/lib_dbtableslow.asp"-->
10 </BODY></HTML>
Here is the original slow library lib_dbtableslow.asp :
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 UNTIL rstemp.eof and response.isclientconnected()%>
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%>
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 <%response.buffer=true%>
2 <HEAD><TITLE>dbtableLoopAll.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_LoopAll
9
10 myDSN = "DSN=student;UID=student;pwd=magic"
11 'mySQL="select * from authors order by author "
12 mySQL="select * from authors order by author "
13
14 Call TimerStart
15 call query2table(mySQL,myDSN,optimize,howmany)
16 Call TimerEnd
17 %>
18 </BODY></HTML>
Here is a table display with a simple LOOP assembling a string:
1 <%response.buffer=true%>
2 <HEAD><TITLE>dbtableLoopAllstring.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_LoopAll_string
9
10 myDSN = "DSN=student;UID=student;pwd=magic"
11 mySQL="select * from authors order by author "
12
13 Call TimerStart
14 call query2table(mySQL,myDSN,optimize,howmany)
15 Call TimerEnd
16 %>
17 </BODY></HTML>
18
Here is a table display with a GetString call and no LOOP:
1 <%response.buffer=true%>
2 <HEAD><TITLE>dbtablegetstringall.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_GetStringAll
9 myDSN = "DSN=student;UID=student;pwd=magic"
10 mySQL="select * from authors order by author"
11
12 Call TimerStart
13 call query2table(mySQL,myDSN,optimize,howmany)
14 response.write OptimizationName(optimize) & "<br>"
15 Call TimerEnd
16 %>
17 </BODY></HTML>
Here is a table display with a GetString call (buffered):
1 <%response.buffer=true%>
2 <HEAD><TITLE>dbtablegetstringbuffered.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_GetStringBuffered
9 myDSN = "DSN=student;UID=student;pwd=magic"
10 mySQL="select * from authors order by author"
11
12 Call TimerStart
13 call query2table(mySQL,myDSN,optimize,howmany)
14 response.write OptimizationName(optimize) & "<br>"
15 Call TimerEnd
16 %>
17 </BODY></HTML>
Here is a table display with a GetRows call and no LOOP:
1 <%response.buffer=true%>
2 <HEAD><TITLE>dbtablegetrowsall.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_getrowsall
9 response.write OptimizationName(optimize) & "<p>"
10
11 myDSN = "DSN=student;UID=student;pwd=magic"
12 mySQL="select * from authors order by author "
13
14
15 call TimerStart
16 call query2table(mySQL,myDSN,optimize,howmany)
17 call TimerEnd
18
19 %>
20 </BODY></HTML>
Here is a table display with a GetRows (buffered):
1 <%response.buffer=true%>
2 <HEAD><TITLE>dbtableGetRowsBuffered.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_GetRowsBuffered
9
10 myDSN = "DSN=student;UID=student;pwd=magic"
11 'mySQL="select * from authors order by author "
12 mySQL="select * from authors order by author "
13
14 Call TimerStart
15 call query2table(mySQL,myDSN,optimize,howmany)
16 Call TimerEnd
17 %>
18 </BODY></HTML>
Here is a table display of a portion of the records:
1 <%response.buffer=true%>
2 <HEAD><TITLE>dbtablelimitrows.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_LimitRows
9 myDSN = "DSN=student;UID=student;pwd=magic"
10 mySQL="select * from authors order by author"
11
12 Call TimerStart
13 call query2table(mySQL,myDSN,optimize,howmany)
14 response.write OptimizationName(optimize) & "<br>"
15 Call TimerEnd
16 %>
17 </BODY></HTML>
Here is the optimized library lib_dbtablefastv2.asp which achieves this speed:
1 <%
2 Const optimize_LoopAll = 1
3 Const optimize_GetstringAll = 2
4 Const optimize_GetrowsAll = 3
5 Const optimize_GetrowsBuffered = 4
6 Const optimize_GetStringBuffered = 5
7 Const optimize_LimitRows = 6
8 Const optimize_LoopAll_String = 7
9
10 dim optimize_buffersize
11 dim optimize_started
12 dim optimize_ended
13 dim optimize_SQL
14 dim optimize_DSN
15 dim optimize_howmany
16 dim optimize_cursorlocation
17 dim optimize_maxrecs
18 dim optimize_disconnectRS
19
20 optimize_started=0
21
22 ' performance stuff
23 optimize_buffersize=200
24 'optimize_cursorlocation=aduseclient
25 optimize_maxrecs=500
26 optimize_cursorlocation=aduseserver
27 optimize_disconnectRS=false
28 optimize_stringwrite=false
29
30 SUB TimerStart()
31 optimize_started=now()
32 END SUB
33
34 SUB TimerEnd()
35 optimize_ended=now()
36 elapsed=DateDiff("s", optimize_started, optimize_ended)
37 response.write "SQL=<b>" & optimize_SQL & "</b><br>"
38 response.write "DSN=<b>" & optimize_DSN & "</b><br>"
39 response.write "Query took <b>" & elapsed & " seconds.</b><br>"
40 IF optimize_howmany=-1 THEN
41 optimize_howmany=querycount(optimize_DSN,optimize_SQL)
42 END IF
43 response.write "Query processed <b>" & optimize_howmany & " records.</b><br>"
44 response.write "Speed =<b>" & optimize_howmany/elapsed & " records per second.</b><br>"
45 response.write "Notes:<br>"
46 pad=" "
47 response.write pad & "buffersize=<b>" & optimize_buffersize & "</b><br>"
48 IF optimize_cursorlocation=adUseClient THEN
49 response.write pad & "cursorlocation=<b>adUseClient</b><br>"
50 END IF
51 IF optimize_cursorlocation=adUseServer THEN
52 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 END FUNCTION
381 %>
382
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 <%response.buffer=true%>
2 <HEAD><TITLE>dbtableSQLoledb.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8 optimize=optimize_LoopAll
9 mySQL="select * from authors where au_id<2000 order by author "
10
11 myDSN="PROVIDER=SQLOLEDB;DATA SOURCE=sql2.datareturn.com;"
12 myDSN=myDSN & "USER ID=student;PASSWORD=magic;"
13
14 Call TimerStart
15 call query2table(mySQL,myDSN,optimize,howmany)
16 Call TimerEnd
17
18 %>
19 </BODY></HTML>
Here is a table display against a SQL server with a ODBC driver:
1 <%response.buffer=true%>
2 <HEAD><TITLE>dbtableSQLODBC.asp</TITLE></HEAD>
3 <HTML><body bgcolor="#FFFFFF">
4 <!--#include virtual="/adovbs.inc"-->
5 <!--#include virtual="/learn/test/lib_dbtablefastv2.asp"-->
6 <%
7 server.scripttimeout=240
8
9 mySQL="select * from authors where au_id<2000 order by author "
10 optimize=optimize_LoopAll
11 myDSN="PROVIDER=MSDASQL;DRIVER={SQL Server};"
12 myDSN=myDSN & "SERVER=sql2.datareturn.com;UID=student;PWD=magic;"
13
14 Call TimerStart
15 call query2table(mySQL,myDSN,optimize,howmany)
16 Call TimerEnd
17 %>
18 </BODY></HTML>
Here is the optimized library lib_dbtablefastv2.asp which achieves this speed:
1 <%
2 Const optimize_LoopAll = 1
3 Const optimize_GetstringAll = 2
4 Const optimize_GetrowsAll = 3
5 Const optimize_GetrowsBuffered = 4
6 Const optimize_GetStringBuffered = 5
7 Const optimize_LimitRows = 6
8 Const optimize_LoopAll_String = 7
9
10 dim optimize_buffersize
11 dim optimize_started
12 dim optimize_ended
13 dim optimize_SQL
14 dim optimize_DSN
15 dim optimize_howmany
16 dim optimize_cursorlocation
17 dim optimize_maxrecs
18 dim optimize_disconnectRS
19
20 optimize_started=0
21
22 ' performance stuff
23 optimize_buffersize=200
24 'optimize_cursorlocation=aduseclient
25 optimize_maxrecs=500
26 optimize_cursorlocation=aduseserver
27 optimize_disconnectRS=false
28 optimize_stringwrite=false
29
30 SUB TimerStart()
31 optimize_started=now()
32 END SUB
33
34 SUB TimerEnd()
35 optimize_ended=now()
36 elapsed=DateDiff("s", optimize_started, optimize_ended)
37 response.write "SQL=<b>" & optimize_SQL & "</b><br>"
38 response.write "DSN=<b>" & optimize_DSN & "</b><br>"
39 response.write "Query took <b>" & elapsed & " seconds.</b><br>"
40 IF optimize_howmany=-1 THEN
41 optimize_howmany=querycount(optimize_DSN,optimize_SQL)
42 END IF
43 response.write "Query processed <b>" & optimize_howmany & " records.</b><br>"
44 response.write "Speed =<b>" & optimize_howmany/elapsed & " records per second.</b><br>"
45 response.write "Notes:<br>"
46 pad=" "
47 response.write pad & "buffersize=<b>" & optimize_buffersize & "</b><br>"
48 IF optimize_cursorlocation=adUseClient THEN
49 response.write pad & "cursorlocation=<b>adUseClient</b><br>"
50 END IF
51 IF optimize_cursorlocation=adUseServer THEN
52 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 END FUNCTION
381 %>
382
IsClientConnected -- eliminating stray tasks by Charles Carroll
Unbeknownst to most users if their script begins execution it continues invisibly in the background even if the user hits the stop button or moves to a different page on your site or the web. A database 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.
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.
Here is some code that will loop until the script times out. If the user hits stop, then the script will still continue invisibly even if they are executing a different page.
1 <%server.scripttimeout=20
2 ' this times out the script in 20 seconds whether done or not%>
3 <TITLE>infiniteloop.asp</TITLE>
4 <body bgcolor="#FFFFFF">
5 <%
6 DO
7 x=x+1
8 response.write x & "<br>"
9 LOOP
10 %>
11 </body></html>
12
Here is the fixed code that will loop until the script times out AND WILL STOP IF THE USER HITS "STOP" OR ACCESSES A DIFFERENT PAGE. Notice the mod test to ensure the echeck is only made when x is a multiple of 1000 (1000, 2000, 3000, 4000, etc.) to reduce how many times the client connection is checked.
1 <%server.scripttimeout=20
2 ' this times out the script in 20 seconds whether done or
3 ' the user hit the STOP button
4 %>
5 <TITLE>infiniteloopfixed.asp</TITLE>
6 <body bgcolor="#FFFFFF">
7 <%
8 DO
9 x=x+1
10 response.write x & "<br>"
11 IF x MOD 1000=0 AND response.isclientconnected=false THEN
12 EXIT DO
13 END IF
14 LOOP
15 %>
16 </body></html>
17
this code above 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 script that incorporates this functionality and quits reading the database when the user hits stop button or accesses a different page:
1 <%response.buffer=true%>
2 <TITLE>dbtableisclientconnected.asp</TITLE>
3 <body bgcolor="#FFFFFF">
4 <%
5 ' ASP program that displays a database in table form
6 myDSN="DSN=Student;uid=student;pwd=magic"
7 mySQL="select * from publishers"
8
9 set conntemp=server.createobject("adodb.connection")
10 conntemp.open myDSN
11 set rstemp=conntemp.execute(mySQL)
12 howmanyfields=rstemp.fields.count -1
13 %>
14 <table border=1><tr>
15 <% 'Put Headings On The Table of Field Names
16 for i=0 to howmanyfields %>
17 <td><b><%=rstemp(i).name %></B></TD>
18 <% next %>
19 </tr>
20 <% ' Now lets grab all the records
21 howoften=200 ' how many records to check client connection
22 DO UNTIL rstemp.eof
23 counter=counter+1
24 response.write "<tr>" & vbcrlf
25 for i = 0 to howmanyfields
26 fieldval=rstemp(i)
27 If isnull(fieldval) THEN
28 fieldval="-null-"
29 END IF
30 If trim(fieldval)="" THEN
31 fieldval=" "
32 END IF
33 response.write "<td valign=top>" & fieldval & "</td>" & vbcrlf
34 next
35 response.write "</tr>" & vbcrlf
36 IF counter mod howoften = 0 THEN
37 IF response.isclientconnected=false THEN
38 EXIT DO
39 ELSE
40 response.write "</table>" & vbcrlf & "<table border=1><tr>"
41 response.flush
42 END IF
43 END IF
44 rstemp.movenext
45 LOOP
46 response.write "</table>"
47 rstemp.close
48 set rstemp=nothing
49 conntemp.close
50 set conntemp=nothing
51 %>
52 </body></html>
53
54
55
56
57
58
59
60
61
62
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.
Database Connection Pooling by Charles Carroll
Connection pooling takes care of re-using connections.
Lets say Scripta.asp
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 | Open conn. time | Process Start time | Close time |
| #1 | 1:00am .001 | 1:00am .002 | 1:00am .012 |
| #2 | 1:00am .002 | 1:00am .003 | 1:00am .013 |
| #3 | 1:00am .003 | 1:00am .004 | 1:00am .009 |
| #4 | 1:00am .003 | 1:00am .004 | 1:00am .015 |
| #5 | 1:00am .007 | 1:00am .008 | 1:00am .014 |
| #6 | 1:00am .009 | 1:00am .010 | 1:00am .021 |
| #7 | 1:00am .016 | 1:00am .017 | 1:00am .028 |
| #8 | 1:00am .017 | 1:00am .018 | 1:00am .026 |
| Time - open conns | Open conns | Pool to be reused | Being Re-used |
| 1:00am .001 - 1 | #1 | 0 | |
| 1:00am .002 - 2 | #1, #2 | 0 | |
| 1:00am .010 - 4 | #1, #2, #4, #5, #6 | #3 | |
| 1:00am .013 - 4 | #2, #4, #5, #6 | #1 | #6 using #3 |
| 1:00am .014 - 3 | #4, #5, #6 | #1, #2 | |
| 1:00am .016 - 2 | #6, #7 | #2, #4 | #7 using #1 |
| 1:00am .022 - | #7, #8 | #1, #3, #4, #5 | #8 using #2 |
| 1:00am .027 - | #7 | #1, #3, #4, #5 | |
| 1:00am .029 - | #1, #3, #4, #5 waiting |
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 the following articles:
Threading and ASP/IIS by Charles Carroll
Threads - Worker Bees of the Web Site
All the work done by a webserver is handled by threads.
Threads are the worker bees of the web server.
Like any employees you want them working hard!
Any ASP script running on the webserver runs on a given thread. If for example, 100 scripts are requested an IIS has 4 threads to service them typically each thread will process 25 scripts.
Think of threads as cashiers at McDonalds or at the supermarket. 4 cashiers could handle 4 customers simultaneously.
In IIS4, the default is 4 threads (which is simply a registry setting) in initial install but extensive real-world testing on Microsoft.com and hig volume sites indicated 20 per CPU would be ideal.
example:
100 scripts arrive at a web-server with 4 threads. 4 scripts run simultaneously,
round-robin style ala:
http://www.learnasp.com/advice/roundrobin.asp
and eventually the 4 threads would probably handle 25 requests each.
100 scripts arrive at a web-server with 20
threads. 20 scripts run simultaneously, round-robin style ala:
http://www.learnasp.com/advice/roundrobin.asp
and eventually the 20 threads would probably handle 5 requests each.
In IIS5 / Win2000 that registry setting is irrelevant. IIS5 dynamically changes the number of threads processing ASP scripts as needed to optimize performance.
IIS4 / NT4 TIP:
Increase threads 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
for more details.
Thread Affinity - Enemy of Scalability
Since a request can normally be serviced by any
available thread it is like "hopping lines" at cashiers to get to the
shortest line. Usually that is true. If a thread finishes its request it just
grabs the next waiting script UNLESS the request has thread affinity (which Ted
Pattison famed VB author calls a monagomous thread) in which case no matter how
many threads are idle the request must wait for the specific thread it has
affinity too. Don't make your requests have thread affinity (more on how they
can be screwed up this way @
http://www.learnasp.com/advice/dbsessionapp.asp)
Read Up on Threads! Have an Aspirin Ready!

Threads can affect ASP in several ways
Thread Safety 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, see:
We will focus on Thread Safety issues here.
What is Thread Safety?
If a program gets called very fast it can crash or burn out it's motor like a car driven at a high speed UNLESS the designer built in some pretty aggressive code to deal with speed and tested it (kind of like the cars that get run into a wall with crash dummies) Thread safety and high scalability is usually only accomplished by EXTREMELY experienced programmers or commercial components. Thread safety means that the insides were built for speed and then actually tested by creating intense loads (the equivalent of crashing cars into walls) with tools like the Stress Tool at http://homer.rte.microsoft.com/. Better they do this and find out before someone hits a wall and dies the insides need re-inforcement.

A component that is not thread-safe
Crashes or contributes to system instability if the usage pattern creates a situation where several users concurrently access the component in same millisecond.
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.
Test for Thread Safety with WAST - Not People
Thread Safety testing on home-grown components
can be done with tools like the Web Application Stress Tool see:
http://www.asplists.com/asplists/aspwast.asp
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
The WinInet control is a popular way Visual Basic programmers use to scrape web sites. It however was not tested for server use and had some serious flaws that caused it to create many runtime disasters.
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)
http://support.microsoft.com/support/kb/articles/q237/9/06.asp
Thread Safe WinInet Alternatives
Three alternatives to WinInet exist.
Microsoft finally created a server side HTTP
component in MSXML3.0:
http://msdn.microsoft.com/xml/general/xmlparser.asp
ASPHTTP from www.Serverobjects.com is an example of a very safe implementation.
ASPTear from http://www.alphasierrapapa.com/ComponentCenter/ is built on WinInet but the designer Christophe Wille has assured me it wrapped it in thread safe C code to skirt the thread safety problems.
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.asp
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.
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.
Round-Robin Code Execution 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 one of the correct things to do when coding an ASP page.

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.
If your code does something for example 3 lines later you may think it is inconsequential...
Only 3 lines after all...
But the webserver may execute thousands of lines in other scripts before returning to your code.
Hence if the task could be done on line 1 INSTEAD of line 3 that may conserve a resource for thousands of lines of code.
What most people do without thinking:
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
%>
What they should do:
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.
GetString, GetRows conserve resources
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
that code closes recordsets and connections as early as possible.
This is also why disconnected recordets can help
an application perform better see:
http://www.learnasp.com/learn/dbtabledisconnected.asp
Related Links:
Transaction Processing Performance Council @
http://www.tpc.org/
ArrowPoint Mother Nature Profile @
http://www.arrowpoint.com/solutions/profiles/mother_nature.html
Enterprise Scaling Benchmarks @
http://www.devx.com/upload/free/features/entdev/1999/08aug99/cs0899/cs0899.asp
Developmentor Load Balancing @
http://www.develop.com/hp/ewald/lb/loadbalancing.htm
Scalability Resource Kit @
http://www.microsoft.com/siteserver/commerce/DeployAdmin/ResKit.asp
Cisco's Distributed Director, multiple data centers @
http://www.cisco.com/warp/public/cc/cisco/mkt/scale/distr/
Microsoft Enterprise White Paper @
http://www.microsoft.com/NTServer/ntserverenterprise/techdetails/overview/NTSEE.asp
Cisco's Local Director @
http://www.cisco.com/warp/public/cc/cisco/mkt/scale/locald/
-no name- @
http://www.level3.com
Fitch & Mathers Intro @
http://www.fmcorp.com/
Radware - Excellent Cluster @
http://www.radware.com
Faster SSL Acceleration, deals with AOL too @
http://www.ipivot.com/products/products-cd8000.html
Pure SSL acceleration @
http://www.ipivot.com/products/products-ca1000.html
Commerce Accelerator 1000, claims 50X faster SSL @
http://www.ipivot.com
RSW Load Balance Analyzer @
http://www.rswsoftware.com/products/eload.html
Endurance 400 @
http://www.marathontechnologies.com/productinfo/index.htm
L5: A Self Learning Layer-5 Switch @
http://www.research.ibm.com/people/d/debanjan/papers/l5.pdf
8 App Web Servers That Actually Deliver @
http://www.zdnet.com/pcweek/stories/news/0,4153,409380,00.html
-no name- @
http://www.timesten.com
BIG IP by F5 @
http://www.bigIP.com
Interview with Mother Nature Lead Engineer @
http://www.internetwk.com/story/INW19990416S0005
Web switches open e-comm doors at Nettaxi @
http://www.nwfusion.com/archive/1999/82163_12-06-1999.html
Performance Of TCP Splcing For URL-Aware Redirection (requires membership) @
http://www.usenix.org/events/usits99/cohen.html
Server Farms, Port Density, Load-Balancing Switch @
http://www.techweb.com/se/directlink.cgi?INW19991018S0017
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
ASP Components Building
C++/ATL: Component Building (buildc.asp) - Page 243
Java ASP Components Building (buildjava.asp) - Page 244
VB: Simple Component (buildvbsimple.asp) - Page 245
VB: Registering Component (buildregister.asp) - Page 246
VB: DLL overwrite problems (FAQvbDLLoverwrite.asp) - Page 247
VB: ADO, Run It! (buildvbado.asp) - Page 248
VB: ADO, Build It! (buildvbado2.asp) - Page 249
VB: Warnings/Guidelines (buildvbguidelines.asp) - Page 250
VB: General Building Guidelines (buildvb.asp) - Page 251
VB: Installation Requirements (buildvb2.asp) - Page 252
VB: Threading Models (buildvbthreads.asp) - Page 253
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.
Undergoing renovation - SUB ListServSignup
Related Links:
Using Java Servlets on IIS 4.0 @
http://support.microsoft.com/support/kb/articles/Q240/8/42.ASP
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
home for MS Java @
http://www.microsoft.com/java/default.htm
Robert Zembowicz White Papers @
http://www.robertz.com/Papers/
Newsgroups @
http://developer.java.sun.com/developer/community/
Recommended Books:
Related Lists:
Mobile lists by Asplists @
http://www.asplists.com/asplists/mobile.asp
Mobile lists by WROX @
http://p2p.wrox.com/mobile/
Rules:
Mailing List Manners (suggested by Bob Filipiak) @
http://db.tidbits.com/getbits.acgi?tbser=1141
Ken Shaffer's Advice on Asking For Help... @
http://www.adopenstatic.com/personal/help.asp
Simple VB Component by Charles Carroll
This is a very simple component written in Visual Basic. You can create it by
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>
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
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 hasnt 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).
Theres a catch however the new DLL needs to be compiled with binary compatibility with the old DLL. If you dont 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.
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>
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:
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:
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
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:
Undergoing renovation - SUB ListServSignup
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:
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.
MTS - Microsoft Transaction Server
MTS: Overview (buildmtxoverview.asp) - Page 255
MTS: Essentials (buildmtx2.asp) - Page 256
MTS: Transactional ASP pages (buildmtxasp.asp) - Page 257
MTS: Book (booksmtx.asp) - Page 258
MTS: Book (booksmtx2.asp) - Page 259
MTS: Registering Components (buildmtxregister.asp) - Page 260
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, or server.createobject) | mycntxt.CreateInstance("... objectname ..") |
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.
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 = Required %>
<%@ Transaction = Requires_New %>
<%@ Transaction = Supported %>
<%@ Transaction = 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
%>
/font>
|
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://www.amazon.com/exec/obidos/ISBN=0672311305/learnasp |
/font>
Not Ready Yet. Coming Soon!
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.
Advice For Better Coding!
Database in Session or App. Say NO! (dbsessionapp.asp) - Page 262
advice: Cache No More by Phil Paxton (cachenomore.asp) - Page 263
advice:Option Explicit (explicit.asp) - Page 264
advice: Encode with Redirects (encode.asp) - Page 265
advice: Write Your SQL (sqlwrite.asp) - Page 266
advice: Named constants for ADO are better (namedconstants.asp) - Page 267
advice: Clean Up Your Room, I mean Objects (cleanup.asp) - Page 268
advice: Server.MapPath is Good (pathmap.asp) - Page 269
advice: Just Say No to Session COM objects (nosessionobjects.asp) - Page 270
advice: Don't Read COM Properties Twice (propertyexpense.asp) - Page 271
advice: Secure Code and Data (securecode.asp) - Page 272
advice: Encaspulate Code! (encapsulate.asp) - Page 273
advice: CASE reads better than IF (caseisbetter.asp) - Page 274
advice: Error Trapping Strategies (errorstrategies.asp) - Page 275
advice: Error Trapping Secrets (errorsecrets.asp) - Page 276
advice: You Should... (shoulds.asp) - Page 277
Databases and Sessions....
Just Say No!
by Charles
Carroll
Many new ASP programmers and some who even call themselves experienced aspire or accomplish placing recordsets and/or applications in session and/or application variables. They do it to speed things up but actually ensure that the site will perform slower as it gets busier.
Putting a recordset or application into application or session scope leads to:
What works for few users will not for many
Imagine how fast and convenient a Porsche is when driving to Las Vegas with your significant other. Must be the best way to get there... Right? Now imagine a bunch of seniors want to go. 200 seniors x 100 trips in the porsche. Ouch! The tour bus or an airplane scales. The porsche does not. Developers should always design for scaling not minimal users.

Application Level Connections
Mechanically, creating one Application level variables with a database connection is simple.
SUB application_onstart
set application("theCONN")=server.createobject("adodb.connection")
END SUB
Then any code that wants to use that connection
might look like this:
<%
mySQL="select * from publishers where state='NY'
set rstemp=application("theconn").execute(mySQL)
%>
However this code will not scale well. The code is mechanically easy, but the
scripts using this code will suffer from Thread-Affinity and Serialization.
An application variable lives until a web server shuts down. It also lives on a specific thread; we would say the object has thread affinity. Any script utilizing that object must live on same thread, as that object or make an expensive marshalled call to talk to that object.
Thread Affinity
Thread affinity is bad. If a request comes in it would be fast if any thread could perform the task. Thread affinity guarantees only 1 thread can service the request and if that thread is busy the task waits in line for that thread, despite other threads who may be able to service the request.
http://www.learnasp.com/advice/threads.asp
explains threading fundamentals.
Serialization is an enemy of Scalability
If multiple tasks all have affinity to the same thread they become serialized, that is to say they all run in sequence. As a real-world analogy for serialization imagine you wanted to buy a meal at a fast-food cashier and the person in front of you ordered 150 sandwiches for their swim-team. You don't get your 1 sandwich until they finish their order. 6 request for 150 records from a database means the fourth request for 1 record comes after those 900 are retrieved. Without thread affinity the requests could be divided among available threads.
Conclusion: All recordsets and database access would have some level of thread affinity if one connection only is made in global.asa. The side-effect would be recordsets that were forced to specific threads and serialized requests effectively slowing a site's overall performance and for specific scripts.
Recordsets stored at Sessions Level...
Mechanically, this is easy to accomplish:
SUB session_onstart
set session("rstemp")=server.createobject("adodb.recordset")
END SUB
Then any code that wants to use that connection
might look like this:
<%
...
mySQL="select * from publishers where state='NY'
set session("rstemp")=conntemp.execute(mySQL)
%>
However this code will not scale well. The code is mechanically easy, but the
scripts using this code will suffer from Thread-Affinity, Serialization, and
there will always be more recordsets than users accessing a site. In fact a more
aggregious version of Thread Affinity occurs which I will nickname
Thread-Locking.
Thread Affinity Part #2
In IIS3 and IIS4 once a user is assigned a session object (recordset or VB5/VB6 component) with thread affinity every script run in that session is forced onto the thread the first script is assigned. It effectively handcuffs every user's script to the thread their first script was assigned. This occurs because recordsets and VB5 and VB6 need to store their data on a specific thread and until destroyed (unlike C++ components which specifically aggregate the Free Thread marshaller) the objects may never be moved to a different thread which hurts performance.
More Recordsets than Users??? Please explain...
If for example a mere 20 users who access 1 page each and no others at tour site, their session objects (in this case recordsets) persist for the default session timeout (20 minutes unless the registry is modified or a page explicitly sets it using the session.timeout command. If then 50 users access several scripts and 20 of them go lunch or go home for the day, the recordsets will waste memory until their session times out. In this example there would be 90 recordsets and 30 active users within minutes. How can any scenario where significantly more resources are allocated than are being used be efficient?
http://www.learnasp.com/learn/globalproblems.asp
explains a typical scenario.
Create and Destroy on Every Page
Even though every page creates and destroys connections, the newly created ones can execute on any thread. Also because of round-robin execution resources are used sparingly and connections are never open too long.
Make Sure Connection Pooling is in Effect
Connection Pooling can speed up sites. ADO invisibly can co-ordinate that any destroyed connections are not instantly destroyed, instead they are left ready to be grabbed by the next page who requests creating a connection. That page's code has a create request that gets intercepted at a low-level and given an already created connection ready to do database access. The programmers code then is not being executed literally; their create requests often get serviced by already created connections.
http://www.learnasp.com/learn/dbpooling.asp
has more information and details.
What is the fastest way then (if I want fast, scalable database displays)?
"The Worlds Fastest Listbox"
http://www.learnasp.com/learn/speedappdata.asp
shows a lightning fast way to display databases.
GetString to speed up Data Transfer
http://www.learnasp.com/learn/dbtablegetstring.asp
GetRows to speed up Data Transfer
http://www.learnasp.com/learn/dbtablegetrows.asp
All we discuss is fast code over at:
http://www.asplists.com/asplists/aspfastcode.asp
What If I am willing to pay the price?
Make sure you test the load using tools like the
Web Stress Tool @
http://homer.rte.microsoft.com
Much more information on scalability can be found
on
http://www.asplists.com/asplists/aspscalability.asp
which has links and a signup for an excellent 2 way listserver.
Cache No More by Phil Paxton (juggler@iquest.com)
Essentials
Here are the the commands to place at the top of your ASP scripts to ensure that the page is not cached:
<%
Response.Expires = 60
Response.Expiresabsolute = Now() - 1
Response.AddHeader "pragma","no-cache"
Response.AddHeader "cache-control","private"
Response.CacheControl = "no-cache"
%>
Response.Expires = 60
is said to expire at 60 seconds, not 0. Also, Khin Zaw (from
http://www.asplists.com/asplists/aspadvanced.asp) 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).
Response.Expiresabsolute=Now()-2
(my own creation) says "expire this page
48 hours ago", allowing for time
differences, rather than specify a static date. If your page is being viewed by
a browser in a very different time-zone it
Response.AddHeader "pragma","no-cache"
Response.AddHeader "cache-control","private"
Response.CacheControl = "no-cache"
their use originates rom an MS KB article. The code is correct but there are some incorrect
statements in the article itself.
Some related KB articles include:
http://support.microsoft.com/support/kb/articles/q189/4/09.asp?FR=0
http://support.microsoft.com/support/kb/articles/q172/8/96.asp?FR=0
http://support.microsoft.com/support/kb/articles/q165/1/50.asp?FR=0
If the above techniques do not work in every instance, a "cache-buster" can be employed.
<a href=whatever.asp?Nocache=<%=rnd()%>>
or
<a href=whatever.asp?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.
ASP Commandment #1: Use Option Explicit
use Option Explicit when writing VBScript.
<% option explicit%>
goes at the top of the script!
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