March 2008 - Posts

Don't miss the Nova Code Camp South this weekend!
Friday, March 28, 2008 8:34 AM

The NoVa CodeCamp South v1 will be held on March 29th 2008 in Woodbridge VA.  The speaker schedule has been posted here.

 

I am presenting two sessions:

9:00-10:15:     Refactoring in C#

1:00-2:15:        Web Application Testing in Watin

Register now!

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

Can you find the bug in this code? (THE FIX)
Wednesday, March 26, 2008 12:30 PM

Thanks to everyone for contributing!  It was really neat to read everyone's ideas and see the discussion and review (talking about code is always fun!).  Here is a summary of responses and the "fixed" code. 

If you are interested in the original problem, go here.

 

@drakiula: The idea with the Response.Redirect is that it will stop processing so the else is not needed on line 23.

@JV: Yes, this code could definitely be refactored! :)
And your suggestion would squish the bug.

@rajbk: Nice. Yes, the ThreadAbortException is definitely part of the bug but I don't think the Redirect(url, false) is the best way to go.

@Basgun: Changing line 17-23 as you suggest would make it cleaner but wouldn't fix the bug.

@cibrax,Lee:  Nice. Yes, the ThreadAbortException will cause the catch to fire everytime and redirect the user to the same page.

@Thomas Eyde: Nice. Yes, the refactoring into separate responsibilities would make it much cleaner and also would somewhat inadvertently fix the bug since the redirect would happen outside the catch.

@Zack Jones:  Nice suggestions.  Thanks!

@Hosam Kamel: Yes, good point - there are several ways those method calls could fail (lots of encryption and authentication done within them) so the catch is there as a simple default "then send them here".

Summary:

If you call Response.Redirect(string) or Response.Redirect(string, true), it will throw a ThreadAbortException.  So if you do the redirect inside a generic try/catch then your catch will fail everytime.  As pointed out by several people above, the code could be refactored so the responsibilities are separated out - this means that the Redirect should probably only be done in one place which would mitigate the issue.

I was surprised to see that Response.Redirect throws this exception especially since this exception is not thrown up the Application_Error event so some "magic" must happen within ASP.NET to issue the HTTP location header but not allow the exception to continue as a real exception.  This seems like a misuse of exceptions since a Response.Redirect is hardly an "exceptional" case and in many applications happens somewhere on every page!
That said, it is reasonable to see how Microsoft uses this mechanism to prevent further execution in the page.

Either way, it is a good gotcha to remember!

Here is the "fixed" code:  (although this could still be seriously refactored)

01: private void Page_Load(object sender, EventArgs e)
02: {
03: string redirectUrl = null;
04: try

05: {

06:     AuthenticationInfo authenticationInfo = GetAuthenticationInfo(Request.QueryString["t"]);

07:     Authenticator authenticator = new Authenticator(new LoginProvider());

08:     AuthenticationStatus authenticationStatus = authenticator.Authenticate(authenticationInfo);

09:     if (authenticationStatus.Authenticated)

10:     {

11:         IUser user =

12:             BLUser.Load(authenticationInfo.UserName, authenticationInfo.OrganizationCode, aut
henticationInfo.DomainId);

13:         user.SetNewSessionId();

14:         AuthenticationTokenParser authenticationTokenParser = new AuthenticationTokenParser();

15:         string authenticationToken = authenticationTokenParser.Create(user.UserName, user.OrganizationId,

user.DomainId);

16:         FormsAuthentication.SetAuthCookie(authenticationToken, true);

04:         redirectUrl = FormsAuthentication.GetRedirectUrl(authenticationToken, true);

04:     }

16: }

17: catch

18: {

19:     // If anything goes wrong (encryption error, etc) then just let it fall through to the redirect.

20: }

21: if (redirectUrl == null || redirectUrl.Trim().Length == 0)

22: {

23:     redirectUrl = "~/Home.aspx";

24: }

25: // NOTE: If you do the Redirect inside the try/catch it will get a ThreadAbortException!

26: Response.Redirect(redirectUrl, true);

27: }

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

For once, not blogging wasn't my fault
Tuesday, March 25, 2008 8:09 AM

For the last couple of days, the weblogs.asp.net website has been unable to accept posts from Windows Live Writer.  For the first time in the history of this blog, I can blame someone else for not posting.  In fact, I even started queueing up draft blog posts! :)

Kudos to the weblogs.asp.net team for fixing the issue quickly.

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

by thycotic | with no comments
Filed under: ,
Can you find the bug in this code?
Tuesday, March 25, 2008 8:04 AM

