Come to GANG next week!

Next week, our local user group (GANG) is having Jason Beres -- INETA Speaker and Director of Product Management for Infragistics -- come and talk about building applications with Silverlight 2.0.  I'm really looking forward to this one since I haven't had time to dive into Silverlight myself.  Come on down to Microsoft's Southfield, Michigan offices on Wednesday, May 21st at 6:30pm.

PS: Sorry about the GANG website -- it's a little plain right now.  We're in the middle of re-working the website and should have the new one up before next weeks meeting.

Posted by psteele with no comments

The Elder will be back!

Keith Elder will be back in Michigan next month for the Lansing Day of .NET!  This is great news.  Keith is a great presenter and is always entertaining and informative.  I've submitted a couple of abstracts myself.  Even if I don't present, I'll still be there.

Keep watching the site to see what other great speaker speakers will be sharing their expertise at this FREE all-day event.

Posted by psteele with no comments

Lazy Loading/Eager Loading

The NHibernate FAQ has a new post about complex object graphs and lazy loading.  If you use NHibernate (or, ActiveRecord -- which makes NHibernate a whole lot easier), it's worth a look.  The technique described can greatly improve the way your app interacts with the database.  OR mappers are nice, but you need to make sure you understand what is happening with the database calls that are made automatically by your OR framework.

If you're using ActiveRecord, here's a few more items regarding lazy loading:

Enabling Lazy Loading in ActiveRecord

Tuning ActiveRecord

Combating the Select N + 1 Problem In NHibernate

Posted by psteele with 1 comment(s)

Navigating around in the VS.NET IDE

Last week, Bill Wagner and I were providing some C# training for one of our clients.  Bill showed the class how to use F12 to jump to the definition of a method.  One of the students asked how to go back to your previous position and Bill didn't know the key binding off hand.

As someone who comes from a VB6 background, I've maintained my VB6 keyboard mappings since I moved to C# in 2003.  Navigating around inside the VS.NET IDE has been a no-brainer for me since all of the keystrokes I used for the 7 or 8 years of VB development are the same in VS.NET -- assuming you use the VB6 keyboard layout.

I decided to see if C# has a default key binding to jump back to your previous positions after jumping to a method definition using F12.  First off, I wanted to see what IDE command is mapped to my "go back" function.  I pulled up the VS.NET IDE keyboard options, clicked on the "Press shortcut keys" texbox and hit the keyboard keystroke I use for jumping back to my previous position (Ctrl+Shift+F2):

 image

Looking in the "Shortcut currently used by" field, I see "View.NavigateBackward" is the command used in the IDE to navigate back to your previous position.  Now I changed my keyboard mapping scheme to C# and entered "View.NavigateBackward" into the "Show commands containing" field:

image

So I see control and "-" (minus) is the keystroke to jump back in C#.  I changed my IDE settings to use C# and tested this out.  Sure enough, I can use F12 to jump to a method definition and then ctrl+- to return to my previous position -- sort of like having my own little callstack within the IDE.  :)

And now I've changed my settings back to VB6 mapping scheme since I'm a creature of habit!

Posted by psteele with no comments

LINQ: Deferred Execution

Another interesting tidbit I learned about at the summit was deferred execution of LINQ queries.

Here's an example that highlights what deferred execution means to you.   Let's create a Customer class and then build up a list of customers:

   1: public class Customer
   2: {
   3:     public int ID { get; set; }
   4:     public string Name { get; set; }
   5:     public double Balance { get; set; }
   6: }
   1: static List<Customer> GetCustomers()
   2: {
   3:     return new List<Customer>()
   4:     {
   5:         new Customer {ID = 1, Name="Bill", Balance = 22.50},
   6:         new Customer {ID = 2, Name="Bob", Balance = 0.00},
   7:         new Customer {ID = 3, Name="Joe", Balance = -5.00}
   8:     };
   9: }

Now assume we're going to run a query to find all Customers whose first name begins with a particular letter (supplied in a variable):

   1: var customers = GetCustomers();
   2:  
   3: string firstLetter = "B";
   4: var query = from c in customers
   5:             where c.Name.StartsWith(firstLetter)
   6:             select c;
   7:  
   8: firstLetter = "J";
   9: foreach (Customer c in query)
  10: {
  11:     Console.WriteLine(c.Name);
  12: }

What do you think prints out?  Due to deferred execution, the application will only print "Joe", not "Bill" and "Bob" as you might expect.

