June 2005 - Posts

Screw It, I Filed the Claim
30 June 05 07:39 PM | Scott Mitchell | with no comments

This is the fourth installment of my ongoing Small Claims Court Experience...

In yesterday's blog entry I mentioned that I went to the company's office and was told, upon informing them that I was heading to the courthouse to file a small claims court case, that a partial payment had been sent earlier in the week. I felt I was being lied to, but didn't know what else to do than just wait it out and see if payment did arrive by the end of the week. After reading the comments in yesterday's blog post and a few private emails, I decided that I had a better chance winning the lottery then getting payment (or a truthful statement) from this company, so today I went and filed the paperwork. The courtdate is in early August, assuming everything goes to plan (i.e., the don't file for a later date, they are properly served, etc., etc.).

<rant>
When filing the paperwork the employee who was assisting me did a quick search on the company and noted that the company's address as recorded by the secretary of state was different than the address I had put down as the place to have the defendent served. This piqued my interest so after leaving the courthouse I stopped at this other address and found yet another office for this corporation. A bit more of an exhaustive search on this company revealed that they also have offices in San Jose and Scottsdale... but they can't freakin' pay their instructors the small sums they promised them for the services the instructors have already performed. Gah.
</rant>

Ok, enough ranting on about this. In fact, you probably won't see another entry on this small claims court hubbub for a while, until the actual court date draws nearer. I don't mean for this series of entries to turn into a whine-fest, but rather to serve as a source of information for other independent consultants who arrive in a position similar to the one I find myself in. As aforementioned, the best way to avoid such a headache is to not let yourself get in this position in the first place. See the first blog entry for more suggestions on this matter.

A complete list of blog entries related to this topic can be found at My Small Claims Court Experience and through Going Independent category. Your feedback is most welcome - please leave a comment or drop me a line.

Filed under:
A Faint Glimmer of Hope
29 June 05 05:50 PM | Scott Mitchell | with no comments

This is the third installment of my ongoing Small Claims Court Experience...

In my last blog entry on this topic I mentioned how, a week ago, I was about to head out and officially file the necessary paperwork when, walking out the door, I got a call from a fellow trainer's father who was a lawyer and gathering information to take this company to superior court. Additionally, I managed to get ahold of some email addresses of past instructors, and sent out an email blast asking if any of them were in my position. Sadly, I have since received news that an additional six instructors have done work three to nine months ago and have yet to be paid a dime or given an ounce of explanation other than the standard run-around.

Having wrapped up a project yesterday, today I had a free hour to actually head down to the city's offices and formally file the claim. Thanks to suggestions in earlier blog entry comments and IMs/emails, I decided it wouldn't hurt to stop by this company's office with the paperwork in hand and give them one last chance to pay up before I filled the paperwork.

Unfortunately upon arriving the owner of the company, and the person I've been dealing with since the account became delinquent, wasn't in the office. Instead, another lady helped me. She explained that they had recently received a large check that was long overdue and had sent out partial payments to the instructors that they owed. She said the checks were mailed out yesterday so I should be receiving them any day now, and that the other half would be coming soon after. I huffed and puffed a little, letting her know how unprofessional her company was behaving and so on.

In the end, I didn't file the paperwork. I decided, instead, to wait til the end of the week to see if, miraculously, a partial payment does arrive. I think I may be being a bit to naive, taking this company's word at face value. After all, as this person was explaining the situation to me it felt like I was listening to a pitch to buy some excellent real estate in Florida as an investment that will pay for itself ten times over. I mean, if they had gotten this big check and were going to pay me, even a partial payment, wouldn't they email or call me to update me on the status?

The new and final deadline, then, is Friday - no check by then, and I'm heading in to file the paperwork on Tuesday the 5th. I hope there is a partial payment in the mail... I don't want to go to court, I just want what's owed me to be paid. Even if there is payment working its way through the mail system as I type this, though, this company needs to learn how to better communicate with those it owes money. Not returning phone calls or answering emails, not providing those you are indebted to with any information as to the status of forthcoming payment, even if it's partial, is not acceptable.

Meh.

A complete list of blog entries related to this topic can be found at My Small Claims Court Experience and through Going Independent category. Your feedback is most welcome - please leave a comment or drop me a line.

Filed under:
Scott Hanselman's Recommended Tools
28 June 05 09:58 PM | Scott Mitchell | with no comments

The other day I stumbled across Scott Hanselman's 2005 Ultimate Developer and Power Tools List. In his blog entry, Scott lists a whole slew of recommended tools and utilities covering a wide array of facets. Definitely worth checking out.

There are a few tools Scott mentioned that I wanted to give a shout out to, as well:

  • Reflector - this tool has given me an understanding and comprehension of the .NET Framework and ASP.NET internals that (IMO) no book could ever provide. Learning some factoid by reading about it doesn't stick in the ol' noggin nearly as well as figuring out the same bit of information by spending 15 minutes plowing through the actual source code. Highly, highly, highly, highly, highly recommended.
  • Firefox Extensions - extensions make Firefox one sweet browser. The most useful to me in a day-to-day setting are GoogleBar, IEView, and WebDeveloper. For having to dig into the HTTP internals for a request, the Live HTTP Headers extension is invaluable. (Ditto for Fiddler for IE.)
  • Peter Blum's Validation and More and Date Package - a client of mine bought these controls on a whim and it was the best investment he could have made. It's probably saved me a couple dozen hours, netting the client several thousand dollars in savings... all this for a few hundred dollars.
  • Andy Smith's MetaBuilders - a number of very useful, free, open-source server controls and custom DataGrid column classes, that have also saved my clients oodles of money over the past couple years.
  • ELMAH - Atif Aziz's Error Logging Module and Handlers component, for which I co-authored an article on MSDN Online (Using HTTP Modules and Handlers to Create Pluggable ASP.NET Components). This is another thing I use in every ASP.NET project - takes about two minutes to setup and the rewards are priceless. Plus you can't beat the fact that ELMAH is free and open-source, so you can enhance it as needed.

One tool not on Scott's list that is invaluable to me is UltraEdit32. (Granted, Scott has a similar buffed up text editor, Notepad2, the benefit over UltraEdit being that Notepad2 is freeware. I've not used Notepad2, so I can't compare it feature-wise to UltraEdit.) I also want to give a shout-out to FileZilla, which is a free FTP program that, since I started using it, I could not imagine life without it. (I was using WS_FTP before... ick.)

For more tools and utilities be sure to check out Scott's list. There are also some past blog entries that touch on similar topics, such as Programs You Can't Live Without and What Programs Do You Have Running 24x7?

I'm No Longer Cutting Edge
27 June 05 08:43 PM | Scott Mitchell | with no comments

I'm no longer cutting edge. Well, I guess I've never really been super cutting edge, but since the ASP 3.0 days I've always been on the forefront of new ASP-related goodness coming down the Microsoft pipeline... I started working with classic ASP 3.0 months before it officially shipped with Windows 2000 / IIS 4 when I started working on my first book. Right as I was finishing my second (and final) book on classic ASP I was invited up to Redmond to learn about this new technology, ASP+ (which later became ASP.NET). Those were the days.

Here we are now, getting closer to having an RTM version of 2.0, and I'm so far behind. I've looked into 2.0, played around with it, even written some tutorials on the GridView, but I've not created an end-to-end application with ASP.NET 2.0 or done anything remotely close to it to prepare myself for my upcoming book, which I've yet to start and whose priority seems to be diminishing daily. I feel so outdated.

A large part of this is due to the fact that I do quite a bit more consulting work these days than I used to do in the past and my clients are happy with ASP.NET 1.x (not that I've tried to convince them to switch their existing, working ASP.NET 1.x systems to beta software). I will master ASP.NET 2.0 here sooner than later, but what concerns me is that I'll need to know both ASP.NET 1.x and 2.0 quite intimately. The 4Guys visitors and my students will be interested in 2.0 content, but my clients will want me to keep expanding their existing, functional 1.x systems.

There was a time when I knew classic ASP and VBScript like a second language. It's been years since I've last created or edited a classic ASP page, thankfully. Without the practice with ASP/VBScript, however, this “second language” has fallen into disrepair. I had to write some VBScript the other day and was able to whip it out in 15 minutes or so, but about 13 minutes of that was poking around the Microsoft Scripting docs.

I know there's a lot less difference between ASP.NET 2.0 and 1.0 than between classic ASP and ASP.NET, but nevertheless I find myself worrying that I won't be able to have a mastery of both versions like I know I will need. I'm concerned that as I learn and use ASP.NET 2.0 more and more that my ASP.NET 1.x skills will erode, where it will take twice as long to tackle some given ASP.NET 1.x task than it does now, and that's not fair to my clients. I don't mind change in the least - if I did I'd be in the wrong field - I'm just hoping that I can continue to thrive in the 1.x and 2.0 worlds simultaneously.

Software Engineering Thought for the Day
24 June 05 07:49 PM | Scott Mitchell | with no comments

I emailed the following tripe brimming over with run-on sentences to my wife yesterday:

There's something profoundly satisfying with completing some seemingly long task in under a minute after putting forth the time, effort, and energy to build a well-architected solution to enable such a quick turnaround. It's almost magical, because in constructing the architecture you see only your application's guts and then, once the foundation has been laid, you can go from no exterior to a fanciful fascade in such speed that it's nearly alarming how simple it was to move from absolutely nothing an end user could interact with to a complete end user experience.

THE MAGIC OF SOFTWARE ENGINEERING!

I don't know what's better - the fact that such a statement can lead to a thirty minute conversation between my wife and I, sharing experiences where we had experienced the “magic,” or the fact that my wife puts up with these trite platitudes that have about as much insight as the statement, “The government taxes too much.”

Filed under:
Update on My Small Claims Court Experience
23 June 05 01:08 AM | Scott Mitchell | with no comments

Last week I wrote a blog entry about a client that has yet to pay for work I completed half a year ago. Rather than just take my lumps and move on, as I have done in the past, I decided this time to take the matter to small claims court this time because:

  • The company that is not paying appears to be quite good and not paying a lot of people for some time now,
  • The people I have interacted with run me in circles, unanswered emails/voicemails, excuses galore, and rarely, if ever, what sounds like a sincere apologetic, “We're sorry, but we're having cash flow issues“ or something of that nature.
  • I'm interested in exploring the process, although hopefully I'll never need to do this again.

That blog entry last week generated some great ideas, tips, and suggestions from those who left comments. In fact, to answer a number of questions raised by those comments, I started a separate page here on my blog, My Small Claims Court Experience. That page serves as a master index to blog entries focusing on this small claims court experience as well as providing a short history of what led up to this decision. Additionally, I am filing these blog entries in the Going Independent category.

When I was teaching my class back in January of this year I saw and said hi to another instructor who was also teaching classes at the facility that day. I had recognized him from the courts not far from my home where I play basketball a couple times a week. Anyway, I ran back into him on the courts in late May and asked him if he had ever been paid for his services - not surprisingly, he hadn't. We talked a bit and it turns out his father is a lawyer and is in the early stages of taking this issue to superior court. Long story short, I gave him my phone number and asked to have his dad give me a ring.

On Tuesday of this week I had my completed small claims court papers in hand and was ready to make one, or maybe two, stops. I was first going to show up at the non-paying client's site with the papers in hand and a message along the lines of, “I'm off to file this, why don't you save yourself the hassle and cut me a check.” If they chose to continue their current course of action my next plan was to, naturally continue on over to the courthouse and file the paperwork.

However, as I was literally heading out the door the phone rang and it was the father of my basketball colleague. We talked, he basically gave me his status on the matter. In essenance, he's still in an exploratory stage, so he's not 100% certain if this thing will move forward to court or not, but he wanted to hear my story and discuss matters. In any event, I decided rather than rushing to small claims court I'd instead wait to see how this matter unfolds. (Don't know how long I'm going to wait on this... probably not too long, but I don't want to chose one option - small claims court - and not be able to take advantage of a better option that might open up further down the road.)

In any event, I was searching through old emails I received from the company using Google Desktop Search, and stumbled across one that had been sent to my Junk Suspects. It was a sort of “I'm leaving the company to pursue other interests, wish you all the best” from a person I had interacted with early on in my experience with this company. What was interesting was that rather than use Bcc, this person sent this email to about a dozen folks directly through the Cc line. Aha!, I thought, this must be a list of past insturctors!

So I quickly whipped up an email, Bccing it to this list of people, explaining my situation and asking anyone who had been an instructor and had not been paid to reply and let me know. Sent that out late Tuesday night and, as of tonight (Wednesday), I've heard back from four people who are in the exact same boat - taught one or more classes, haven't been paid, some from back as far as late 2004.

This company makes me ill. While they may have “cash flow” issues I think their manner of operation is immoral and repugnant. They clearly have hired several instructors and not paid them, and then hired several more, likely not planning on paying. This company just gives me negative vibes. I did a search on their corporation name with the California Secretary of State and found that over the last decade there have been three corporations formed by the same person with very similar names - like Acme Training, Ackme Training, and Acme Technology Group - over the past decade, a new one every few years. I imagine that what happens is a corporation is started up, it's run trying to make a profit, obviously, but ends up running up a lot of debt - such as promising to pay for instructor services renderd - and then, if things don't work out, they fold up shop just to create a new, similarly named corporation. (This guess as to their business practices may be heavily influenced by the bitterness of not getting paid and having to deal with these folks, of course.) Anyway, it's disgusting how they can do this to independent trainers and just stick 'em with no payment for their services. Of the instructors I've heard back from all have opted to just take the loss and move on.

Anyway, so that's where I'm at now, just thought I'd keep y'all updated. Thanks for reading...

A complete list of blog entries related to this topic can be found at My Small Claims Court Experience and through Going Independent category. Your feedback is most welcome - please leave a comment or drop me a line.

Filed under:
When a Client Won't Pay...
18 June 05 07:18 PM | Scott Mitchell | with no comments

Over the years I have worked on a number of consulting projects and had to put up with a “rotten apple” client on more than one occassion - one that might take an eternity to pay, or might bicker over the agreed upon price after they have received the services rendered and are staring at the invoice, or - worst of all - those that simply don't pay. Thanks to some excellent long-term clients, I am in the position now where I can be very conservative when accepting new jobs. Essentially, when working with a new client for the first time I will not do a lick of work that is not pre-paid. After I have worked with the client long enough to develop and build some trust, and after I have been paid a couple of times, on-time and without nickel and diming, I'll do work on a Net 15 or Net 30 basis. That has been my policy on consulting jobs for a couple of years now.

However, I have not seemed to learn my lesson in this matter with regards to my training services. Occassionally a technology training company will request my services to teach a class on their behalf. I've done this maybe a half-dozen times over the past few years. Anywho, it's never yet been a problem until recently when a local company failed to pay me for a three-day class I taught. It has now been over half a year since the services were rendered and I've yet to see a dime. I've gotten nothing but the run-around when trying to communicate with the company - being sent to voicemail, not getting returned emails or phone calls, being given a cacophony of excuses as to why I've yet to be paid.

When a client doesn't pay I am aware of three available options:

  1. Do nothing - just chalk up the experience, write off the loss on your expense sheet, and never do business with that client again. This is the easiest approach as it requires no action on your part, counts as income off the top at the end of the year, and can help teach a valuable lesson moving forward. However, you don't get paid, so that's a bummer.
  2. Sell the debt to a collection company - I've never done this but have talked to consultants who have gone this route. Essentially you sell what is owed to you to another company for pennies on the dollar and let them hassle the client for their money. This approach takes a bit more work than doing nothing, but not too much more, and you do get something. Problem is, you get much less than was owed, although I assume you can take the difference off your income sheet at the end of the year.
  3. Get a judgement against the client - that means take them to court and sue them for the money owed. This can, of course, be expensive and time consuming and might not yield any results, especially if the client can't pay because they simply don't have the cash. This route can be especially a hassle if they money owed exceeds the limits allowed for small claims court (hence necessitating hiring a lawyer) or if the client resides in another state or city.

In the past I have, without fail, always taken option #1. However, I have decided that with this latest client I am going to pursue option #3 for two reasons: first, and most importantly, this client seems very unethical. They claim that they have yet to pay me because of cash flow reasons, yet they've continued to operate their business for six months since payment was due. Furthermore, I have talked with a number of other instructors they have hired during various times (both before and after me) saying that they, too, have yet to be paid. This behavior makes me sick to my stomach. Second, and more trivially, I am curious about the whole small claims court process. I've never been to any sort of court matter before, so it will be interesting to observe and record the process and results.

Has anyone taken the small cliams court route before for a non-paying client? Any advice/recommendations/tips? Is it worth it or am I just wasting my time and energies chasing a few measely bucks that I likely won't see in the end anyhow? Thanks!

Maintaining an Audit Trail
17 June 05 12:26 PM | Scott Mitchell | with no comments

Have you ever worked on a data-driven application where it was essential all changes to the system's underlying data could be examined by an auditor at some later point in time? In medical, university, governmental, and, increasingly, corporate settings, it is becoming increasingly important for legal reasons that one can go back into the system and see precisely how the data changed over time and (most importantly) by whom.

If you've ever needed to create such an auditing application, what techniques have you used? When I've needed such functionality I've always done the following:

  1. For each database table X that requires an audit trail, create a table named XAudit that has the exact same schema as X but with four additional fields:
    1. XAuditID - a primary key, IDENTITY field
    2. Deleted - a bit field that defaults to 0 that indicates if the record has been deleted.
    3. CreatedOn - a datetime field that defaults to the current date and time (getdate()).
    4. CreatedBy - a field that records who changed the data. If you are having the users log directly onto the database to perform the edits, you can use the SUSER_SNAME() function to get the username. If you are having all users come through some standard account, you'll need to record this information in the X table so that it translates over smoothly to the audit table.

      Note: you may already be tracking the last time and user that changed a record's data, and therefore these last two fields would be captured in table X and therefore not need to be additional fields added to the audit table.
  2. Create a trigger on X for UPDATE and INSERT that inserts the contents from the inserted table into XAudit.
  3. Create a trigger on X for DELETE that inserts the contents from the deleted table into XAudit, putting in a value of 1 into the audit table's Deleted field.

That's all there is to it! At that point you have a complete audit trail showing creation, editing, and deletion of all records, including when the change was made and by whom.

If you keep an audit trail using a different technique, or if there's a better way than how I do it, I'd be interested in learning more - leave a comment.

Filed under:
How are Session IDs guaranteed to be unique?
15 June 05 10:53 PM | Scott Mitchell | with no comments

The other day I was reading Jeff Prosise's article Foiling Session Hijacking Attempts and it got me to wondering how, exactly, session IDs are chosen and how they are guaranteed to be unique. The last thing you want to have happen is multiple, unique visitors hitting your site and being assigned, by chance, the exact same session ID, for such a case would cause these two unlucky visitors to “share” session state.

Session hijacking is an attack where the attacker attempts to guess a valid session ID or “steals“ a valid user's session cookie. Jeff says that guessing a valid session ID is a pretty hard attack to successfully pull off with ASP.NET since the session ID is “a highly-random 120-bit ID.” If you check out the formal docs for ASP.NET Session State - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconsessionstate.asp - it says:

"Each active ASP.NET session is identified and tracked using a 120-bit SessionID string containing only the ASCII characters that are allowed in URLs. SessionID values are generated using an algorithm that guarantees uniqueness so that sessions do not collide, and randomness so that a malicious user cannot use a new SessionID to calculate the SessionID of an existing session."

My question is - how are the selected session IDs guaranteed to be unique? In using Reflector & poking around the code for the session state (specifically System.Web.SessionState.SessionId and System.Web.SessionState.SessionStateModule), I fail to see how the algorithm guarantees uniqueness.

The only method that calls SessionId.Create is SessionStateModule.BeginAcquireState, which doesn't appear to do any validation to ensure the session ID is unique. Am I missing something obvious here?

From my understanding, the session ID is generated by a cryptographically strong algorithm, but I'm not too familiar with the properties of such algorithms. I imagine they provide a stronger pseudo-random technique than non-cryptographically strong algorithms... maybe one of the properties of such algorithms is that it takes a really long time before there's a random number picked that has been picked before.

And, yes, I realize that 2^120 is a huge number, a number that, if written out, would be comprised of 36 digits... but still, I am wondering how no conflict in session IDs is guaranteed.

So....... does anyone know how this guarantee is made? Am I missing finding something in Reflector or do I just need to have a better understanding of cryptographically strong pseudo-random number generators? Any info most appreciated.

Filed under:
Tip: When Adding Dynamic Controls, Specify an ID
03 June 05 12:32 PM | Scott Mitchell | with no comments

One area where ASP.NET developers seem to have the most difficulty with is working with dynamic controls. This difficulty is understandable, as there are a plethora of subtleties in getting everything to work right. I've actually authored a number of articles on working with dynamic controls:

The other day I was talking to a colleague who was having some problems with dynamic controls. His site was designed as a single “master” page that had on it navigation controls (skmMenu, to be precise) and a PlaceHolder. Whenever a skmMenu menu item was clicked, this colleague was wanting to dynamically load in a corresponding user control into the PlaceHolder.

His first attempts at knocking this out was to do the following:

  1. In his “master“ page he had a method called LoadPageControls() that was invoked from the Page_Init event handler. This LoadPageControls() method looked at a Session variable - if the session variable was set to a user control path, that user control was loaded into the PlaceHolder (using Page.LoadTemplate(path)- see An Extensive Examination of User Controls for more info on dynamically loading user controls). If, on the other hand, the session variable was not set (such as on the first page load before the user had clicked an item from the skmMenu), a default user control was loaded.
  2. When a skmMenu menu item is clicked the MenuItemClicked event fires. This colleague then created an event handler for this event, set the Session variable to the menu item's CommandName property and recalled LoadPageControls(), thereby loading in the appropriate user control based on the menu item clicked. And since this information was saved in the Session, if the dynamically loaded user control caused a postback, for example, upon reloading the “master“ page the appropriate user control would be re-added, thereby remembering the user control to display across postbacks. (Side note: this information could have also been serialized to view state. I don't know if the Session option was chosen out of ignorance over using ViewState or if it was chosen because he wanted the user to be able to return to the “master“ page sometime later and have the last loaded menu item for that user brought back up. One issue with Session, though, is that this “master“ page will not work for those who have cookies disabled in their browser.)