This is a real bug that I came across yesterday in some code I had written about a week before.  I was a little surprised at the mechanics but it makes sense once you understand what is happening ...

   1:  private void Foo()
   2:  {
   3:      try
   4:      {
   5:          AuthenticationInfo authenticationInfo = GetAuthenticationInfo(Request.QueryString["t"]);
   6:          Authenticator authenticator = new Authenticator(new LoginProvider());
   7:          AuthenticationStatus authenticationStatus = authenticator.Authenticate(authenticationInfo);
   8:          if (authenticationStatus.Authenticated)
   9:          {
  10:              IUser user =
  11:                  BLUser.Load(authenticationInfo.UserName, authenticationInfo.OrganizationCode, authenticationInfo.DomainId);
  12:              user.SetNewSessionId();
  13:              AuthenticationTokenParser authenticationTokenParser = new AuthenticationTokenParser();
  14:              string authenticationToken = authenticationTokenParser.Create(user.UserName, user.OrganizationId, user.DomainId);
  15:              FormsAuthentication.SetAuthCookie(authenticationToken, true);
  16:              string redirectUrl = FormsAuthentication.GetRedirectUrl(authenticationToken, true);
  17:              if (redirectUrl == null || redirectUrl.Trim().Length == 0)
  18:              {
  19:                  redirectUrl = "~/Home.aspx";
  20:              }
  21:              Response.Redirect(redirectUrl, true);
  22:          }
  23:          Response.Redirect("~/Home.aspx");
  24:      }
  25:      catch
  26:      {
  27:          Response.Redirect("~/Home.aspx");
  28:      }
  29:  }

 

I will post the answer soon if no-one gets it. :)

 

Jonathan Cogley is the CEO and founder of Thycotic Software, a .NET consulting company and ISV in Washington DC.  Our product, Secret Server is a enterprise password manager system for teams to secure their passwords.  Is your team still storing passwords in a text file?

Learning from your Burn Down chart
Tuesday, March 18, 2008 12:36 AM

image

The chart to the left represents the Burn Down chart for the Secret Server 4.1 release which shipped on March 14th 2008.  We have always shipped Secret Server on the published date (or in the early hours of morning the next day!) but this release pushed things a little too close for our liking.  What was the problem?  Did we take on too much?  Did we trade off scope like we are supposed to?

Looking at the Burn Down we can see that our velocity was really low in the early stages of the release.  This was mostly due to some support issues that drained our development resources and also some staff shuffling on projects which lead to inefficiencies.  We were able to make up for this with a phenomenal increase in velocity in the final iterations.  Unfortunately this was achieved by using more team resources to accomplish the tasks.  While the increased velocity is good, it also means there was a greater rate of change in the codebase at a point where quality assurance was trying to stabilize the product.  Test Driven Development certainly helps by allowing us to lean on our regression suite of tests but it is still not ideal.

So what went wrong?  We will be having a recap meeting later this week to determine how to improve our planning for future releases. We need to get back on track to our usual release schedule where we are ready for the actual release days before the release date (not bad for a small team with frequent releases!).  I think part of the problem was not planning properly for reducing scope.  We left one of the larger features of the release until the end (the Role Based Security feature) - then we didn't recognize that this feature could be thinned out to reduce scope but rather implemented most of the originally specified functionality. 

image

Typically our team cannot easily change resources (cost) since most team members are committed to projects and cannot easily shift responsibilities.  We also can't change the date since customers are expecting a release on a particular date because sales and support have been giving this date out for a few weeks.  This only leaves scope as the final equalizer to make timely releases possible.  In future, we will need to be more careful to ensure that scope can always still be reduced if necessary.

What does your Burn Down Chart tell you?

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

Please question the need for whitespace
Tuesday, March 18, 2008 12:02 AM