The code executed in line 4 only builds the query into a query expression tree.  And that expression tree includes a reference to the "firstLetter" variable, not its contents.  The expression tree is not executed until line 9 when a foreach loop is used.  As a result, the value of the "firstLetter" variable is not obtained until line 9.

So be careful how you use locally-scoped variables in your LINQ queries and be aware of deferred execution in LINQ queries.

Posted by psteele with no comments

Extension Methods: Behind the scenes

One of the sessions I was able to attend (and talk about) at the MVP Summit involved some of the new features of C# 3.0.  My day job still has me doing a lot of C# 2.0 stuff so I haven't dived in too deeply to the new 3.0 stuff.  This was my opportunity to get the information directly from the C# language PM Mads Torgersen.  One thing I found interesting was how extension methods were implemented.

If you're not familiar with extension methods, here they are in a nutshell (and simplified): Extension methods allow you to add new methods to existing classes -- classes that you don't have source code access to and can't recompile with the new method.  In reality, you're not truly adding new methods, but the IDE experience makes it look that way so it flows very nicely.

First, let's look at how we'd tackle a problem without extension methods.  We have a simple Customer class.  I've used C# 3.0's auto-properties to allow me to quickly define the class:

   1: public class Customer
   2: {
   3:     public int ID { get; set; }
   4:     public string Name { get; set; }
   5:     public double Balance { get; set; }
   6: }

Now let's create a list of customers since we're going to iterate over them later:

   1: static List<Customer> GetCustomers()
   2: {
   3:     return new List<Customer>()
   4:     {
   5:         new Customer {ID = 1, Name="Bill", Balance = 22.50},
   6:         new Customer {ID = 2, Name="Bob", Balance = 0.00},
   7:         new Customer {ID = 3, Name="Joe", Balance = -5.00}
   8:     };
   9: }

Note that in the GetCustomers code above I'm utilizing C# 3.0 property initializers too to make this demo simple and concise.

Now we get to the meat of the problem.  First off, we're assuming that the Customer class is in another DLL that we don't have source code for it.  We'd like to know which customer's are delinquent, i.e. a balance less than zero.  It would be easy to simply loop through and check the Balance property, but we'd need that check everywhere we look for a delinquent customer (reports, inquiries, lookups, etc...).  And what if our client decided to change the definition of "delinquent" (for example "a balance less than -10.00)?  We'd have to change that balance check everywhere.  Instead, we'll create a utility method for this (since we can't simply add it to the Customer class):

   1: public static class MyExtensions
   2: {
   3:     public static bool IsDelinquent1(Customer c)
   4:     {
   5:         return c.Balance < 0;
   6:     }
   7: }

(You'll see why I called it "IsDelinquent1" and not simply "IsDelinquent" shortly).  We created a static class and created a utility method that will tell us if a customer is "delinquent" (based on our client's current definition).  Now let's do a quick check to find delinquent customers:

   1: private static void Method1()
   2: {
   3:     var customers = GetCustomers();
   4:  
   5:     foreach (Customer c in customers)
   6:     {
   7:         if (MyExtensions.IsDelinquent1(c))
   8:         {
   9:             Console.WriteLine(c.Name);
  10:         }
  11:     }
  12: }

Pretty simple.  However, it is a little verbose.  Let's now look at how we can utilize extension methods to make this cleaner.

We go back to our static "MyExtensions" class and add our extension method.  It's important to note that extension methods can only be defined in static classes that are contained directly in a namespace (i.e. not a nested class).

   1: public static bool IsDelinquent2(this Customer c)
   2: {
   3:     return c.Balance < 0;
   4: }

This looks almost exactly like the first method (the code block is identical).  We've simply added the "this" keyword at the beginning of the parameter list (before the "Customer" reference).  This tells the C# compiler (and the VS.NET IDE) that "IsDelinquent2" is an extension method on "Customer" since it appears right before a Customer parameter.  That's the only difference!

Utilizing this extension method makes the loop code much cleaner and easier to read:

   1: private static void Method2()
   2: {
   3:     var customers = GetCustomers();
   4:  
   5:     foreach (Customer c in customers)
   6:     {
   7:         if (c.IsDelinquent2())
   8:         {
   9:             Console.WriteLine(c.Name);
  10:         }
  11:     }
  12: }

Very nice!

Now the reason I've got static code all over this demo is because you can take all of the code, slap it into a VS2008 Console application and compile it (make sure the MyExtensions class is not nested within the default "Program" class).  Now fire up ILDASM and look at the decompiled IL for both "Method1" and "Method2" (I named them differently so you could compile them together and examine the differences).  You'll see that the IL code is exactly the same, byte for byte.  That's because extension methods are not a CLR addition, they are a C# addition.  They're a neat "macro" that the C# compiler automatically does for you.

