Wednesday, May 24, 2006

The Control Gallery at ASP.NET still exists, it's just not on the menu anymore.  It has been moved to the Resources Page, along with Hosts, Community Sites and Case Studies.  VWDE, Starter Kits and The Sandbox are on the Downloads page.

Alex Lowe has a short explanation in this thread: http://forums.asp.net/thread/1294935.aspx

Wednesday, May 24, 2006 2:38:41 PM (Eastern Standard Time, UTC-05:00)

My latest ASP Alliance article has been published, titled Getting Started with the Club Site Starter Kit:

Since the release of ASP.NET 2.0, several starter kits have been released as examples of programming practices. These kits are also good starting points for actual websites and can be valuable to novice webmasters. This article will demonstrate how to download and install the Club Site Starter Kit, configure a different database to prepare for a production site and change the appearance by modifying the master page.

There is one correction to the article--Listing 4 is incorrect.  The MasterPage filename in Figure 20 should be "caddyshack.master", and Listing 4 should then read:

<%@ Page Language="VB" MasterPageFile="~/caddyshack.master" Title="Untitled Page" %>

Find the full article at http://aspalliance.com/839.

 

Wednesday, May 24, 2006 1:27:49 PM (Eastern Standard Time, UTC-05:00)
 Tuesday, May 23, 2006

Eric says crazy filename parsing is something else you should stop doing.  If you're creating output files, you probably need to timestamp the file name to keep the files separate.  Step away from the keyboard before you do anything crazy--you can do this in one line of VB.NET:

Dim _filename As String = String.Format("MyFile.{0}.xml", Now.ToString("yyyyMMddHHmm"))

 

Tuesday, May 23, 2006 5:17:00 PM (Eastern Standard Time, UTC-05:00)

Brendan Tompkins has a nice post on printing a web page as a PDF using webSuperGoo's ABCPdf component.  The example is written in C#, but shouldn't be too hard to translate.

 So what’s the solution to your website printing problems at least until you can guarantee that the majority of your users will be using a print-friendly browser?  Simple, when a user makes a print request on your site, dynamically create PDF documents on the fly making sure to include all of your users page state, and output that PDF document to the browser

Full article at http://codebetter.com/blogs/brendan.tompkins/archive/2006/05/22/145267.aspx.

Tuesday, May 23, 2006 3:06:03 PM (Eastern Standard Time, UTC-05:00)
 Monday, May 22, 2006

At the last BADNUG meeting, someone mentioned they wished there was Intellisense for SQL Server.  I said there was such a product; Red Gate recently purchased it, and is now giving it away until Sep. 1, 2006!

Also included in the package is a 14-day trial of Red Gate's Dependency Tracker, which is a wickedly-cool database diagrammer.

More information and download link at http://www.red-gate.com/products/sql_prompt/index.htm.

Monday, May 22, 2006 1:26:23 PM (Eastern Standard Time, UTC-05:00)
 Thursday, May 18, 2006

