Wednesday, October 06, 2004

Today is a very exciting day for me (as well as those in our local Utah .NET User Group).  It is with great pleasure that we welcome Rob Howard (formerly of Microsoft on the ASP.NET/.NET Framework teams and now founder of Telligent Systems).  Rob will be providing a presentation entitled “10 'Killer' Performance Tips and Tricks for ASP.NET”.  I'll provide a report of the event later tonight after the meeting...this is going to be awesome!

If you'd like to attend, please 1) RSVP and let me know and 2) show up.  It's free and anyone and everyone is welcome.  Our local .NET User Group meets at Northface University which is kind enough to offer us space at their facilities each month.

Here are the details about tonight's meeting:

Date: October 06, 2004
Time: 6:00 PM
Northface University
10701 South River Front Pkwy, 2nd Floor
South Jordan, Utah 84095

Wednesday, October 06, 2004 8:04:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I have found it's a lot easier to blog about solutions to problems because of the turmoil and heartache involved as well as the victorious feeling of relief when the issue has been resolved.  In an attempt to be more proactive to coding solutions, rather than reactive, I will work on providing more valuable blog entries not so much about problems overcome, but techniques and strategies that I employ in my day-to-day programming because I feel that some of that experience would be valuable to someone out there in the wild wild web.

Today's blog entry, however, is not one of those blog entries.  I'm going to talk about a problem solved.  I was taught a very valuable lesson today - again.  Here's the deal:

I am working on an ASP.NET application that dynamically loads various controls depending on the user's context with the application.  Some of the controls I wrote as Server Controls while others are User Controls.  Within a particular user control (.ascx) I had placed some hidden controls (HtmlInputHidden) that provide UI feedback to the server so I can take appropriate action.

When the form was posting back to the server I couldn't see the values within the controls.  That is, the .Value property would ALWAYS return the default value (at least it would return the value assigned in the <input /> tag).  No matter what I did.  Interestingly, however, I could SET the value and that would get posted back to the server.  The only way I could ascertain this was to inspect the form's posted values - indeed the correct value was always there, but it was never associated with the control variable.

As it turns out, and it is with much embarrassment that I even admit this, I was loading the control too late in the hosting page's lifecycle.  I had the call to LoadControl(”...ascx”) in the OnLoad() method.  Instead, it belongs in the OnInit() method andthat's because the ViewState is loaded back in the controls after the OnInit and before OnLoad.  I don't know how I overlooked that, but I did.  I don't think I'm going to forget that lesson ever again.

In order to properly associate control values, property values, events, etc with dynamically loaded user controls, you must always instantiate the control in the OnInit() method (or the Page_Init() event) and add it to the parent control's .Controls collection therein:

protected override void OnInit(EventArgs e) {
   MyControl ctl = (MyControl)LoadControl(”MyControl.ascx”);
   Page.Controls.Add(ctl);
}

Wednesday, October 06, 2004 7:56:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, October 05, 2004

Sorry for the non-technical post, but I must agree with Sam Gentile.  I saw Sky Captain and the World of Tomorrow on opening weekend and thought it was a blast.  I couldn't precisely nail down what I liked about it, but I think Sam hits the nail on the head: it's a mixture of (semi-)modern sci-fi with a Flash Gordonesque, 30's style.  I absolutely love the pastel, sepia color used throughout the flick.  I am definitely one for nostalgia, and watching this movie I felt once again like a kid.  Watching the characters travel over the globe with the super-imposed lat/long lines and compass beneath the surface of the water was fantastic; that and the abnormally enlarged radio tower summoning Sky Captain...Watching it reminded me too much of the old George Reeves Superman...though the movie wasn't that corny.

I normally wouldn't be posting something like this, but it turns out that during my weekly programming session with a group of friends last night we were talking about just this movie.  Then reading Sam's blog I couldn't help it.  Go see the movie if you haven't yet!

Tuesday, October 05, 2004 7:45:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, October 04, 2004

