Thursday, June 05, 2008

In my quest to find a suitable generic update method for a generic LINQ Data Access class I have found a decent amount of code and even more theories (sans code).  Some good, some verbose, and a lot bad.  It seems that Extension Methods are a fan favorite for just about everything nowadays and I wasn't suprised to see Extension Methods being used for LINQ to SQL updates.

In reading about Extension Methods I have heard good and bad feedback.  The good usually involves the convenience of bypassing a utility class and the bad involving code readability / maintability.  Forgive me for I am the William Hung of LINQ as I have had no formal training in this arena, but IMHO Extension Methods are a pain-in-the-ass when ExtensionMethodA returns the result of ExtensionMethodB which depends on the output of ExtensionMethodC which ..... Here is an example of what I am talking about in pseudo-code:

public static bool Update<T>(this Table<T> table, T instance) where T: class
{
   try
   
{
      // do stuff here with parameters...
      
return table.Foo() > 0;
   }
   catch (Exception)
   {
      return false;
   }
}

public static int Foo<T>(this Table<T> table) where T: class
{
   return table.GetEnumerator().Bar();
}

public static int Bar<T>(this IEnumerator<T> e) where T : class
{
   return 1;

Horrible example yes and for that I apologize.  Hopefully you see where I am going with this and that if you are given a similar codebase it can be quite confusing.  When I first heard of extension methods I though they were for simple utility tasks such as outputting a decimal value as a dollar amount (again, doesn't REALLY warrant an extension method but...):

public static string PrintWithDollarSign(this decimal input)
{
   return input.ToString("c");
}

Simple. Effective. Here's how you would use:

Console.WriteLine(instance.Price.PrintWithDollarSign());

Cheap. No frills.  I could have just bypassed this extension method altogether but it provides a very "Hello World"'y introduction to extension methods for those of you not hip to them.  In my previous example if you had an object with a decimal property and the value was 5.00 the output would be $5.00. Easy.

Anyone care to chime in on extension methods relying on other extension methods? I'd love to get some feedback.

C# | Will
Thursday, June 05, 2008 6:19:17 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, February 14, 2008

In working on some inherited code in a very large and complex website I was a little bit skeptical of touching the code.  Let's just say the codebase was dubious at best.  This presented a problem as I had 3 days to make a lot of changes in the admin section of the site.  When inheriting code there is always a learning curve.  Unfortunately I didn't have this luxury as I spent 1.5 days getting the code running locally (still haven't COMPLETELY finished this).  This left me with about another half-day to learn the handful of tables I was to be using.  One day to actually write the code.  No problem. 

So the client relayed to the PM what needed to be done which was ultimately relayed to me.  "When a manager selects a value from the whatever dropdownlist the values for the FileUpload control disappears and the user has to re-enter this value (which is by design as this would be a huuuuge security risk. Think if you could programmatically set the postedfile for the FileUpload control!).  Different sections are displayed depending on the value of such-and-such dropdownlist, etc..." I then ask myself, "WTF are there so many postbacks to simply hide / show sections?"  This sounded  like a perfect opportunity to utilize my new favorite property: Control.ClientID.  The goal was to move the functionality from server-side to client-side while making minimal changes to the server-side code ( VB* ;-) ). Half of the dropdownlists had AutoPostBack enabled.  I expected to see a handful of handlers when I viewed the code-behind. Nope. Why is it that developers feel the need to always post back to the server even if nothing is happening? Maybe they were planning to implement the handlers in the future?  A postback is kind of a big deal and I believe they should be used sparingly, but that is just me.  Anyway, my server-side code consisted of maybe 6 lines where I added Attributes to server-side controls similar to:

dropdownlist.Attributes.Add("onchange",

   string.Format("clientSide('{0}', '{1}', this.value)",

   someDiv.ClientID, anotherDiv.ClientID))

With ClientID I am shoving the ID of the rendered control into my dropdownlist's onchange event so I can guarantee the control Id on the client-side.  This is extremely important since this particular site uses a series of nested masterpages and you can never be too sure what the output control id will be.  I then wrote some utility JavaScript functions to set CSS display style to "none" or "" depending on the values selected.  I also use client-side JavaScript to enable / disable appropriate validators (which is pretty cool).

ValidatorEnable("validatorId", false); // disable
ValidatorEnable("validatorId", true); // enable

It may seem like a bit more work solving problems on the client-side, but in the end it definitely makes the user experience more fluid.

* I have found that VB can be quite pleasant when written correctly.  I am not the definitive authority on correct programming but I'm pretty sure immuting a string object while enumerating an ArrayList with a series of nested if statements and for loops is not the correct way to display SQL data in tabular form.  I also can't think of a good reason to have 400+ lines in Page_Load. These practices aren't language-specific and would probably piss me off in any .NET platform.

Thursday, February 14, 2008 7:17:59 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, January 18, 2008

There is no reason, NONE WHATSOEVER, for updating SVN (or any other source code repository) with code that does not compile.  There are 2 rules for version control that are both #1:

1. Check code in frequently
1. Don't check projects in unless they compile

Some argue that this isn't a good practice (1 #2 above) but let me explain.  Let's say you are working on a distributed team and there are 3 people working on a project.  Team members 1 & 2 are working on a class library for a web project.  They figure they are done for the day and check in the code that they worked on. Team member 3 (me) wants to check out this class library when working on a new & unrelated project.

I add this library to my project, do my thing, build. WTF? 57 Errors and 2 warnings.  I should see 0 Errors and 2 warnings.  Warnings are usually harmless and a lot that I have seen lately stem from converting 1.x websites to 2.0, 3.5 projects and usually have something to do with obsolete code (which is still compatibile).  So now there are a couple of problems.  First of all, I have to get my project to compile, which means fixing YOUR code.  Then, I have to check the code in that I fixed. Then, I  have to recompile my project and continue to try and be in a good mood while I am pissed that I had to waste anywhere from 5 minutes to sometimes an hour or more (then I get really pissed!).

"Well I didn't want to write the method that reflects my object and creates an instance of T."

You don't have to. This will do:

public static T GetRecord<T>(List<IDbDataParameter> parameters, string commandText)
{
   return Activator.CreateInstance<T>();

Or the following if you don't want the possibility of bugs slipping through the cracks due to incomplete data (which will never happen if you implement some sort of Unit Testing Framework but that is a whole other topic).

public static T GetRecord<T>(List<IDbDataParameter> parameters, string commandText)
{
   throw new NotImplementedException("Not done yet");

Another beef is when people add references to .DLL's that will break the build.  Adding .DLL references is commonplace, especially if you use 3rd party solutions or existing class libraries.  This can break builds also.  I learned this after making a mistake once where I downloaded a control to my desktop and added the reference from there.  The next person to check out my code didn't have that assembly on his desktop and it broke his build.  A workaround for this is to have a Dependencies folder within a project that is the central location for all these add-on assemblies.  That way when a developer adds a reference the next person who checks the code out (or updates their existing codebase) will be able to hit the ground running.

Again, code doesn't have to be bug-free or work like it's supposed to.  As long as it compiles when I update my code I am happy.  It is impossible to check in code that works as it should every day (i.e. conversion projects).

Friday, January 18, 2008 12:20:25 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  | 
 Thursday, January 17, 2008

The ClientID property is my favorite property this week and will definitely reshape how I write asynchronous functionality in the future.  I learned about this while adding some functionality to a client's site earlier this week.  The original site was created off-shore and people like me are the ones who get to take care of it.  It's been fun so far and had I not been working on this site this week I would've totally overlooked this wonderful property.

First off, ClientID is a readonly property (as it should be!) that does nothing more than get you the id of the control that is rendered.  Take the following rendered RequiredFieldValidator.

<span id="datalistContent_ctl05_requiredDescription" style="color:Red;visibility:hidden;">I saw what you did there.</span> 

Not quite the same as my original "requiredDescription" ID set in the .aspx.  When this control was processed this original ID was appended to the UniqueID created for this control. ASP.NET does this to make sure that there are unique id's for controls and this process is especially prevalent in Repeaters, DataLists, and GridViews.  Most of you probably knew that.  As you can tell from the HTML above my "requiredDescription" was in my DataList called "datalistContent" in the 5th generated table cell ("ctl05").

So how will this help me with asynchronous programming, cleaner UI's, etc, etc?  If you're familiar with the ItemDataBound event of the Repeater, DataList, Gridview controls then you can probably see why. Let's say I have a DataList that contains a TextBox and a HyperLink.  The Description property of my object is displayed in a multi-line textbox with a CSS style attribute (see below) that makes it appear to be normal text (i.e. can't see the border, scrollbars, etc..).  The link that reads "Change Description" should enable the already-disabled textbox, hide the link, apply a TextBox-like style, and focus the cursor on this newly-enabled TextBox.  After editing the text the onblur event triggers a client-side function that disables the textbox and adds the disabled, plain-ole-text feeling CSS, then display the link again for changing the description.  It's actually easier than it sounds (demo below). Take the following example (ps. If this were production code I would use e.Item.FindControl("string") as Foo and check for null before adding attributes):

protected void ItemDataBound(object sender, DataListItemEventArgs e)
{
   TextBox text = (TextBox) e.Item.FindControl("textDescription");
   HtmlAnchor link = (HtmlAnchor) e.Item.FindControl("linkChangeDescription");

   text.Attributes.Add("style", "border: none 0px #fff; overflow: hidden; width: 250px;");   
   text.Attributes.Add("onblur", string.Format("Blur('{0}', '{1}');", text.ClientID, link.ClientID));   
   link.Attributes.Add("onclick", string.Format("Edit('{0}', '{1}');", text.ClientID, link.ClientID));
}

Those JavaScript functions consist of a whopping 6 lines so I won't paste here.  If you are curious, leave a comment and I will send you a download link to AspNetAjaxLolSike.csproj. Quick tangent, if you are into Internet memes check out LOLCode.  Chances are you you have been on the receiving end of an image such as this or this.  Think of a programming language with that vernacular. Try-Catch = Hai-KThnxBye.  ANYWAY, that's where the LolSike project name came from as I spent a good 2-3 hours laughing uncontrollably at the user-submitted codebase at LOLCode.  Some guys at Microsoft actually created a compiler for it, which I have yet to track down.

Anyway, that code will render as follows with the appropriate client-side id of the ASP.NET Control from our code-behind:

<a href="#" id="datalistContent_ctl04_linkChangeDescription" onclick="Edit('datalistContent_ctl04_textDescription', 'datalistContent_ctl04_linkChangeDescription');">Change Description</a><br />
<textarea name="datalistContent$ctl04$textDescription" rows="2" cols="20" id="datalistContent_ctl04_textDescription" disabled="disabled" class="hidden" onblur="Blur('datalistContent_ctl04_textDescription', 'datalistContent_ctl04_linkChangeDescription');" style="border: none 0px #fff; overflow: hidden; width: 250px;">Hai 5</textarea><br /> 

Moving on, I came across exploring this functionality after getting tired of finding solutions requiring a Postback (i.e. asp:LinkButton control).  This, as far as I'm concerned: sucks.  The next best option was to wrap the datalist in an UpdatePanel.  That is wrong on so many levels.  My general attitude towards the UpdatePanel is that it generally sucks 80% - 90% of the time.  80% - 90% may seem like a large number and I will explain my feelings.  The UpdatePanel is a slippery slope of bad practices (imho) for those that want to start with asynchronous technologies.  I say this because most of those that use it (80% - 90%) don't know WHEN to use it.  I can't tell you how many times I've seen someone wrap a DataGrid of 100+ records (with update, add, delete functionality) in an UpdatePanel.  Set up a project in Visual Studio that has a textbox and button in an update panel.  On "postback" set the textbox to the current date time (DateTime.Now) and use Firebug or Fiddler to check out the size of the response.  It will probaby surprise you.  I'm not saying that if you use an UpdatePanel you suck at AJAX.  By no means do I consider myself the authority figure on asynchronous programming.

You can add a button to this (hidden if there are no records in your IEnumerable<T>) to give your application "Update" functionality.  Your button OnClick event would then check all the DataListItem's in the DataList, cast your DataListItem.Item.DataItem to type T, interpret the data, and process accordingly by way of some class library. Easy.

Notice that there are no postbacks when I edit the descriptions in my DataList.

ClientID Demo

When I get some more time I will explore the avenue of asynchronous GridView paging.  I have never used the GridView so I'll have to be REALLY motivated to try.  I only used this in the DataList because I needed to display columns based on user input and treated the DataList as a Repeater with Columns functionality.

.net | C# | Will
Thursday, January 17, 2008 6:03:04 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, January 11, 2008

I've been reading a couple of renditions of this SessionWrapper class via DotNetKicks over the past couple of days.  While I must admit that this code isn't 100% original, I can say that I have given it a more generic feel and added a little bit of functionality.  With my implementation you can not only use any class, you can specify a name for the session object.  That way if you want to store say the Account and Order objects in Session you could use the same method without creating a wrapper for each type.

using System.Web;

namespace NamespaceNameGoesHere
{
   public class Session<T> where T: class
   
{
      private string _name = string.Empty;

      public string Name
      {
         get { return _name; }
         set { _name = value; }
      }

      public T Object
      {
         get { return HttpContext.Current.Session[Name] as T ?? null; }
         set { HttpContext.Current.Session[Name] = value; }
      }

      public Session(string name)
      {
         _name = name;
      }

      public Session()
      {
      }
   }
}

Pretty straight-forward. Here's how you would use it from a Page_Load for example:

Session<Foo> session = new Session<Foo>("Foo");

if (session.Object == null)
   session.Object = new Foo(-1, "hai guyz!");
else
{
   Foo foo = session.Object;

Not cutting-edge but could be useful if you want a type-safe session state.

.net | C# | Will
Friday, January 11, 2008 3:46:40 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 

Lately I have doing a lot of SSRS and overall SQL work for a project.  In returning some data to process server-side my data retrieval method was returning null* which means that an exception was thrown. I did a little digging around and then decided to execute the stored procedure manually (i.e. Management Studio).  After debugging in Visual Studio and seeing what the values were and that they were in fact getting passed to the stored procedure I used the same signature to execute the proc in Management Studio.  Hmm, no dice.   My error message was of a "Divide-By-Zero" fashion.  This is the first time that I have ever seen this.  A little reading on the subject and I come to find out that the field used as the denominator allowed nulls.

Enter NULLIF. This is what saved the day.  This function will compare two values and return a null value if the expressions are equal.  For example, take the following dummy stored procedure.

CREATE Procedure SharesCalculateSharePrice
(
   
@shareId int,
   
@numberOfUnits decimal
)

AS

DECLARE @totalPrice decimal

SET @totalPrice = ( SELECT TotalPrice FROM Shares WHERE ShareId = @shareId )
DECLARE @returnValue decimal

SET @returnValue = ( @numberOfUnits / @totalPrice )
SELECT @returnValue 

Pretty basic. I'm selecting the total price from a table and using as the denominator.  I pass in number of units. To get price per unit (share price) I divide one by the other. What if the @totalPrice is 0? Then I get the dreaded Divide-By-Zero error.  Using NULLIF, we can make a trivial aleration to the above procedure and return a NULL value instead.

CREATE Procedure SharesCalculateSharePrice
(
   
@shareId int,
   
@numberOfUnits decimal
)

AS

DECLARE @totalPrice decimal

SET @totalPrice = ( SELECT SUM(TotalPrice) FROM Shares WHERE ShareId = @shareId )
DECLARE @returnValue decimal

SET @returnValue = ( @numberOfUnits / NULLIF(@totalPrice, 0) )
SELECT @returnValue 

Easy. If @totalPrice is 0 we will substitute with a null value.  This way the returnValue will be NULL and we can process accordingly from our .NET application.

public static object ExecuteScalar(List<IDbDataParameter> parameters, string commandText)
{
   using (DBManager manager = new DBManager(_provider, _connectionString))
   {
      manager.Open();
      manager.CreateParameters(parameters.Count);

      for (int i = 0; i < parameters.Count; ++i)
         manager.AddParameters(i, parameters[i].ParameterName, parameters[i].Value);

      object returnValue = manager.ExecuteScalar(CommandType.StoredProcedure, commandText);

      return returnValue == DBNull.Value || returnValue == null ? -1 : returnValue;
   }

There could be even more useful ways to use NULLIF but for me this has worked out fine.

T-SQL | Will
Friday, January 11, 2008 8:41:10 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  | 
 Monday, January 07, 2008

I just finished my first VB.NET project and it was pretty interesting. Some of you might be wondering why I did a project in VB.NET.  There are actually 3 reasons:

  1. Client's money is still green
  2. Site was the first .NET application by someone straight out of classic ASP
  3. Client won't pay to upgrade to C#

Now that we've cleared that up, I'd like to say how awkward it was.  First of all, it took me probably twice as long to write this as it would if it were in C#.  This is due to my not knowing the in's and out's of VB.NET 2.0 and not necessarily something I can blame on VB.  While there are some great additions to VB.NET such as Generics (even though the syntax isn't very intuitive), the Using construct (about time!) there is one feature that is still not there that I use day-to-day when writing applications in C#. I am talking about collapsible regions within methods.

Take the following code example:

Protected Sub ButtonClick(ByVal sender As Object, ByVal e As EventArgs)

   
Dim button As Button = sender

   If Not button Is Nothing Then

      Dim stringVariable As String = String.Empty

      Select Case button.ID

         Case "foo"
            stringVariable = "foo"

         Case "bar"
            stringVariable = "bar"

         Case "asdf"
            stringVariable = "bar"

         Case "qwert"
            stringVariable = "qwert"

      End Select

   End If

   If Not String.IsNullOrEmpty(stringVariable) Then
      
DataAccessOrBLL.DoSomethingCoolWithThisString(stringVariable)
   End If

End Sub

Given the opportunity to start from scratch I like to setup my event handlers like this.  One method that handles everything I need. To me, it makes for cleaner code and much easier to read.  If something goes wrong with an event handler, I can look in one place. In a C# environment I would setup a collapsible region like so:

Protected Sub ButtonClick(ByVal sender As Object, ByVal e As EventArgs)

   
Dim button As Button = sender

   If Not button Is Nothing Then

      Dim stringVariable As String = String.Empty

#Region "button switch"

      Select Case button.ID

         Case "foo"
            stringVariable = "foo"

         Case "bar"
            stringVariable = "bar"

         Case "asdf"
            stringVariable = "bar"

         Case "qwert"
            stringVariable = "qwert"

      End Select

#End Region "button switch" 'C# would actually be #endregion

   End If

   If Not String.IsNullOrEmpty(stringVariable) Then
      
DataAccessOrBLL.DoSomethingCoolWithThisString(stringVariable)
   End If

End Sub

The reason I would do that is because when I am writing code I view monitor space as real estate. On each screen I like to see as much code as possible. In the example above I could add a collapsible region outside of this sub routine but that wouldn't work (at least for me).  In scanning through the code I'd still want to see the section where I call DoSomethingCoolWithThisString because it's an action item so to speak.  In scanning this code-behind I could see that in my handler method I am setting a string based on the button that was clicked and then calling that method in my DAL / BLL.  Even though the code segment is collapsed I can still see what it is doing and if I need to fix that section (i.e. add a case for a new button added to the page) I could just uncollapse that region.

Quick tangent: Is it just me or does Intellisense seem a little slow and different than C#?  Also, what's up with not being able to hightlight a segment of code, right-click, 'Surround With' when in the VB.NET environment?  The 'Surround With' functionality is great for using constructs and try-catch blocks amongst other things.

At the end of the day it's all .NET and I'm kind of glad I came across this project.  As a software developer in the consulting world it's nice to be dextrous when it comes to writing / reading code but I'm still partial to C#.

.net | Will
Monday, January 07, 2008 7:07:42 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  |