DEV414: Black-Belt ASP.NET
Notes from Rob Howard's TechEd 2004 break-out session "Black-Belt ASP.NET: Tips and Tricks for your ASP.NET Applications." Rob is, as of the time of this writing, a Program Manager for Microsoft's Web Team. He has worked as an evangelist for Microsoft, did some great work on .NET Web services, etc. Quite the resume. The following are the notes from Rob's talk.
- Building an Intermediate Page
- Problem: Long running, expensive operation to prevent re-submit
- Goal: Want to display temporary 'Please Wait' processing UI - client waits while server processes.
- Solution: When user submits a long-running form, it submits to a different page, which displays the "Please Wait" graphic, while using an IFRAME to actually load the page that has the long-running query. Upon completion of the long running operation, the IFRAME is displayed in the page.
- Set Focus
- Rob presented a function
SetFocus(), into which a user could pass in a Control
ID and have the control receive focus. This function used a
- Tip: Make sure the HTML of your pages are not too large - impacts download speed. Aim to keep page size under 30 KB; Google's front page is 2 KB.
- OutputCache can affect performance of application, even micro-caching (OutputCaching with a duration of just 1 second).
- Demo: Showed page displaying a DataGrid with the contents of the Northwinds database. Used Application Test Center to view requests per second that could be handled by adding output caching. Adding a 60 second OutputCaching added requests per second being handled from 200 reqs./sec to over 500 reqs./sec. Changing to a 1 second duration still kept reqs./sec around 500. (Of course, practically, benefits of this approach can only be seen if there are more than 1 request per second.)
- Per-Request Caching
- Problem: There exists data that cannot be cached - data tied to user, for example.
- Per-Request Caching: cache data for the lifetime of a request; different than Cache API.
- Solution: Use
HttpContext.Items collection; scoped to lifetime of HTTP request.
- Benefit: Allows multiple server controls on a single page to share data among one another. For example, if various controls all access user data, can cache it in the
HttpContext.Items collection so that only one control needs to actually access the data from the database. This technique is used with the ASP.NET Forums to provide better performance.
- Used Application Test Center to show perf. gain of using
HttpContext.Items; well, actually the demo didn't work, performance didn't improve. Bummer.
- Reflection Caching
- Problem: Reflection is expensive, 3-4 times the cost of normal object creation.
- Solution: Cache the constructor of the class - 1/3 cost of non-cached. This technique is used in the ASP.NET Forums in teh Forums provider.
- Returning Multiple Result Sets
- Database operations are expensive and network I/O is costly.
- Solution: You can batch result sets in one go, rather than requiring separate trips to the database. Use
SqlDataReader.NextResult() to step through result sets.
- Performance gains are most profound if the database and Web servers reside on separate machines.
- Demo: Using Application Test Center, Rob showed not using multiple result sets provided about 40 reqs./sec; using multiple result sets improved the performance marginally, to 45 reqs./sec, or so.
- SQL Record Paging
- Problem: DataGrid default paging gets all database records, and only shows the specified subset - very inefficient.
- Solution: Use DataGrid custom paging, and implement a stored procedure to get back the precise subset of records based on page number and records per page. (Rob's stored procedure built a temporary table, dumped the entire results in the database, and snipped out the appropriate set of records from the temp. table.)
- Background Processing
- Problem: Expensive operations can tie up the request thread.
- Solution: Can use
System.Threading.Timer to schedule background tasks. Can set a callback to happen every n milliseconds. Requires CLR AppDomain to be active. Uses thread from ASP.NET threadpool.
- Implementation: Create an HTTP Module that has a static
Timer class instance. In the module's
Init event, create a new
Timer class if it's
null, specifying a callback function to call within some interval (like once every 10 seconds). The callback function should be passed in an
- Database Cache Invalidation
- Problem: Keep cache and database in sync.
- Solution: Cache is invalidated on changes to the underlying data in the database. Will be a built-in feature of ASP.NET 2.0. Many implementations in ASP.NET 1.x today, but many have flaws. Current techniques with flaws include using an extended SQL stored procedure to send an HTTP request to the Web server - a potential bottleneck, since the SQL database is waiting on the Web server to respond (also doesn't work with Web Gardens). Another option is having an extended sproc touch a file on the Web server - another bottleneck.
- A better approach uses a separate process that polls SQL server to see if the data has changed. (This is the technique used in ASP.NET 2.0's database cache invalidation.) Rob's demo used the background processing technique discussed above to poll the database once every 10 seconds.
As usual, Rob's talk was informative and interesting. The presentation is nice, as he gives a tip or trick, and then dives straight into a demo.