By no stretch am I an Xml guru.  I know enough to get by and can be pretty dangerous with it.  I stumbled upon this tool by Jeff Key that I find extremely useful.  I deal with a lot of XML as single, long strings.  I want to view the Xml in a hierarchical node-tree view and while IE gives me that (to a limited degree), this tool gives me much more power with a very small learning curve.

  • You can view your Xml loaded from a file
  • You can view your Xml loaded from the clipboard.  Nice!  While this functionality might be expected, I'm glad the Jeff took the time to support such functionality.
  • Organizes your Xml indented (regardless of whether it came in in that format or not)

Now if you're wanting more power and capabilities, but at a steeper learning curve, there is also the XMLSpy 2004 Home Edition (which is free) or the Professional or Enterprise versions.

Unless I absolutely need the added functionality, though, I'll be sticking with Jeff's tool...thanks Jeff!

Request:  Support XPath queries for searching; it would help facilitate using a single tool for my basic XML needs, rather than having to jump between tools to perform those queries.

As you can see, sometimes the simplest of things gets me excited because I've been wanting this capability for a long time, but haven't taken the time to write it myself.

Monday, October 04, 2004 8:47:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Saturday, October 02, 2004

I consider myself a pretty good ASP.NET developer.  However, it doesn't matter how many times I try to do it, I can't seem to remember how each of the path functions on the Request and Page/Control objects work.  Invariably I find myself opening MSDN or tediously debugging and stepping through my code, making heavy use of the Command Window or the Quick Watch dialog.

Thanks to Rick Strahl for consolidating these functions in a manner that's easy to read and understand. :-)

Saturday, October 02, 2004 3:54:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, September 30, 2004
I was catching up on some blog reading and ran across this link in Eric Gunnerson's C# Compendium.  Great game that tests your ability to not follow your instincts.  Fantastic game!
Thursday, September 30, 2004 4:07:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback

If you're a website developer you may have run across several of the nuances presented with the more secure IE 6 for Windows XP SP2 - namely the Information Bar (the nice yellow bar that appears at the top of the webpage when the page attempts to perform some restricted action such as display a popup the user didn't request, or the unsolicited installation of an ActiveX control).

Here are a couple of great links to follow to learn more about those restrictions and how to make your website play friendly in their new environment:

Compatibility in Internet Explorer 6 for Windows XP Service Pack 2

Fine-Tune Your Web Site for Windows XP Service Pack 2

Thursday, September 30, 2004 3:50:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, September 29, 2004

Last night I was greeted to a very unpleasant, and unsettling occurrence that had me baffled until today when I got some help from a great friend - one of my old co-worker buddies from Microsoft.  My network was up and everything was fine (internally), but I couldn't get any DNS resolution outside my network (i.e. out on the internet).

As it turns out I could ping my router from every computer on the network except my domain controller (which is also my DNS server).  Because my DNS server couldn't resolve anything, I was pretty dead in the water.  I tried several things to fix the issue, but nothing worked.  It was suggested by my buddy to change the server's IP address and see if I couldn't still ping the router.  Lo and behold that was the problem!

Somehow, somewhere, the router was denying traffic from my old IP address.  Without any concrete evidence, I attribute this problem to a pretty bad power outage that we had a few days ago.  Even after powering down the router for several minutes and starting it back up I could not get connectivity on the old IP so I had to resort to a new IP.  Crazy, but at least it works!

Ya know? I've been in the contemplating getting a new, good, reliable router anyway...maybe this is the incentive that I need.  This one that I have (a NetGear) has been fantastic over the past several years, but I've been wanting to get something newer and better; budget is not the primary concern - but practicality is.

Any suggestions?

Wednesday, September 29, 2004 3:24:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, September 27, 2004

Today I had an issue in which I wanted to build out a tree of data.  This information is collected in a single table with self joins to define the hierarchy.  I wanted to avoid having to repeatedly query the database for a subset of the records - instead, I wanted to get the whole batch from the database, already organized and set up in the tree.  I've done things such as this in Oracle via the CONNECT BY statement in the past, but unfortunately SQL Server (in its current incarnation) doesn't support this type of functionality; therefore, I had to resort to rolling my own.