(I apologize in advance for anyone I'm citing below.  Your intentions were good, but IMHO, your technique leaves soemthing to be desired.)

Almost as annoying as bad-question-askers-in-forums are the click-here people.  That was bad enough on web pages, but it's gotten worse with the explosion of blogging.

First example comes to us from John Cilli's Commerce Connect.  John found an article that he'd like to share:

Before I "click here", I'd like to know what the article is about.  Maybe it's something I already read this morning.  Maybe it's something he thinks is useful, but not necessarily something Id find so.  No indication.  John's blog is reputable, but whatif this is a random blog--could "here" be a trojan waiting to infect my system?  And since my Internet usage at work is monitored, I can't just click willy-nilly.  Chances are I'll forget when I get home, and any benefit from the article is lost.  The article title and maybe a snippet or short abstract would be really great (see me pat myself on the back below for an example).

John Papa brings us our next example, but it's more of a "Where's Waldo: Hyperlink Edition" style of linking.  Can you see the download link below?  It's that little tiny one labelled "Attachment(s)", below the Google ads and Published information.  This isn't so much John's fault as it is the skin designer's.  Unless John designed the skin.

So who does links well?  Mike Gunderloy does a good job, with a title and short description.  Scott Hanselman as well.  I think I do article links prett well; see http://www.rjdudley.com/blog/First+Ultra+Mobile+PC+Comes+To+US.aspx for an example.

I'm sure both everyone of you reading this article has seen more than enough examples.  Share some below.  But don't be a bad linker; not in the comments, nor in your posts.

<update 2006-05-19>

Jesse Ezell adds one to the list.  Hey Jesse, what is 'this'?

Thursday, May 18, 2006 7:07:46 PM (Eastern Standard Time, UTC-05:00)

If you use a Treo 700w and SplashBlog, don't perform their automatic upgrade.  Their upgrader installs the wrong version of the software on your phone, and the client won't start.  There are two versions for Windows Mobile devices, one for those without a touchscreen (which they call the SmartPhone version) and a separate version for devices with a touchscreen (which they call the Pocket PC version).  Treo 700w users want the Pocket PC Version of SplachBlog.

Get the correct version at http://splashblog.com/portal_download.aspx.

Thursday, May 18, 2006 11:08:28 AM (Eastern Standard Time, UTC-05:00)
 Monday, May 15, 2006

I couldn't find a quick example when I was looking for one, so here's mine.

First, create your stored procedure with an output parameter:

CREATE PROCEDURE [dbo].[MySproc]
(@MyParameter varchar(50) OUTPUT)

And in your sproc, set your parameter to a value

set @MyParameter = scope_identity

Then, add an output parameter to your database command:

Dim _db As Database = DatabaseFactory.CreateDatabase
Dim _cmd As DbCommand = _db.GetStoredProcCommand("MySproc")
_db.AddOutParameter(_cmd, "@MyParameter", DbType.Int32, 4)

Then, execute your stored procedure, and assign the parameter value to a variable (remember to DIM the variable)

_db.ExecuteNonQuery(_cmd)
_result = _db.GetParameterValue(_cmd, "@MyParameter")

 

Monday, May 15, 2006 11:25:31 PM (Eastern Standard Time, UTC-05:00)
 Thursday, May 11, 2006

One of the great things about stored procedures is that you can put a whole bunch of different commands into one procedure, and call everything with a single command.  Gnarly!  However, if the procedureruns slowly, it's difficult to determine which command(s) are the problem.  Bogus!

One trick I use is to sprinkle little logging steps throughout my stored procedure, and try to narrow down which command is causing the problem.  These steps just log a step name and a timestamp into a table.

My table has the following structure:

CREATE TABLE [tblCommands] (
 [fldID] [int] IDENTITY (1, 1) NOT NULL ,
 [fldCommand] [nvarchar] (2000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
 [fldDate] [datetime] NOT NULL CONSTRAINT [DF_tblCommands_fldDate] DEFAULT (getdate())
) ON [PRIMARY]
GO

fldCommand is either a good name of the setp being logged, or something descriptive about what's happening in the procedure.  Just so long as I can find it again in the sproc.

Then, I add commands such as

insert into tblCommands(fldCommand, fldDate) values ('Final selection',getdate())

-- do my selection here

insert into tblCommands(fldCommand, fldDate) values ('End',getdate())

Reviewing the data from tblCommands:

fldID       fldCommand         fldDate
----------- ----------------   -----------------------
31          Start              2006-05-11 13:18:19.943
... (snipped for brevity)
39          Final selection    2006-05-11 13:18:24.240
40          End                2006-05-11 13:19:56.677

We can see that the entire procedure runs in roughly 1:40, with approx. 1:30 of that wrapped up in the final selection step alone.  By focusing on only the final step, I was able to optimize the query so that the entire procedure runs in 10 seconds.

I realize that with the naming convention I've used here, I'm likely to raise the ire of naming zealots.  I like appending a prefix to column names because that means I can use a reserved word such as 'Date' as a column name.  If you don't like it, you're fere to use a different convention in your own sprocs.

<update 2005-05-14>

Eric brings up a good point in his comment below about using the Query Analyzer (part of the SQL Server 2000 tools).  I have used the Query Analyzer extensively, and one place it falls short is with dynamic SQL statements in your queries.  If you have properly formatted dynamic sql (see http://www.rjdudley.com/blog/Is+Dynamic+SQL+In+Your+Stored+Procedures+Vulnerable+To+SQL+Injection.aspx), and especially more than one dynamic SQL statement, the Query Analyzer can't analyze the sproc.  Adding sinks like I have above can help debug an entire sproc, especially those with dynamic SQL.

Thursday, May 11, 2006 3:53:19 PM (Eastern Standard Time, UTC-05:00)

I dislike how VS 2005 handles solutions, but I thought it was just me.  Victor Garcia Aprea has a good commentary on the subject:

Of course, I still think Visual Studio is totally messing up the Project and Solution terms, and that such core concepts should deserve a bit more of attention; here goes my view on it so you can take a look and make your own mind

Glad to know I'm not alone.

Thursday, May 11, 2006 11:39:50 AM (Eastern Standard Time, UTC-05:00)
 Wednesday, May 10, 2006
Wednesday, May 10, 2006 3:21:15 PM (Eastern Standard Time, UTC-05:00)

Part of my work involves a SQL Server 2000 data warehouse, updated nightly with extracts from an ERP system.  I knew that the DTSs tended to run long, and I wanted to get a better idea of exactly how much data we were moving around.

First thing I did was add a table with the following schema:

CREATE TABLE [tblDtsLog] (
 [fldEntry] [int] IDENTITY (1, 1) NOT NULL ,
 [fldStep] [int] NOT NULL ,
 [fldStepType] [varchar] (5) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
 [fldStepName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
 [fldTimeStamp] [datetime] NOT NULL ,
 [fldNotes] [varchar] (255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
 [fldPackage] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]

This is a pretty general structure, and allows me to add different logging and debugging steps to the DTS.  fldEntry is simply an incrementing value to help sorting what happened when.  fldStep refers to the stepf of the DTS package, fldStepType is a short description of the DTS step.  I use fldStep because someone always asks me what that step is doing when we're looking at the numbers, and it's easier to log it than open the DTS and find it.  fldStepName is there because I inherited almost all of these DTSs, and the names don't always describe what's going on.  fldTimeStamp is the execution time of the step, fldNotes are some information I want to include about the step (usually just a rowcount), and fldPackage is the name of the DTS package.

One of the early steps for most DTSs is the extract from the ERP system to an intermediate table.  Depending on the package, the data in the intermediate table used for comparisons or modified before being migrated to the production tables.  By adding  a SQL task immediately after the extract, I could get an exact idea of how many data rows we just moved:

select * from IntermediateTable
insert into tblDtsLog(fldStep, fldStepType, fldStepName, fldTimeStamp,fldNotes, fldPackage) values (1,'Begin', 'Extract Step 1',getdate(),@@rowcount, 'Some DTS')

This simly adds one entry to the above table with a count of how many rows exist in the intermediate table.   For other steps, I use the Begin and End flags in conjunction with the getdate() to see how much time elapsed for the processing of a particular matching or modification step.  By sprinkling these liberally through my DTSs (some packages have 15-20 of these logging sinks in them), I have excellent insight into what is running slow, and then we can examine each step and try to optimize it.

Recently, we used the results of this monitoring to make a small tweak to one step of one DTS, which resulted in an overall gain of 2 hours of processing time in the overall update!

Wednesday, May 10, 2006 11:16:29 AM (Eastern Standard Time, UTC-05:00)