This approach worked well, or so it seemed. The user could click a skmMenu menu item and its appropriate user control would be loaded up in the PlaceHolder. If the user control caused a postback - say it contained a Button Web control - even when the postback was invoked, everything worked as expected - the page was reloaded and the appropriate user control was displayed.

There was, however, one problem. One dynamically loaded user control contained an editable DataGrid. If a user clicked the Edit button in the DataGrid, nothing happened. If he clicked it a second time, the DataGrid row became editable. There was a one-click pause, so to speak. Setting a breakpoint in the code, my colleague was able to determine that the event handler wasn't being invoked until the second (and all subsequent) clicks.

Anytime you are working with dynamic controls and events seem to go missing, the first thing to do is a View/Source. View the rendered HTML of the page that's sent to the browser before you do the action that doesn't trigger the server-side event (but should), and compare it to the HTML of the page right before the action does trigger the server-side event. Specifically, pay attention to the IDs of the Web controls since its the ID is what is passed back during postback to indicate what triggered the postback...

When examining the HTML after the editable DataGrid was loaded the first time, the DataGrid's ID was something like _ctrl1_DataGridID. After clicking the Edit button (which did not make the row editable), the returned HTML differed in that the DataGrid's ID was now _ctrl0_DataGridID. Note the change from 1 to 0 in the ID. Since the ID differed from the first time the DataGrid user control was loaded to all subsequent postbacks, the event wasn't picked up that first time, when the ID was still in flux.

