Working for Microsoft: Week 1

me Initially I was planning to blog every day or so about my experiences within Microsoft, but alas, this has been the first free moment I've had so far after my last post.  The reason?  Well, as I mentioned in a previous post, the first three weeks of my new career are spent at something called "MSSU" (Microsoft Services University).  This is affectionately referred to as "Boot Camp" by those in the know.  The boot camp analogy is not far from the truth, I must say.  Having never gone through boot camp in the traditional sense of the term, having never been in the armed services, I referred to a military site and realized  that it has been pretty close to my experience, thus far - Minus the disparaging drill sergeant type atmosphere.

Basically, the intention is to get us up to speed on Microsoft, the products, tools, etc. as fast as possible.  Most days start with a 7am shuttle ride to one of the campuses and then you are in class until sometime after 5pm'ish.  So, here's a few things I've learned in my relatively short tenure:

  1. Be Prepared to Eat Well - When I was in college, they had something they called the "Freshman 15".  Basically, in the first semester of college, you expect to gain about 15 pounds.  I think I am going to start the "Microsoft 15".  Every day, I am given 3 square meals.  Breakfast usually consists of eggs, bacon, etc.  Lunch is usually a trip to one of the many Cafeterias on campus.  You're usually on your own for dinner, but they have a lot restaurants within walking distance from the Apartments.  It has been years since I've consistently eaten 3 square meals.  I'm going to have to start hitting the gym while I'm here. IMG00086
  2. Be Prepared to Work - As I mentioned above - each day starts at 7am and goes late.  During that time, you will learn about the MS Products, the Tools available, the culture, etc.  Everyone pretty much uses OneNote to track all of the various information provided.  In the past, I would generally use a Text editor to take notes - but I have certainly started drinking the OneNote kool-aid.  It's a great tool and I wish I had had a license in my previous life.
  3. Take the Time to Socialize - It's not often I have gone through a training regiment where everyone is really intelligent.  Most people are smart, no doubt about that, but at a class like this - everyone is scary smart.  Part of this boot camp is meant to allow you to build relationships with other people in your position.  Chances are, you will be communicating with these same people throughout your career.  It really behooves you to get to know them and build those relationships now.  Every night, the other PFE's and I have gone out for drinks and dinner and the conversations have ranged from Exchange to .NET to Active Directory to Windows Server to BizTalk to SQL Server.  Everything is fair game and you will learn a lot about a ton of products during these informal conversations.
  4. Set up your Outlook Rules - As Scott Hanselman mentions here, one of the things that has amazed me so far are all of the e-mails that get sent around.  In my third day or so on the job, I opened up my inbox and had several HUNDRED e-mails there waiting for me.  Therefore, it was a necessity to starting setting up my Outlook rules and start the forwarding process into folders.  I'm sure as I get added to more and more lists, my rules list will get longer and longer.
  5. Start Making Redmond/Seattle Connections - During my first day at NEO, I got a call from a .NET PFE based out of Redmond welcoming me to the team.  Since there are few other .NET PFE's starting, he offered to go out for drinks one night to pick his brain.  I highly highly highly recommend doing this.  I learned more about the position and what challenges I will be facing during that few hour session than I did throughout the several week hiring process.  The bottom-line is that the culture of MS is to help your peers and other employees.  Truly incredible.IMG00091
  6. Explore the Campus - Although, you may not be located in Redmond, that doesn't mean you shouldn't take a walk around the campus and pop into the offices.  As part of a team building event yesterday we had to walk around the campus.  It was truly a great experience and I got to see the homes of teams that I've long followed as an external admirer.  For example, just imagine sitting in Bill Gates' old office in Redmond.  You get a real sense of history in certain areas.  Very cool stuff.

Honestly, I think most of these things can be applied to anyone starting a new job, but it just may be more prevalent in a MS field based role.

Overall, I've really enjoyed myself.  So far, this has been an incredible experience and I can't wait for the next 2 weeks.

Enjoy!

 

Technorati Tags: ,
Working at Microsoft: Day 1

Well, I have officially been in the Seattle area for about 24 hours.  My flight in was fine and yes, the weather was cold and rainy.  I'm very happy that I picked up a raincoat before I left. 

After arriving and checking into my long term housing, I took a walk around the area and ended up at a nice little bar and grille called 520 in Bellevue to catch the second half of the Bears game - and for once, the Bears didn't lose.  I consider that a good omen.

Here's a pic of my home for the next 3 weeks:

IMG00071

The view from the apartment:

IMG00080

The next morning, the other PFE's and myself took a nice shuttle ride from our housing to the Microsoft campus.  We knew we had arrived when we saw this:

IMG00077 IMG00078

The entire day was spent in New Employee Orientation.  The day was good, learning much about the company and the tools available to us as Microsoft employees.

This new stage in my career is finally beginning to feel real.  I expect it will feel even more so the longer I'm out here.

I'm still working on the samples for the SamuraiProgrammer.Web.UI - and I should have that up soon.

Enjoy!

Technorati Tags: , ,
Releasing the Source Code for .NET

I was just about to head to sleep when I read this great post by Scott Guthrie.  Apparently, Microsoft will be releasing the source code for the BCL (Base Class Libraries), ASP.NET, WinForms, etc. when .NET 3.5 and VS2008 (aka Orcas) is released later this year. 

I have to admit that I was looking forward to reading some of that code when I started my new gig over there next week.  Silly me, I considered it a perk for working over at MS <grin>.   

In any case, us developer type folk could always use Reflector to browse through the code, but the level of integration with the IDE (along the line of the Symbol integration) is really slick.  Plus, we get to see the comments in that code.  I know that they'll probably clean them up prior to release or maybe they won't.  I've seen some pretty wacky (and humorous) comments over the years, so I can only imagine the type of things in that code.

Some funny comments I've read that come to mind:

  • "It's late, I'm tired and this is as good as it's going to get."
  • "I know this shouldn't be hardcoded.  Leave me alone."
  • In a summary tag for a method:  "Blah blah blah"
  • I even recall someone that had pasted lyrics into their code comments.  Go figure.

Anyway, now I'm really off to bed.

 

Enjoy!

 

Technorati Tags: , , ,
Developers Love Their Tools...

Seriously, I think there are few things that Developers are more passionate about than the tools and toys they use to code.  Carl has compiled a great list of Free Visual Studio 2005 Addins.  You can read the list here

The addins that I use on a (almost) daily basis for VS 2005 are (in no particular order):

  • AnkhSVN
  • CodeKeep Add-in
  • GhostDoc 2.1.1 (wish there was a VB version of this one)
  • Modeling Power Toys
  • Pinvoke.Net Addin
  • Refactor! family of Addins
  • Smart Paster 1.1 (HUGE time saver)
  • Dpack