It's a pretty neat implementation and can make interaction with external libraries a bit easier.  And if you're wondering, yes, the extension methods are listed as a method directly on the class with Intellisense.  They get a slightly different icon (I wasn't able to capture it with my screen capture utility) and the tooltip for the method in Intellisense has "(extension)" at the beginning of the method name.

Posted by psteele with no comments

Adding Action Filters to MonoRail Controllers

Neal Blomfield made interesting use of MonoRail filters.  Check it out.

Filters are commonly used for tasks like authentication and localisation, however by default they run for all actions in the controller and you must specify which actions to exclude using the [SkipFilter] attribute. In a majority of cases this works well as the filter is designed to handle cross-cutting concerns (which by definition affect most if not all actions), however there are times when you want to apply the filter to a minority of the actions in a controller, or add action specific metadata that may vary the way the filter executes depending on the action. Recently I came across just such a scenario…

Posted by psteele with 1 comment(s)

Sessionless MonoRail Controllers

I saw this post on the Castle Users mailing list and thought it was interesting and I wanted to post it.

By default, MonoRail controllers assume that ASP.NET session state is enabled.  If you disable ASP.NET's session state inside web.config, you'll get an exception when MonoRail tries to process the request.  What you need to do in this situation is to add a ControllerDetails attribute to your controller and set "Sessionless = true".  Thanks to Roelof Blom for posting a quick solution.

Posted by psteele with no comments

MVP Summit 2008

I'm now at the MVP Summit in Seattle.  This is my first summit in 5 years and I'm pretty excited!  They've got a great line-up of sessions, speakers and events.  It'll be a busy four days.  I'll try and blog as much as I can (anything that isn't NDA).  As a fan of the Castle Project (especially MonoRail), I'm looking forward to some of the ASP.NET MVC sessios.

Posted by psteele with no comments

NHibernate 2.0 Statistics and a MonoRail filter

This looked pretty cool.

Just to try this out I created a MonoRail filter that checks for "nhibstats" in the query parameters of the request. If the parameter is found it will turn on the nhibernate statistics, this is done before the controller action is executed. After the action as completed it will add the stats data to the PropertyBag so the view can access it.

Posted by psteele with no comments

Home Appliance Repair

Last night, instead of finalizing an app I'm working on for a client, I was playing around with my dishwasher.  I'm going to be at the MVP Summit next week and did NOT want to leave my wife alone with the kids and no working dishwasher!  It reminded me of my experience a couple of years ago when I had a furnace that didn't want to work.

A furnace (a gas one as we have) seems like such a simple thing: The termostat tells the furnace the house is too cold and the furnace turns on to blow hot air through the house.  Once the house is warm enough, the thermostat tells the furnace to turn off.  I'm sure many of our clients think the software we bulid is a pretty simple process: Enter a few numbers, drag a few sliders, hit "Submit" and you get your data plotted in a nic pie chart.  Easy!  But just as we developers put in so much work "behind the scenese" (input validation, unit tests, parameter validation, etc...) so too, do gas furnaces.

Our furnace (like many other gas furnaces, I suspect) has quite a complex cycle between the thermostat saying "I need heat" and actually getting heat.  First off, the blower spins up.  Time for hot air?  Not yet.  First, the gas has to flow and something has to ignite it.  Our system is pilot-less so there's a heater element.  This device is basically a 2-inch piece of material that glows red-hot when the system tells it to.  That is actually the second step in the process.

Now the gas flows right?  Nope.  Before the gas flows, the system must ensure that the heater element is hot enough to ignite the gas.  If the heater element was broken and the gas started flowing, instead of heating the house you'd be pumping gas throughout the house.  Not good!  So there's a heat sensor placed near the heating element.  The system tells the heating element to "glow hot".  It then waits for the heat sensor to detect that the heating element has gotten hot enough to light the gas.  Once this happens, then the system opens the gas flow, the gas ignites and we have hot air to warm up the house.

Not as simple as I had originally thought, but as I learned this, I definitely saw the parallels in my day job of software development.  Granted, a fault in my system may generate a nasty error message.  A fault in the heater could have much more dire consequences!

Oh yeah, the dishwasher?  I don't know what went wrong with that.  After pulling it out (its an under-the-counter model) and looking around, nothing seemed out of place.  So I turned it on and it started working fine (you know -- the client says, if I do "this" it breaks.  You do "this" and it works).  Before putting it back under the counter I want to run a few more tests before I mark this bug as "could not duplicate"...