Once we had identified that this was the problem (as it usually is when missing an event once, but not in subsequent tries), the next step was to figure out why this was happening. The problem could be traced back to the chain of events that unfolded when the skmMenu menu item was clicked. When the “master” page is visited for the very first time, the LoadPageControls() method fires during the Init event and, since there is no Session variable set, the default user control is loaded. Now, when the skmMenu menu item to load the editable DataGrid is clicked, the page posts back and the LoadPageControls() method runs first, and it says, “Hey, I still have no Session variable,” so it loads the default user control. Then, later in the page lifecycle, the MenuItemClicked event handler runs, which sets the Session variable and then recalls the LoadPageControls() method, which says, “Ah, yes, here is this Session variable, let me load the associated user control.”

The problem is, the PlaceHolder has had two controls added to its Controls collection, hence the reason why we get the _ctrl1 in the DataGrid's ID! (This happened even though the PlaceHolder's Controls collection was Clear()ed each time the LoadPageControls() method was called...) When the Edit button was clicked for the first time, the page posted back and the LoadPageControls() method was called from the Init event. This time it said, “I do have a Session variable set, so let me add the DataGrid user control.“ Note that in this sequence only one control is added to the PlaceHolder instead of the two that were added in the previous page lifecycle. Hence we get the _ctrl0 in the DataGrid's ID the second (and all subsequent) times. Furthermore, in this lifecycle, the _ctrl1 ID was what was sent back in the post headers, so when the Page class can't tie the event that caused the postback back to the DataGrid, and that was why the DataGrid's Edit button wasn't firing the DataGrid's EditCommand event on the first click.