If you know of one that is not listed on Carl's blog, just drop a comment and he'll evaluate and add it.  Please be aware that I think he has a 15-20 addin backlog at this moment.

As Orcas (ahem, Visual Studio 2008) is right around the corner, I'd be interested to see a list of addins for that IDE.  Wishful thinking, but if you see a list - drop me a line.

 

Enjoy!

Giving XBOX Live a Chance

I am far from a hardcore gamer.  I don't log on and play for hours upon hours because well, I just don't have that much spare time to play.  It's a shame, but hey, that's life.  In any case, one thing that I've been meaning to do for years was sign up for an XBOX Live membership.  Several of my friends are avid gamers and have weekly Thursday night Halo battles (was Halo 2 and now it's Halo 3).  One of my closest friends has been trying to get me online for years to join them but I never took them up on it.

The main reason that I never signed up was because I simply didn't have any free ports on my Router.  I know that's a lame reason, but it's true.  I only had a 4 port router - with Wireless - but with a few servers, a few desktops and a laptop (or 2) in my home office my measly 4 ports were filled up pretty quickly.  And Yes, I could have purchased the XBOX 360 Wireless Netowrking Adapter but maybe I'm just old school in that I always worry about network lag when I'm wirelessly gaming.  I remember when I was first playing some online games on my PC back in the day (ie:  10 years ago), specifically Star Wars Jedi Knight: Dark Forces II, network lag was a big issue in the online component.  I would be having a heated Light Saber duel and my opponent would disappear for a second or two.  All of a sudden, he would reappear and I'd be dead having taken a Saber hit to my head.  Aaah, those were the days.  :: Sigh ::

Well, last night, since I was already at Micro Center picking up a new Hard Drive Enclosure, I stopped by the networking section and picked up a new 8 Port Router and a new 100 foot cable. I swear, Micro Center is a very very dangerous place for a geek to wander around within.  I went there looking to spend about $50 and left spending about 5 times that.  :: Grin :: 

In any case, once I was home, installation was a breeze - with one caveat.  Plastered all over the internal router were these stickers and labels saying "Run the CD before hooking up the router".  Skeptical, I did pop in the CD and found it to be a step by step guide on how to plug everything into your network from the perspective of the newbie.  What they should have said is - if this is your first router, then run the CD.  Oh well - what a waste of about 30 seconds of my time. 

After hooking everything up, the XBOX Live membership process was a breeze, although, I couldn't use "SamuraiProgrammer" as my handle (too many characters).  I had to settle for something else:

image

Yes, I realize that my Gamer Score is lame but in all fairness I played the heck out of my original XBOX and none of my achievements (nevermind that they didn't exist back then) carried over to my 360.  Feel free to add me to your list of friends and perhaps we can jam on some multiplayer Frogger one day. 

I do have a few tiny tiny nitpicks, though. 

1.  When you are online via the XBOX, you have a lengthy list of icons you can use to decorate your gamer card.  However, when you view your gamer card online - you have much fewer.  This means that if you pick an icon that is not on the XBOX Live site, your icon will default to the fella featured on the right.  It would seem to me that any icons they allow you to select from online should be available on the XBOX Live site.

2.  Points.  This was something my friend told me about last night.  Apparently if you choose to buy points in the store, they're sold in batches of 1600 or 4000 at about 80.04 points per dollar (USD).  If you buy them on the XBOX Live site or while you're in XBOX Live, they're sold in increments of 500/1000/2000/5000 at exactly 80 points per dollar.  So, if you discount tax and shipping/handling, it's actually cheaper to buy your points in a place like Best Buy instead of online. 

Like I said, though, those are just a few tiny tiny nitpicks.  Overall, the XBOX Live experience is really incredible!  It is truly much superior to the Wii and PS3 equivalent.  I can already tell that I'll be spending a lot more time playing my 360, which I guess is the whole point.

One last plug for Scott Hanselman, though.  He, Rich Claussen and Jason Mauer are hosting a Halo 3 tournament on October 20 as a benefit to raise money for Diabetes.  Since I'll be out that way for my MS Bootcamp during this time, I'm going to try and show-up.  But if you are in Vancouver, WA and would like to meet some MS guys and play Halo 3 on a 50 foot screen in Super Hi-Def, check out his blog entry and sign-up. 

Enjoy!

 

Posted 30 September 07 11:08 by Greg | 0 Comments   
Filed under
The Road Not Taken

"...Somewhere ages and ages hence:
Two roads diverged in a wood, and I--
I took the one less traveled by,
And that has made all the difference."
                                 -- Robert Frost

You may have noticed that I've been more quiet than normal for the past month or two.  There is a reason for that.  I have decided to leave my current company of almost 4 years for another opportunity.  Starting Monday, October 8, 2007, I will be a full time employee of Microsoft on the Premier Field Engineering team!  If you're not familiar with this position at Microsoft, the description on the Microsoft Careers site states:

"The purpose of the Premier Field Engineer (PFE) position is to provide Microsoft customers with reliable technical solutions to the complex integration problems associated with business solutions built on the Microsoft platform. The PFE Team supports a diverse variety of technical solutions built with Microsoft technology and products Typical tasks performed in this role include specific problem isolation and correction, user and kernel mode debugging, conducting application design and supportability reviews, performance tuning, application stability consulting/troubleshooting, code reviews, and porting/migration assistance, configuration management, pre-rollout testing and general development consulting. The prospective PFE candidate should draw upon all resources at Microsoft, to advise and consult on the use of Microsoft technologies to avoid such problems in the future."

This position immediately appealed to me because of its customer focus and technically challenging environment.  Plus, I get to help developers do their job better!  That alone is a great high for me and I'm really looking forward to this new adventure!  From speaking with members of my new team and my future manager, I can tell that this team is composed of incredibly intelligent folks and I am honored to be joining them.

All that said, though, this decision was far from easy for me to make.  I have had the distinct honor to work with some wonderful folks at my current company.  Plus, I was able to architect and design some great applications.  In the end, though, I knew that I had to take the road "less traveled by" and join a company that is constantly changing the world.

Here's a quick FAQ on the process and my new position:

  • Do you have to move? 

    Nope.  I get to stay in good ol' Chicago for the time-being.  Even better, I get to work from home when I'm not at a client site.
  • Wait, does that mean you don't get to go to Redmond at all? 

    Well, actually, I do.  For all folks in this arm of Microsoft's service group, your first three weeks are spent in Redmond at a bootcamp.  This is where I'll get wonderful things like my ID badge, laptop and learn all about the Service leg of MS.
  • How did you find out about the job?  How did you apply, interview, etc.?

    Well, one of my friends sent me a link to the initial Job Details page saying that it might be a good fit for me.  After that, it was just a matter of signing up on the MS Careers site and submitting my resume.  This was the first time that I had ever applied to Microsoft before, so I wasn't entirely sure what to expect.  Pretty soon after I officially applied, though, I received an e-mail from an Recruiter over there and everything kind of snowballed from there.  All in all, the process took just over a month, from initial communication to the Offer stage.  I probably could have shortened that time-span, but I wanted to provide adequate time to prepare for each interview.
  • What were the interviews like? 

    Well, my interview came in three stages:

    1.  HR phone interview.  This was there the Recruiter got to tell me about the position, the company, normal tasks, etc.  He also asked some fairly basic .NET questions.

    2.  Technical Screen.  This was an hour-long phone conversation with an incredibly sharp guy.  The questions were NOT easy, in-fact, this was probably the most difficult tech screen I have ever encountered.  They were simply not interested in how you develop a webpage, but instead asked some really difficult questions about garbage collection, the JIT compiler, and loads of .NET memory related questions.  We also got into some Windbg debugging and memory dumps.  Certainly not for the faint of heart.

    3.  In-Person Technical Interview and Managerial Interview.  This was about 2 hours long at one of the local MS offices and included a technical interview with 2 PFE's and a managerial type interview with 2 PFE Managers.  The technical interview included more of the same types of questions mentioned above but also included some best practice-type questions about Exception Handling and debugging issues.  The managerial interview included a lot of behavioral questions and also about how you manage difficult situations. 
  • How did you prepare for them?

    I took a page from Jayson Knight's blog and studied my little heart out.  My average was about 4 hours every night studying everything I could find and then some.  I re-read several books and tons of great blogs.
  • What's going to happen to your blog?

    For the time being, I'm planning to keep it updated, but the focus may change a bit.  As my new position will include a lot of deep technical dives into some great technologies - the focus may be a bit more deeply technical in nature.  As I have always tried to keep the focus on simplifying development, though, expect more of those same types of entries.
  • How did management at your current company take the news?

    Honestly, their reaction surprised me.  LOL...in a good way, I suppose.  They didn't even try to keep me.  As soon as I said "Microsoft" their eyes lit up and they offered their congratulations and gave me many hearty handshakes and hugs.  They all knew that this was a dream for me and it's nice to know that they were as happy for me as I was.  It was truly a testament to the wonderful and supportive folks that they employ.

All in all, I feel very fortunate to have been given this incredible opportunity.  I can't wait to start my new adventure!


 

Posted 27 September 07 11:33 by Greg | 0 Comments   
Filed under ,
SamuraiProgrammer.Web.UI - v0.5

One of my friends suggested that I should provide a download for all of the little code snippets, controls, etc. that I throw up on my blog so people don't have to constantly copy/paste into their IDE of choice. 

I thought about it and it sounded like a good idea but I think I'll do things a little bit different.  I fully intend to provide code downloads for each of my blog entries, but in addition to that, I'm going to expand upon them in a separate download.  The reason for this is that many times, I post very very simple solutions to common problems or issues.  I always leave it as an exercise for the reader to further enhance the simple code I provide. 

I like the way this works, but a lot of times I do the enhancing myself.  So, I might as well make that code available as well.  In this initial release (arbitrarily set as v0.5), I provide the following controls:

  • ValueCheckBox - This was a control that I described here and is simply a CheckBox with an additional property (CheckBoxValue) that can be used in a grid/list/anywhere where you want to store an actual useful value for quick reference later.
  • ConditionalDisplayPanel - This was a control that I initially described here and was a simple way to hide portions of a templated control from the user at runtime.  Since its first creation, though, I've actually enhanced this quite a bit.  Using something similar to the GridView/SQLDataSource binding model, I have made this control a lot more flexible and extensible. 

    When you add this control to your page, you can specify in your XHTML a SuccessTemplate and a FailureTemplate.  Within each template, as with most templated controls, you can specify the controls/HTML to appear for each condition.  For example:
    <sp:ConditionalDisplayPanel 
                   runat="server" ID="cdpTest" 
                   EvaluationSourceId="cesCustomCheck">
        <FailureTemplate>
            <asp:Label runat="server" 
                       ID="lblFailure" 
                       Text="Failure"></asp:Label>
        </FailureTemplate>
        <SuccessTemplate>
            <asp:Label runat="server" 
                       ID="lblSuccess" 
                       Text="Success"></asp:Label>
        </SuccessTemplate>
    </sp:ConditionalDisplayPanel>
  • EvaluationSource - In order to provide looser coupling between the uses of this control and the control itself, these simple controls provide a nice abstracted method of providing the condition for which the FailureTemplate and SuccessTemplate appear.  All EvaluationSource controls implement the IEvaluationSource interface which provides a method of evaluating success or failure.  The EvaluationSources included in this release are:

    RoleEvaluationSource:  Provides a method to evaluate against a user's role membership.
        <sp:RoleEvaluationSource runat="server" 
                                 ID="resRoleCheck" 
                                 RoleName="Test">
        </sp:RoleEvaluationSource>
    FieldEvaluationSource:  Provides a method to evaluate against a a null or empty field value in a DataView.
    <sp:FieldEvaluationSource runat="server" 
                              ID="fesAttributeName" 
                              FieldName="AttributeName">
    </sp:FieldEvaluationSource>
    CustomEvaluationSource:  Allows the developer to specify their own logic to be evaluated.
        <sp:CustomEvaluationSource runat="server" 
                                   ID="cesCustomCheck">
        </sp:CustomEvaluationSource>
    Then, in the code behind, you simply handle the CustomValidate event raised in the control to provide your own logic to evaluate.
        Protected Sub cesCustomCheck_CustomValidate( _
                                ByVal source As Object, _
                                ByVal args As CustomValidateEventArgs) _
                                        Handles cesCustomCheck.CustomValidate
            args.IsValid = True
        End Sub
  • ControlPersister - This allows you to specify the values in one or more controls on a page and save them to a cookie when a certain event is raised by another control on the page.  In addition, the control will place the values back into the controls when the user next visits that page.  An example of the XHTML would be useful here perhaps:
    <sp:ControlPersister runat="server" 
                         id="fpSearchFields" 
                         PersistenceKey="Search" 
                         PersistenceTypeName="cookie">
        <Sources>
            <sp:ControlSource ControlName="txtSearchCriteria" 
                              ControlProperty="Text" 
                              Name="SearchCriteria1" 
                              Type="String" />
            <sp:ControlSource ControlName="ddlSearchCriteria2" 
                              ControlProperty="SelectedValue" 
                              Name="SearchCriteria2" 
                              Type="String" />
            <sp:ControlSource ControlName="chkSearchCriteria3" 
                              ControlProperty="Checked" 
                              Name="SearchCriteria3" 
                              Type="Boolean" />
        </Sources>
        <SaveTriggers>
            <sp:SaveTrigger ControlId="btnSearch" 
                            Name="SearchButton" />
        </SaveTriggers>
        <ResetTriggers>
            <sp:ResetTrigger ControlId="btnReset" 
                             Name="ResetButton" />
        </ResetTriggers>
    </sp:ControlPersister>

    Here is an explanation of each property on the base ControlPersister control:

    PersistenceKey:  A string value representing the name of the cookie for this page.  This is useful if you have more than one ControlPersister on a page.

    PersistenceTypeName:  A string value representing the medium in which these values should be stored.  For this version of the control, only a "cookie" is available.  In future versions, you will be able to store the values in Session, Database or even using a File Based persistence model.

    Here is an explanation of each property on the ControlSource object:

    ControlName:  A string value representing the name of the control to persist.

    ControlProperty:  A string value representing the property of the control from which you should persist the values of the control.  This property is also used to *set* the value of the property on the initial page load.

    Name:  A string value representing the name of the instance of the ControlSource.

    Type:  A string value representing the type of data to be stored.

    Here is an explanation of each property on the SaveTrigger object:

    ControlId:  A string value representing the name of the control that would trigger the save operation of this control.  The control referenced here must implement the IButtonControl interface which exposes the Click event.

    Name:  A string value representing the name of the instance of the SaveTrigger.

    Here is an explanation of each property on the ResetTrigger object:

    ControlId:  A string value representing the name of the control that would trigger the reset operation of this control.  When the user clicks this button, any values being persisted would be cleared and would not load the next time the page loaded.  The control referenced here must implement the IButtonControl interface which exposes the Click event.

    Name:  A string value representing the name of the instance of the ResetTrigger.

I think that's it for this version of the SamuraiProgrammer.Web.UI.  You can download the assembly here.  I'll try to get some samples posted within the next week or so.

Any questions or comments, please feel free to comment or contact me via the link on this page.

Enjoy!


String Concatenation

This is an old topic, but as I work with developers more and more, I find that there is still some gray area on this topic.

Concatenating strings is probably one of the most comment tasks that most developers perform in their work-lives.  If you've ever done some searching around, though, you'll find that there are 2 main ways that people perform those concatenations:

First, you can use the "+" or the "&" operator with the native string object:

    Sub ConcatWithStrings(ByVal max As Int32)
        Dim value As String = ""
        For i As Int32 = 0 To max
            value += i.ToString()
        Next
    End Sub

Second, you can use the System.Text.StringBuilder() object to perform the concatenation:

    Sub ConcatWithStringBuilder(ByVal max As Int32)
        Dim value As New System.Text.StringBuilder()
        For i As Int32 = 0 To max
            value.Append(i.ToString())
        Next
    End Sub

So, which is better?  Well, if you do any Google'ing or Live Search'ing on the topic, you'll find some great articles on the topic.  Mahesh Chand has a great article, which I'll quote:

"You can concatenate strings in two ways. First, traditional way of using string and adding the new string to an existing string. In the .NET Framework, this operation is costly. When you add a string to an existing string, the Framework copies both the existing and new  data to the memory, deletes the existing string, and reads data in a new string. This operation can be very time consuming in lengthy string
concatenation operations."

Now, I'm a big fan of short descriptions like the above, but I always find that without actually showing what is happening behind the scenes, you might lose some folks in the translation.  To illustrate what happens behind the scenes, I wrote a quick console application that uses the first code sample - and then took a memory dump using ADPlus to show what actually gets kept around in memory after the String level concatenation.

I'm not going to go into a lot of detail on what I did to mine through the memory dump, but if you're interested in getting down to this detail on your own - I highly recommend the book Debugging Microsoft .NET 2.0 Applications.  After you read that great book, you should read Tess's Great Blog to get even more practice on this area.

In any case, what was uncovered after the memory dump was that with the listing in the first example, there will be a separate String object placed into memory each time you perform a concatenation.  Here is an excerpt from that dump:

#         Size Value

1           28 "0123"
1           28 "01234"
1           32 "012345"
1           32 "0123456"
1           36 "01234567"
1           36 "012345678"
1           40 "0123456789"
1           44 "012345678910"
1           48 "01234567891011"
1           52 "0123456789101112"
1           56 "012345678910111213"
.....
1          124 "0123456789101112131415161718192021222324252627282930"
1          128 "012345678910111213141516171819202122232425262728293031"
1          132 "01234567891011121314151617181920212223242526272829303132"
1          136 "0123456789101112131415161718192021222324252627282930313233"
1          140 "012345678910111213141516171819202122232425262728293031323334"
1          144 "01234567891011121314151617181920212223242526272829303132333435"
65       17940 ""012345678910111213141516171819202122232425262728293031323334353"

First, the command I used outputs the first 65 characters or so within the String object.  This is why the last entry has a count of 65 instances.  In any case, as you can see, there is a separate copy of each string made into memory during each concatenation operation.  Ouch.  This can get expensive very quickly! 

Now what about the StringBuilder operation?

#    Size    Value

1    52    "0123456789101112"
1    84    "01234567891011121314151617181920"
3    956  "012345678910111213141516171819202122232425262728293031323334353"

Gee, that seems a lot simpler - but if you're paying attention, you'll notice that there are a few other instances of this lengthy string in memory.  Any ideas why? 

Well, this appears to be my bug.  When you instantiate a System.Text.StringBuilder object, one of the constructors allows for a integer parameter called "Capacity".  If you do not specify an initial capacity, the noargs constructor defaults to "&H10" - which is 16 characters.  If, during your string operations, you exceed that 16 character capacity, the StringBuilder will create a new new string with a capacity of 32 (16 * 2) characters.  The next time, you perform an operation that needs more than 32 characters, the StringBuilder will double the capacity again - this time to 64 characters.  This will continue to happen over and over again as you continually append more characters to the StringBuilder object.

So, what does this mean?  Well, it means that we're still not achieving the maximum efficiency here.  If we want to build a String like this - without creating extra instances of the base string object - even when using a StringBuilder object, you should specify a capacity in the constructor.  To prove this hypothesis, we can rewrite the second code listing to be:

    Sub ConcatWithStringBuilder(ByVal max As Int32)
        Dim value As New System.Text.StringBuilder(193)
        For i As Int32 = 0 To max
            value.Append(i.ToString())
        Next
    End Sub

Now, when we take a memory dump and look for the String objects for the above loop:

#   Size  Value

1   404  "012345678910111213141516171819202122232425262728293031323334353"

We see that there is only one instance of the String object in memory. 

Moral of the story?  Even when using the StringBuilder object, if you know the final string is going to be lengthy, you should set an initial capacity to most efficiently perform your string concatenations.

Enjoy!

 

Visibility of Fields Within FormView

A quick trick that I'm sure many of you know.  Suppose you had a FormView on a page bound to a datasource.  Within that FormView, you have several fields that may or may not contain data.  Now, suppose that for whatever reason, your sponsor would like you to make a control and its label disappear if the corresponding field contained no data.  What are the different ways to achieve this simple requirement?

  1. You can handle the DataBinding event of the FormView and set the visibility of controls in the depending upon a field's value. 
  2. You can set the Visible property of the controls based upon a method defined in your page's code behind.  Possibly something like this:
    Public Function ShouldDisplay(ByVal text As Object) _
                                                    As Boolean
        If text Is DBNull.Value OrElse _
            String.IsNullOrEmpty(text.ToString.Trim) Then
            Return False
        Else
            Return True
        End If
    End Function

And then you can set the visible property of the controls like this:

<asp:Label ID="Label" 
           runat="server" 
           Visible='<%# ShouldDisplay(Eval("Description")) %>' 
           Text='<%# (Eval("Description")) %>'>
 </asp:Label>

3.  You can combine #1 and #2 and encapsulate this into something a little reusable.

Enter the ConditionalDisplayPanel.  This is something very simple which has potential to save you time over and over again.  To show how it works, here is the definition of a simple FormView control before applying the logic from above:

<asp:FormView ID="FormView2" 
              runat="server" 
              DataKeyNames="AttributeId" 
              DataSourceID="SqlDataSource1">
    <ItemTemplate>
        AttributeId:
        <asp:Label ID="AttributeIdLabel" 
                   runat="server" 
                   Text='<%# Eval("AttributeId") %>'>
       </asp:Label>
       <br />      
       AttributeName:
       <asp:Label ID="AttributeNameLabel" 
                  runat="server" 
                  Text='<%# Bind("AttributeName") %>'>
       </asp:Label>
       <br />
    </ItemTemplate>
</asp:FormView>

Now, in this example, suppose you don't want to display the AttributeName text or Label if there is no data in the AttributeName field in the datasource.  In that case, you simply wrap the AttributeName HTML with the ConditionalDisplayPanel like so:

<asp:FormView ID="FormView1" 
              runat="server" 
              DataKeyNames="AttributeId" 
              DataSourceID="SqlDataSource1">
    <ItemTemplate>
        AttributeId:
        <asp:Label ID="AttributeIdLabel" 
                   runat="server" 
                   Text='<%# Eval("AttributeId") %>'>
        </asp:Label><br /> 
        <sp:ConditionalDisplayPanel runat="server" 
                                    ID="pnlAttributeName" 
                                    FieldName="AttributeName">        
            AttributeName:
            <asp:Label ID="AttributeNameLabel" 
                       runat="server" 
                       Text='<%# Bind("AttributeName") %>'>
            </asp:Label>
            <br />
        </sp:ConditionalDisplayPanel>   
    </ItemTemplate>
</asp:FormView>

Please note the FieldName property on the ConditionalDisplayPanel.  This property tells the ConditionalDisplayPanel which field should be evaluated to determine if the contents of the control should be displayed.  At runtime during the binding of the controls in the FormView, the ConditionalDisplayPanel will evaluate the contents of that particular Field and if there is any data in the field, it will display the AttributeName HTML.  If not, then the opposite will happen.

Simple, no? 

Well, how does this work?  Actually, the ConditionalDisplayPanel was relatively simple to construct.  Here is the full class:

Namespace WebControls
    Public Class ConditionalDisplayPanel
        Inherits Panel

        Private _fieldName As String

        Public Property FieldName() As String
            Get
                Return _fieldName
            End Get
            Set(ByVal value As String)
                _fieldName = value
            End Set
        End Property

        Private Sub ConditionalPanel_DataBinding( _
ByVal sender As _
Object, _ ByVal e As _
System.EventArgs) _ Handles Me.DataBinding '// The naming container here (in a bindable context) '// implements the IDataItemContainer Dim container As IDataItemContainer = _ DirectCast(Me.NamingContainer, _
IDataItemContainer) '// Using the property of that container, '// DataItem, you can get at the DataRowView being bound. Dim row As Data.DataRowView = _ DirectCast(container.DataItem, _
Data.DataRowView) '// Retrieve the value from the row. Dim value As Object = row(Me.FieldName) '// Perform the comparison and set the Visible
'// Property Accordingly.
If value Is DBNull.Value OrElse _ String.IsNullOrEmpty(value.ToString.Trim) Then Me.Visible = False Else Me.Visible = True End If End Sub End Class End Namespace
By using this simple control, you can control this situation in one place for your entire application.  It could obviously be enhanced to perform many other checks, but as this was a 15 minute thing, I thought it would be best to keep it simple.

I hope this helps!

Enjoy!

ConfigurationFileWather?

Just something I thought was a bit funny/interesting.  I was debugging someone's code earlier today and I happened to glance down at my threads in VS and noticed this:

image

Any idea of what caught my eye?   Yup -  the text that says:  "_ConfigurationFileWatherThread".   After switching to the thread, I noticed that the mistype is actually in the Enterprise Library v3.0 code, in the class called Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Storage.ConfigurationChangeFileWatcher.  The method is called "BuildThreadName" and is:

        protected override string BuildThreadName()
        {
            return "_ConfigurationFileWatherThread : " + configFilePath;
        }

Since I was working with v3.0, I checked in v3.1 to see if the "bug" was fixed.  Unfortunately, looking at the released source for v3.1 - it was not fixed.  I know this is really picky, but I even went so far as to open an issue.  <sigh>.

In any case, it's nice to know that nobody is perfect. 

 

Technorati Tags: ,
Posted 30 August 07 08:40 by Greg | 0 Comments   
Filed under ,
Scott Hanselman's Ultimate Tool List

Scott has posted his wonderful Ultimate Tool list for 2007.  A lot of the great tools that I use on a daily basis were introduced to me via his previous lists.  With a lot of the apps, you don't know what you were missing until you fire up one of them. 

In any case, pop on over and check out the list.  Well worth the visit.

I especially enjoy:

  • Memory Profiler
  • Snippet Compiler
  • Synergy (essential if you have more than one PC)
  • Notepad2
  • DiskView
  • Refactor!

And oh so many more....

Maybe I'll take some time and profile the apps that I use on a daily basis.

Enjoy!

 

Technorati Tags: , ,
Posted 27 August 07 07:53 by Greg | 0 Comments   
Filed under , ,
Outlook and Lotus Notes

About a year ago, my company (a large holding company) decided to standardize all of their sub-companies on a single e-mail platform.  Since we are a holding company, each sub-company essentially used their own messaging software.  In the US, that meant that we were converting from Novell Groupwise (a very thin e-mail software) to another platform.  After a lengthy RFP process, that platform became IBM's Lotus Notes.  Keep in mind, I like certain aspects of the collaboration platform.  The Lotus Sametime application is really quite nice as a web conferencing platform and the application/workflow software for developers is pretty slick too.  That said, though, my main complaint is that the desktop Client incorporates the UI for all of these features.  This makes the actual Lotus Notes client quite a behemoth in terms of a HDD footprint and a bit of a hog of system resources.  So much so, that I oftentimes use the Web Client to monitor e-mail/schedule meetings/etc. throughout the day. 

It always surprised me that IBM never released a Notes Thin Client - which only did things like e-mail and calendar.  In any case, a friend of mine was trying to configure MS Outlook to work through Lotus Notes last Thursday and could not figure it out.  Well, I figured that Pop3 probably wouldn't be the way to go as you get no actual synchronization between Notes and Outlook that way.  After digging around a bit today, though, I found the wonderful Outlook 2003/2002 Add-in:  Notes Connector.  From the download page:

"Outlook Connector for IBM Lotus Domino enables you to use Outlook 2003 or Outlook 2002 to access your e-mail messages, calendar, address book, and To Do (task) items on an IBM Lotus Domino Release 5.x or Release 6.x server."

Under the covers, this add-in provides a full MAPI driver for Lotus Notes that uses your Notes ID file to communicate with the Domino servers.  It's actually a fairly brilliant solution to the problems mentioned above. 

In any case, I was up and running with Notes and Outlook in just a few minutes after finding this excellent article giving step-by-step instructions on how to install the addin and set it up.  I highly recommend reading it and following the steps (especially the one "Uninstall Microsoft Hotfixes").  I'm sure there are some snafu's with the add-in, but after about 5 hours of using it (so far), I haven't run into any.  If I do, though, I'll make sure to post the problem and solution.

Enjoy!

 

Technorati Tags: ,
Posted 26 August 07 09:59 by Greg | 0 Comments   
Filed under
GridView Grouping and Checkbox Lists

I was helping a co-worker today with one of his screens and realized that it may make a useful little tutorial for all those other folks out there.  This was somewhat interesting because it follows up pretty well on my previous post as I talk about saving records with a 1 to many relationship.  Basically, he needed to develop a screen similar to the following:

image

This is actually a pretty simple page, but there are a few places that might cause a hiccup or two:

  • Grouping items in a checkbox list.
  • Getting the value for each Attribute (ie:  the PK of the Attribute itself)

For the first item - grouping inside of a checkbox list.  This actually won't work - there is no way to specify groups of checkboxes or additional properties to define checkboxes or any of that...so, the only real option is to put the checkboxes into a GridView control.  Now, I've done this type of grouping many times previously and it never really felt right.  After Googling the problem with him - "grouping items in a gridview" - the first result is a great series of classes posted here.  The only problem with this method is that it is focused on grouping within reports.  The difference in this situation is that we wanted the checkboxes to maintain their state between postbacks.  If you perform a postback using the article's method, then not only will your checkboxes lose their state (kinda sorta) but the Header row for each group will disappear. 

Then, I happened to recall something similar written by Matt Dotson and his use of cell-spanning to accomplish a similar feat.  He has a great blog entry posted here to illustrate the concept.  In-fact, he also has a great CodePlex project here that has a bunch of useful "Real World" ASP.NET webcontrols in it.  One of these useful controls is a GroupingGridView.  This is essentially a GridView to perform the actual Grid Grouping.  By default, using Matt's sample, the GridView renders like this:

image

And the XHTML to output this simple page is:

<rwg:GroupingGridView ID="GroupGrid" DataSourceID="PubsDataSource" 
                    AutoGenerateColumns="False" GroupingDepth="2"
                    DataKeyNames="au_id" runat="server">
    <Columns>
        <asp:BoundField HeaderText="State" DataField="state" />
        <asp:BoundField HeaderText="City" DataField="city" />
        <asp:BoundField HeaderText="Last Name" DataField="au_lname" />
        <asp:BoundField HeaderText="First Name" DataField="au_fname" />
        <asp:BoundField HeaderText="Phone" DataField="phone" />
        <asp:BoundField HeaderText="Address" DataField="address" />
        <asp:BoundField HeaderText="Zip Code" DataField="zip" />
        <asp:CheckBoxField HeaderText="Contract" DataField="contract" />
    </Columns>
</rwg:GroupingGridView>

Nice, clean and simple - and it gets us most of the way there.  Instead of actually displaying the grouped items in the center of the cell, though, we needed the Group text to display at the top of the cell.  This is a very simple change to his source code (available on the CodePlex site).  In fact, it's only 1 additional line of code in his SpanCellsRecursive method (see the marked line below):

        private void SpanCellsRecursive(int columnIndex, 
                                        int startRowIndex, 
                                        int endRowIndex)
        {
            if (columnIndex >= this.GroupingDepth 
                    || columnIndex >= this.Columns.Count )
                return;

            TableCell groupStartCell = null;
            int groupStartRowIndex = startRowIndex;

            for (int i = startRowIndex; i < endRowIndex; i++)
            {
                TableCell currentCell = this.RowsIdea.Cells[columnIndex];

                bool isNewGroup = (null == groupStartCell) || 
                    (0 != 
                        String.CompareOrdinal(currentCell.Text, 
                                            groupStartCell.Text));

                currentCell.VerticalAlign = VerticalAlign.Top;
                if (isNewGroup)
                {
                    if (null != groupStartCell)
                    {
                        SpanCellsRecursive(columnIndex + 1, 
                                           groupStartRowIndex, i);
                    }

                    groupStartCell = currentCell;
                    groupStartCell.RowSpan = 1;
                    groupStartRowIndex = i;
                }
                else
                {
                    currentCell.Visible = false;
                    groupStartCell.RowSpan += 1;
                }
            }

            SpanCellsRecursive(columnIndex + 1, groupStartRowIndex, endRowIndex);
        }

Now that gets us the Grouped items in a GridView for our pretty display.  Just using that wonderful GridView gets us a page that looks like this:

image

With only this small amount of code in the XHTML:

    <RWC:GroupingGridView runat="server" ID="GroupingGridView1" 
                AutoGenerateColumns="False" 
                GroupingDepth="1" 
                ShowHeader="False">
         <Columns>
            <asp:BoundField DataField="GroupName" ShowHeader="False" /> 
            <asp:TemplateField>
                <ItemTemplate>
               <asp:checkbox runat="server" 
                             id="checkbox1" 
                             Text='<%# Eval("AttributeName") %>'
                 Checked='<%# DirectCast(Eval("ParentId"),Int32) > 0 %>'
/> </ItemTemplate> </asp:TemplateField> </Columns> </RWC:GroupingGridView>

And then you just bind this grid behind the scenes:

    Protected Sub Page_Load(ByVal sender As Object, _
                            ByVal e As System.EventArgs) _
Handles Me.Load If Not IsPostBack Then Dim attributeList As _ System.Collections.Generic.IList(Of Attribute) attributeList = Me.GetAttributes() With Me.GroupingGridView1 .DataSource = attributeList .DataBind() End With End If End Sub

Now, from a look and feel perspective - we're just about done.  But what about getting the values out of the checkbox - so that we know:

  1. Whether the checkbox was selected.
  2. What the value of the checkbox is - ie:  the primary key of the Attribute object.

The checked property is relatively simple to get out of the page.  In the Submit button's event, you loop through the rows in the GridView and extract out the instance of the Checkbox for each row and then check the "Checked" property of the checkbox to determine if the checkbox is selected:

For Each row As GridViewRow In Me.gvGrouping.Rows
  If row.RowType = DataControlRowType.DataRow Then
    Dim obj As CheckBox = _
         TryCast(row.FindControl("chkbxPermissions"), _
                                CheckBox)
    If obj IsNot Nothing Then
        Response.Write(String.Format("Row {0}: checked value is {1} <br>", _
             row.RowIndex.ToString, obj.Checked.ToString))
     End If
  End If
Next

Now this will write to the page the RowIndex and a value indicating whether the checkbox was checked.  This will not, though, give me the AttributeId for these checkboxes because the ASP.NET 2.0 Checkbox Control does not have actually have a "Value" property like it does in a CheckBoxList control.  So, what do we do?  Well, there are two solutions:

  1. Use the DataKeyNames property of the GridView to specify that the AttributeId is our key for this GridView and then extract it from the row.
  2. Create a new CheckBox control that will include a new property to hold the Checkbox's Value.

Given the two options mentioned above - there are no real differences.  The actual size of the page is EXACTLY the same and the speed to access the GridView's DataKey property versus a new property on a new CheckBox control is no different.  I'm choosing to go with the latter as I know of a few other situations where a control like this might come in handy. 

So, since it is not already there - let's create a new control that derives from the existing CheckBox control.  We'll call this new control a ValueCheckBox control and add a new property:

Namespace WebControls
    Public Class ValueCheckBox
        Inherits CheckBox

        Public Property CheckboxValue() As String
            Get
                Return DirectCast(ViewState("checkboxvalue"), String)
            End Get
            Set(ByVal value As String)
                ViewState("checkboxvalue") = value
            End Set
        End Property
    End Class
End Namespace

Then, we add the new Register tag to the top of our page:

<%@ Register TagPrefix="sp" Namespace="WebControls" %>

And then slightly change our XHTML to include a reference to the new checkbox in our GridView:

<RWC:GroupingGridView runat="server" ID="gvGrouping" 
                AutoGenerateColumns="False" 
                GroupingDepth="1" 
                ShowHeader="False">
         <Columns>
            <asp:BoundField DataField="GroupName" ShowHeader="False" /> 
            <asp:TemplateField>
                <ItemTemplate>
                    <sp:ValueCheckBox runat="server" 
                       ID="chkbxPermissions" 
                       Text='<%# Eval("AttributeName") %>' 
                       Checked='<%# DirectCast(Eval("ParentId"),Int32) > 0 %>' 
                       CheckboxValue='<%# Eval("AttributeId") %>' />          
                </ItemTemplate>
            </asp:TemplateField>                               
        </Columns>
</RWC:GroupingGridView>

Lastly, you tweak your submit button code-behind to get at the new control:

        For Each row As GridViewRow In Me.gvGrouping.Rows
            If row.RowType = DataControlRowType.DataRow Then
                Dim obj As WebControls.ValueCheckBox = _
                    TryCast(row.FindControl("chkbxPermissions"), _
                                WebControls.ValueCheckBox)
                If obj IsNot Nothing Then
                    Dim checked As Boolean = obj.Checked
                    Dim checkboxValue As String = obj.CheckboxValue
                End If
            End If
        Next

And now you're done.  My previous post discusses the best way to store these values, so I won't go into that level.

Enjoy!

 

Technorati Tags: ,
One-to-Many: What is the best way to store the values?

If you've been a developer for any period of time, you have probably come across this question.  If you're given a one-to-many relationship in a table, what is the best way to insert those values into a database.  For example, let's say that you had a Person table and an Attribute table.  Each person can have more than one attribute associated with them, hence the 1-to-Many relationship.  Your database diagram is probably something that looks like this:

bs_1_to_many_relationship

So, if given a Person and a list of Attributes for that person, what is the best way to insert rows into the PersonAttributeXref table?  Well, if this is the first time that you've done something like this, you probably came up with something like this:

  1. Create a Stored Procedure that accepts a UserId and AttributeId value and then insert one row into the PersonAttributeXref table. 
  2. For each Attribute selected, you simply loop through them and call out to that Stored Procedure once for each item you would like to insert.

So what is wrong with this method?  Not a whole lot if you are only inserting a few (1 to 3) rows into the PersonAttributeXref table.  However, when inserting more than those few rows into the table, you will begin to notice a performance hit.  Why?  Well, if you are using something like the Enterprise Library to perform your inserts, your code probably looks a little something like this:

Public Sub InsertAttribute(ByVal userId As Int32, ByVal attributeId As Int32)
     Dim db As Database = DatabaseFactory.CreateDatabase()
     Using dbCommand As Common.DbCommand = _
           db.GetStoredProcCommand("USP_BS_INSERT_PERSONATTRIBUTEXREF")

        db.AddInParameter(dbCommand, "@UserId", DbType.Int32, userId)
        db.AddInParameter(dbCommand, "@AttributeId", DbType.Int32, attributeId)

        Try
             db.ExecuteNonQuery(dbCommand)
        Catch ex As SqlClient.SqlException
            '// Insert error handling here.
        End Try
    End Using
End Sub