Posted by psteele with no comments

Hats off to CATS!

No, not the musical!

My Lenovo (IBM) X60T Tablet started having a problem about a month ago.  The bottom two-inches of the LCD display was flickering/smearing/not displaying properly.  I noticed that if I gently squeezed one corner of the display, the problem went away but returned within a few days.  Further squeezing lasted only a day or two, then hours, then it was flaky all the time.

My warranty expires soon and this seemed like a warranty issue.  I did some research and found a local company, CATS CO, that is an authorized Lenovo repair center.  I went through the fun of backing up EVERYTHING off the machine.  Double-checked my backups, removed the hard drive and took it in for service on Tuesday 3/25 (in the afternoon).  They said they'd call in 3 to 4 days with an estimate.

On Monday morning (3/31) I recieved a phone call at 10:00am.  My tablet was fixed and ready to be picked up.  It was a warranty issue and I owed nothing.  Sweet!  I was expecting to be without my laptop for at least a week, perhaps a little longer if they needed to order parts.  Needless to say, I was very happy with the service I got from CATS CO and would recommend them to anyone in the southeast Michigan area needing to get a laptop repaired.

Posted by psteele with no comments

Attributes and virtual methods

I'll sum this up quickly by repeating a coversation I had with myself about an hour ago while coding:

"Hey -- idiot!  If you're going to override a virtual method that was marked with XmlExclude (because it's exposing a Dictionary that I don't need to serialize), make sure you add the XmlExclude to your override method as well!"

Posted by psteele with no comments

Hosting with Server Intellect

Back in February, I had to find a .NET web hosting company for a website I was building for my daughter's school.  It was critical that I find a reliable web host as the success of this site was extremely important.  And the timeframe was very tight so getting good support was a key criteria also.

After researching many companies, I decided to go with Server Intellect and couldn't be happier.  For my current needs, I went with the Tier 1 plan for $14.95/month.  While this is their least expensive plan, it gave me a lot of disk space, bandwidth and a SQL Server 2005 database.

Support has been outstanding.  I've had a few issues here and there, but every one has been resolved in a very reasonable time -- many within an hour or two.  And since joining Server Intellect, I've received two phone calls (from a real person!) asking me if I'm satisfied and if there's anything they can do to make things better!  Very nice!

If you're looking for a .NET web host, I strongly recommend you check out Server Intellect.  I've been very happy with them and will probably move some other sites I work on to them shortly.

Posted by psteele with no comments

Three Steps to Unmaintainable Code

At one time or another, we've all been asked to maintain or modify someone else's code.  On those few occasions where the code is well organized and documented, we barely notice we're working.  Coding is what we love to do and we do it.

But, on occasion, we get the code written by someone who is not as skilled in practices, frameworks or methodology.  This can lead to a frustrating experience when adding a simple feature or trying to fix a bug.

We've all seen questionable code.  And we've all got ideas on what makes it really hard to maintain.  I've been refactoring and rewriting some code the past few days and found three simple steps that you too can use to write unmaintainable code.

1. Comment your code

"What?!", you ask.  You thought adding comments helped make code maintainable?  In most cases, yes, comments help.  But to make really unmaintainable code you need to comment in a specific manner.  For example:

// Overloaded method called by the Foo class.

Yes, that's a comment in some code I'm working on.  Why do you need to tell me its an overloaded method?  I can tell from looking at the other overloads of the method.  And why tell me who calls it?  That is, no doubt, useful in some cases -- but not in the comments field!  I'd appreciate knowing what the method actually does.

Let's put this into practice and write some comments that can really dazzle and confuse future programmers:

// Static method that takes an int.

This one really shines once the method has been changed to accept a string!

// Fixes bug PR-8817

Bug tracking systems last forever, right?

// Called after Foo is initialized by the Bar class.

I wonder if there's any refactoring tools that will update these comments when I refactor this method to be called at a different time or from a different location?

2. Name your booleans as "flag".

Love this one!  For bonus points, make it a public static field.  That'll really blow 'em away!  Imagine the frustration of having 8 or 10 forms to maintain with three of them having "if(Foo.flag)", "if(!Foo.flag)" or "Foo.flag = true" sprinkled throughout the code.  Priceless!

3. Statics are King!

See item #2 above.  A good mix of instance variables and static variables really help muck up the code.  Mocking code with statics is pure joy!

Ok, my rant is done.  Back to the fun...

Posted by psteele with no comments
More Posts Next page »