The solution? Simply give a specific, named ID to the user control being dynamically added. That is, my colleague's code, before this change, looked like (very rough, I'm leaving out the Session variable check):

PlaceHolderID.Controls.Clear()
Dim c as Control = Page.LoadControl(Session(”pathToUC”))
PlaceHolderID.Controls.Add(c)

Everything worked fine and dandy once the code was changed to:

PlaceHolderID.Controls.Clear()
Dim c as Control = Page.LoadControl(Session(”pathToUC”))
c.ID = “someStaticString“
PlaceHolderID.Controls.Add(c)

With that change, the DataGrid's ID was always the same thing, something like someStaticString_DataGridID. As you can see, working with dynamic controls can introduce all sorts of hard to find and diagnose subtleties. To be able to debug dynamic control scenarios, the following things are paramount:

  • Patience! :-) This is probably true for all debugging but moreso for debugging dynamic controls.
  • A solid, air-tight, profound understanding of the ASP.NET page lifecycle. You need to know what events fire when, what methods run in response, and what happens when controls are added to the control hierarchy mid-way through the page's lifecycle. Some articles worth reading for more information on this include:
  • A good understanding of the ASP.NET event model, and the ability to dig through the rendered HTML for a page and spot differences that may be causing problems.

Happy Programming!

Filed under:
More Posts

Archives

My Books

  • Teach Yourself ASP.NET 4 in 24 Hours
  • Teach Yourself ASP.NET 3.5 in 24 Hours
  • Teach Yourself ASP.NET 2.0 in 24 Hours
  • ASP.NET Data Web Controls Kick Start
  • ASP.NET: Tips, Tutorials, and Code
  • Designing Active Server Pages
  • Teach Yourself Active Server Pages 3.0 in 21 Days

I am a Microsoft MVP for ASP.NET.

I am an ASPInsider.