I have blogged about this before but I think it is a common problem that is worth restating since it affect developers across our industry.  I noticed the following method recently and again the curious separation of sections by whitespace popped into my head:

   1:  private void CalcHeaderOffsets()
   2:  {
   3:      this.fs = new FileStream( assemblyPath, FileMode.Open, FileAccess.Read );
   4:      this.rdr = new BinaryReader( fs );
   5:      dos_magic = rdr.ReadUInt16();
   6:      if ( dos_magic == 0x5a4d )
   7:      {
   8:          fs.Position = 0x3c;
   9:          peHeader = rdr.ReadUInt32();
  10:          fileHeader = peHeader + 4;
  11:          optionalHeader = fileHeader + 20;
  12:          dataDirectory = optionalHeader + 96;
  13:          // dotNetDirectoryEntry = dataDirectory + 14 * 8;
  14:   
  15:          fs.Position = peHeader;
  16:          pe_signature = rdr.ReadUInt32();
  17:          rdr.ReadUInt16(); // machine
  18:          numDataSections = rdr.ReadUInt16();
  19:          fs.Position += 12;
  20:          optionalHeaderSize = rdr.ReadUInt16();
  21:          dataSections = optionalHeader + optionalHeaderSize;
  22:   
  23:          sections = new Section[numDataSections];
  24:          fs.Position = dataSections;
  25:          for( int i = 0; i < numDataSections; i++ )
  26:          {
  27:              fs.Position += 8;
  28:              sections[i].virtualSize = rdr.ReadUInt32();
  29:              sections[i].virtualAddress = rdr.ReadUInt32();
  30:              uint rawDataSize = rdr.ReadUInt32();
  31:              sections[i].fileOffset = rdr.ReadUInt32();
  32:              if ( sections[i].virtualSize == 0 )
  33:                  sections[i].virtualSize = rawDataSize;
  34:   
  35:              fs.Position += 16;
  36:          }
  37:      }
  38:  }

What is the purpose of the new lines at 14, 22 and 34?  Are these separate blocks of logic?  Could they be better represented using "Extract Method"?

One of the first things that I do with code when refactoring is remove all the line breaks and make sure I am comfortable with the logical flow of the code.  If lines don't logically flow together then I ask myself if the two pieces belong next to each other or if they should be different responsibilities in different methods.

Ask yourself next time you leave a new line whether it is really necessary or is it a codesmell indicating poorly separated unrelated functionality?

FYI:  The code above is taken from NUnit (AssemblyReader.cs) and is free software licensed under the NUnit license (Copyright 2007, Charlie Poole, http://nunit.org/?p=license&r=2.4).

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

Subversion Logins Utility - selectively remove authentication data
Saturday, March 15, 2008 5:42 PM

Subversion keeps your saved authentication data in a folder on your local workstation.  On my Windows Vista laptop, this folder is C:\Users\jcogley\AppData\Roaming\Subversion\auth\svn.simple.  In this folder, you will find some cryptically named files - one for each Subversion repository authentication information that you have saved.  Using TortoiseSVN you have the option to "Clear Authentication Data" which will clear all saved authentication data.  In most scenarios, that is probably fine - but if you work frequently onsite with customers this can be a pain since the only way to clear the auth data for a sensitive repository is to clear the auth data for everything or remember the directory to go digging around in to find the right file to delete.

This itch finally got scratched for me last week and I wrote a simple utility to show the saved logins and allow you to delete them one at a time.

subversionlogins

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

Secret Server 4.1 goes live!
Saturday, March 15, 2008 12:56 PM

The team thinks it should be 5.0 since the new features were pretty huge! :)  The full release notes are here.  The new version includes role based security which allows you to slice and dice the access to various features across your organization.  We also have a new feature that allows you to automatically launch Remote Desktop from a secret which is very convenient. 

We have also had interest from many customers about "hardening" their Secret Server installation so there is a new "hardening" report which gives a pass/fail for various features that will make security tighter.  This is really the classic tradeoff between security and convenience.

hardening 

"Simply put, it is possible to have convenience if you want to tolerate insecurity; but if you want security, you must be prepared for inconvenience."
- General Benjamin W. Chidlaw

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

NoVa CodeCamp South v1 speaking schedule has been announced!
Friday, March 07, 2008 11:48 PM

novacodecampsouth The NoVa CodeCamp South v1 will be held on March 29th 2008 in Woodbridge VA.  The speaker schedule has been posted here.

I will be presenting on two topics:

  • Refactoring in C# - bad code to better code
  • Web Application Testing in Watin

There are lots of great sessions from WPF, TDD, SSIS, jQuery, SQL Server 2008 and more...

You can register now.

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

Refactoring in C# at RockNUG this week
Friday, March 07, 2008 10:35 PM

I will be giving a presentation on Refactoring in C# at RockNUG on Wednesday March 12th 2008 at 6:30pm.  Directions here.

What could be more fun on a Wednesday evening than critiquing some bad code and making it better? :) Come along to learn how to clean code like the Thycotic team. What do we look for? How do we take small steps to keep it working? What tips and tricks make it easier? This session will be code, code and more code (and a few unit tests of course!).

Picking over some code and discussing it is so much fun.  Come along and join us ...

 

We are hiring!  Do you want to write beautiful code in a Test Driven, Refactored, Agile .NET software company in the heart of Washington DC and work on cool products
Take the code test and send your resume along with why you want to join Thycotic to
tddjobs@thycotic.com.

More Posts

This Blog

Syndication