The problem with something like this is that each time you call out to this method, a new connection is established with the database and the insert is then completed.  The act of establishing a connection out to the database is very expensive - even using Connection Pools.  In-fact, during some tests that I ran locally, if you are calling out to this method 100 times - it will probably take you in excess of about 937,500 ticks to complete the transaction.  You also don't have the option of rolling back the rows inserted if something fails.

Well, chances are, you've probably noticed this issue and have tried to overcome it a variety of ways.  In-fact, the next thing that I've seen people try is to concatenate the attributeId's into a delimited string and then pass that string to a single stored procedure:

        Dim attributeIdList As New System.Text.StringBuilder()
        For i As Int32 = 1 To MAXINSERTS
            If attributeIdList.Length > 0 Then
                attributeIdList.Append(",")
            End If
            attributeIdList.Append(i.ToString)
        Next

And then in the Stored Procedure, you perform the String parsing using a simple UDF like that which you can find here and then you perform the insert there - all wrapped in a nice little transaction.  If you have done something like this successfully, you have probably seen transaction times somewhere in the neighborhood of 625,000 ticks for 100 inserted rows.  Wow!  That's a nice a performance boost, right?  Yes, it is - however, I've always been a firm believer that the SQL Server is no place to be concatenating and splitting strings.  Just because you can do it, doesn't mean it should be done.  In-fact, I'd argue that splitting strings and concatenating strings makes your procedure a lot less supportable than performing similar actions in .Net code. 

Faced with these two options, I'm likely to propose a third option.  In .NET, though, you have the option of using Transactions (feel free to look here or here or even here for a description).  Transactions in .NET work the same way as Transactions in SQL.  Basically, you wrap one or more operations in a Transaction and if all operations succeed, then the transaction is committed; if one or more fail, then you Roll it back.  In the context of this example, though, how would it work?  Well, assuming you have an array of AttributeId's, your code would probably look like this:

Public Sub InsertAttributeWithTransaction(ByVal userId As Int32, _
                                          ByVal attributeIdList As Int32())
     Dim db As Database = DatabaseFactory.CreateDatabase()
     Using dbCommand As Common.DbCommand = _
            db.GetStoredProcCommand("USP_BS_INSERT_PERSONATTRIBUTEXREF")

         db.AddInParameter(dbCommand, "@UserId", DbType.Int32, userId)
         db.AddInParameter(dbCommand, "@AttributeId", DbType.Int32, -1)

          Using connection As Common.DbConnection = _
                                    db.CreateConnection()
              connection.Open()
              Dim transaction As Common.DbTransaction = _
                                    connection.BeginTransaction()
              Try
                  For i As Int32 = 0 To attributeIdList.Length - 1
                       dbCommand.Parameters("@AttributeId").Value = _
                                                    attributeIdList(i)
                       db.ExecuteNonQuery(dbCommand, transaction)
                  Next
                   ' Commit the transaction
                   transaction.Commit()

              Catch ex As Exception
                  ' Rollback transaction 
                   transaction.Rollback()
               End Try

               connection.Close()
           End Using
       End Using
 End Sub

As you can see, this is pretty nice and straight-forward.  You instantiate the connection, create the transaction, process the inserts and then depending upon the result of the operations, you either Commit() or Rollback() the transaction.  So, what is the benefit of this?  Well, aside from the obvious readability (and consequently supportability) improvements - you also get a speed improvement too!  In-fact, for the same 100 rows that I inserted previously using the first or second approach, the total time to complete the transaction here is between 156,250 ticks and 312,500 ticks.  That compared with with the 937,500 ticks in option 1 and 625,000 ticks in Option 2 - represents an incredible speed improvement - and that's only for 100 rows.  Which, I'd imagine, is the high-end in UI defined cases.

If anyone has experienced issues with using .NET transactions or performance foibles, I'd love to hear about them.  Please feel free to either comment here or e-mail me at greg at samurai programmer dot com.

 

Technorati Tags: , , , ,
Input Validation

It seems that I always appear to run into this issue when performing code reviews.  As has been well documented in various locations on the web - all input is evil, until proven otherwise.  Some people attempt to mitigate this risk by providing dropdowns or calendar controls to coach our users into entering the right values.  While this works often, it is still coaching the users and should not be seen as a replacement for solid validation of the user entered data.

For example, imagine you have a textbox control on a page that is supposed to accept a Date value.  To "coach" the users into entering an appropriate value, you provide a calendar popup control.  Now, when the data has been posted back to the server to be stored in the database, do you:

A)  Assume that because we have given the users a calendar popup control, their input will be exactly as you might expect.

B)  Perform some additional validation that the textbox has a value entered.  If there is a value, assume that it is entered correctly.

C)  Imagine that there really isn't that calendar aid and validate the input as if it were entered entirely by hand by the users themselves.

If you answered "C", congratulations, you are correct.  The fact is, although we provide those wonderful entry "aids" to assist our users, they will never guarantee correct input.  Here is the wrong way to do it:

Dim dateValue as DateTime
dateValue = Date.Parse(me.txtDateInput.Text)

What happens if the Date Input textbox comes across as an empty string?  You will get a big fat exception.  Now, in .Net 1.1, there were certain methods that you would code to validate input - or if you were using VB, you could use one of the methods in the wonderful Microsoft.VisualBasic namespace.  In .Net 2.0, though, there is a wonderful additional method to each one of these primitive objects....  "TryParse(....)".

This is really a great little method that takes as input 2 parameters:

1.  String representing the value to parse.

2.  DateTime/Integer/etc. representing where to store the final value - if the input could be parsed. 

The great thing about this method is that it will actually return a boolean value if it could successfully parse the value.  Therefore, using this new method, the code above could be amended as follows:

Dim dateValue as DateTime

If Date.TryParse(me.txtDateInput.Text, dateValue) Then
    '// Input is valid.  You can use the dateValue 
    '// variable safely.
Else
    '// Input in NOT valid.  Please direct the user to 
    '// enter a value correctly.
End If

Really powerful!  Here's another example - using values obtained from a QueryString as the offending code:

        Dim id As Int32 = -1
        If Request.QueryString("id") IsNot Nothing Then
            id = Int32.Parse(Request.QueryString("id"))
        End If

This looks good, right?  It does - and it might even function correctly about 70% of the time.  What about that other 30%, though?  What happens if a user decides to mess around with the QueryString values?  Instead of a number, they decide that it should be a text value instead.  Exception!  Using the TryParse(...) methods, though, you can do something nice and easy like this:

        Dim id As Int32 = -1
        If Not Int32.TryParse(Request.QueryString("id"), id) Then
            '// Notify user of invalid querystring value.
        End If

This is nice, clean and efficient - plus, it has the added bonus of handling the situation where the QueryString ID value returns nothing. 

Really powerful! 

These are just the basics on input validation (and I can go o