A join (either OUTER or INNER) did not give me what I wanted, though the relationship could be established, so I decided to write a stored procedure to accomplish this.  Now, to be honest, I have not profiled this to see how it can be optimized (I'd welcome insights regarding that) but for small set of data (e.g. < 10,000 rows) I think this approach might work reasonably well.

Basically, the idea is that the stored procedure establishes two temporary tables: one for the final output and one for the work in progress.  You can call the procedure, indicating the root node for the hierarchy (defaulting to the top - those items that have no parent; identified by NULL).  From that point, the procedure begins to analyze the data, writing into the temporary work table (called #Stack) and recording records as necessary into the #Output table.

My strategy (as this will be used in a web-based application and will rarely, if ever, change) is to query it once and cache it so I don't have to perform this analysis over and over again.  Additionally, I'm really only expecting < 50 records so the hit is pretty minimal.  What do you think of the approach?  Good?  Bad?  Ugly?  Ingenious?  Mediocre?  I'd be interested in getting some good feedback.

CREATE PROCEDURE dproc_GetCategoryList
   @RootParentID int = NULL
AS
   SET NOCOUNT ON

   -- establish the table that will contain the output results
   CREATE TABLE #Output ( ID int, Name nvarchar(35), ParentID int )

   -- establish the work table
   -- this data will fluctuate and will represent the information that is being processed
   CREATE TABLE #Stack ( ID int, Depth int )

   DECLARE @currID int
   DECLARE @depth int

   IF ( @RootParentID IS NULL )
      -- start at the parent level (there might be multiple top-level parents) and start working our way down
      -- top-level parents are identified by not having parent themselves
      DECLARE topLevel CURSOR FOR
      SELECT ID FROM tblCategoryIndex WHERE ParentID IS NULL ORDER BY Name
   ELSE
      -- start at the level prescribed by the caller and build out the child hierarchy
      DECLARE topLevel CURSOR FOR
      SELECT ID FROM tblCategoryIndex WHERE ID = @RootParentID

   OPEN topLevel
   FETCH NEXT FROM topLevel INTO @currID
      WHILE ( @@FETCH_STATUS = 0 )
         BEGIN
         SET @depth = 1
         INSERT INTO #Stack VALUES ( @currID, @depth )

         WHILE ( @depth > 0 )
            BEGIN
               IF EXISTS ( SELECT ID FROM #Stack WHERE Depth = @depth )
                  BEGIN
                     -- read the next record's id for processing so we can get its children and delete it
                     SELECT @currID = ID FROM #Stack WHERE Depth = @depth
                     DELETE FROM #Stack WHERE Depth = @depth AND ID = @currID

                     -- add the category to the output table
                     INSERT INTO #Output SELECT ID, Name, ParentID FROM tblCategoryIndex WHERE ID = @currID

                     -- get the children of the current category
                     INSERT INTO #Stack SELECT ID, @Depth + 1 FROM tblCategoryIndex WHERE ParentID = @currID ORDER BY Name DESC

                     IF ( @@ROWCOUNT > 0 )
                        SET @depth = @depth + 1
                  END
               ELSE
                  -- move up one level, we're recursed as deep on this node branch as we can go
                  SET @depth = @depth - 1
            END

         FETCH NEXT FROM topLevel INTO @currID
      END
   CLOSE topLevel
   DEALLOCATE topLevel

   SET NOCOUNT OFF

   -- return the result set
   SELECT * FROM #Output
GO

- [Updated 09/28/2004 for proper sorting of the name - the list is now properly alphabetized in the result set.]

Monday, September 27, 2004 8:40:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Friday, September 24, 2004

For all those programmers out there that think that it's important to write code that is easily maintainable, think again!  You want job security, right?  Think about yourselves for a change - be selfish!  It is of utmost importance to create code that is not only unmaintainable by the unsuspecting inheritor of your code, but if you have to spin your wheels going back over something you just wrote - all the better - it'll keep you employed and your boss will think that you're worth every penny by solving these insurmountable problems found in the mazes and jungles of code!

For more details, check this site out.

Friday, September 24, 2004 11:20:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback