# Sunday, March 18, 2007
For whatever reason when I cut and paste code into DasBlog using the "Insert Code" feature, my tabs always end up missing - even though they initially show up right after clicking Parse Code.  I ended up having to find and replace all blocks of four spaces with a tab before pasting into DasBlog.

The missing tab problem and the fact the syntax highlighting isn't as nice as Visual Studio 2005 makes me think I should start looking for another tool to format my code snippets that appear in this blog.

Sunday, March 18, 2007 7:02:58 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, March 17, 2007

To get my WatiN tests working in predictable and repeatable manner I ended up integrating Spring.NET into my application so that I could swap out the data service implementation through configuration.  When running under WatiN the stubbed data service is used instead of the production web service.  Having a predictable set of test data is critically important, especially since some of my test assertions are looking for specific data values in the rendered HTML, which would be impossible if I was hitting the actual web service for data.

I integrated Spring.NET into the ASP.NET 1.1* application I'm working on and so far I'm very happy with it.  What I like about it:

  • XML configuration almost exactly the same as Spring in Java (which I've been using pretty heavily for the last 3 months).
  • Tight ASP.NET integration, so I have no code dependencies on any of the Spring namespaces in my code.  None.  Zero.
  • There are data validation libraries and other features which may be useful in the future.
  • It just works.

So check it, here's my code behind for the Search.ascx, notice how the controller instance is set via the Controller property by Spring.  Then the view instance (the Search user control instance itself) is set into the controller in the Initialize method call on page load.  The one other thing that might seem strange is that I'm creating the SearchCriteria instance directly from the user control's Request collection rather than using declared ASP.Net controls; sometimes straight HTML controls are just what we need.

public class Search : ControlBase, ISearchView
{
   protected System.Web.UI.WebControls.LinkButton m_btnSearch;
   protected System.Web.UI.WebControls.DataGrid m_resultsGrid;
   private SearchController m_controller;

   private void Page_Load(object sender, System.EventArgs e)
   {
      Controller.Initialize(this, !Page.IsPostBack);
   }

   public void SortSearchResults(object sender, DataGridSortCommandEventArgs e)
   {
      Controller.Sort(e.SortExpression);
   }

   public void SearchClick(object sender, EventArgs e)
   {
      Controller.Search(Criteria);
   }

   public SearchCriteria Criteria
   {
      get
      {
         SearchCriteria criteria = new SearchCriteria();
         criteria.BorrowerId     = Request.Form["txtBorrowerId"];
         criteria.BorrowerName   = Request.Form["txtBorrowerName"];
         criteria.BusinessLine   = Request.Form["txtBusinessLine"];
         criteria.LoanNumber     = Request.Form["txtLoanNumber"];
         criteria.UnderwriterUid = Request.Form["txtUnderwriterUid"];

         return criteria;
      }
   }

   /// <summary>
   /// Injected by Spring.NET.
   /// </summary>
   public SearchController Controller
   {
      get { return m_controller; }
      set { m_controller = value; }
   }

   #region ISearchView Members

   public void setResults(IList results)
   {
      m_resultsGrid.DataSource = results;
      m_resultsGrid.DataBind();
   }

   #endregion

}

And here's the Spring.NET specific configuration for the Search page, this does all the wiring via configuration of the different objects.

<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">

    <object type="Search.ascx">
        <property name="Controller" ref="SearchController" />
    </object>

    <object id="SearchController" type="CRR.Web.Controllers.SearchController, CRR.Web">
        <constructor-arg name="dataService" ref="DataService" />
        <constructor-arg name="stateProvider" ref="SessionStateProviderAdapter" />
    </object>
   
    <object id="SessionStateProviderAdapter"
            type="CRR.Web.Controllers.SessionStateProviderAdapter, CRR.Web"/>


    <!-- Production data service implmentation -->
    <!-- <object id="DataService" type="CRR.Domain.DataService, CRR.Domain"/> -->
   
    <!-- Stubbed data service implmentation for testing -->

    <object id="DataService" type="CRR.Domain.DataServiceStub, CRR.Domain"/>   
   
</objects>

There is also a Spring provided HttpHandler and an HttpModule for Spring in the web.config.  This is the important part.  By registering Spring web as the http handler for aspx pages, I'm now telling Spring to construct my aspx (and thus ascx) page instances rather than ASP.NET.  With Spring now constructing my pages, its now possible to inject dependencies directly into my pages upon construction.

<httpModules>
   <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
</httpModules>
<httpHandlers>
   <add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
   <add verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, Spring.Web"/>
   <add verb="*" path="ContextMonitor.ashx" type="Spring.Web.Support.ContextMonitor, Spring.Web"/>
</httpHandlers>

The search controller uses a state service, specifically ASP.NET session state via a custom session state adapter, and a data service which are injected into the controller by Spring - the view (code behind page) has NO knowledge of the services being injected into the controller, as the controller instance itself is injected into the view.

Here's the relevant parts of the controller used for wiring, the constructor and Initialize().  Note that the constructor is called by Spring and that the Initialize method is called by the search view.

/// <summary>
/// Controller logic for search view.
/// </summary>
public class SearchController
{
   public static readonly string ResultsKey = "SearchController.ResultsKey";

   private ISearchView m_view;
   private IDataService m_dataService;
   private IStateProvider m_stateProvider;

   public SearchController(IDataService dataService, IStateProvider stateProvider)
   {
      m_dataService = dataService;
      m_stateProvider = stateProvider;
   }

   public SearchController Initialize(ISearchView view, bool firstTime)
   {
      m_view = view;

      if (firstTime)
         DefaultSearchForCurrentUser();

      return this;

   }
   // snip //
}

The plan is to have two different Spring configurations.  One for production and integration testing and the other one used for WatiN tests.  That way when WatiN drives Internet Explorer to verify the UI is working, it does so without ever touching the data service, only testing specific stubs are being used for the data service.  This is partly for speed but also because our data service implementation is not yet complete.

*I know… very sad.  My last ASP.NET project was using .NET 2.0, and that was a year and a half ago when that was started.

ASP.NET | IoC
Saturday, March 17, 2007 5:29:16 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, March 14, 2007

Now that I’m finally back in ASP.NET user land, I can finally scratch an itch of mine to use WatiN on a real project.  I’m thoroughly impressed with the product, even though the documentation is fairly light; the thing is the API is so straight forward you don’t need a bunch of documentation which allows you to ramp up and use it very quickly.  How nice is that?

The one problem I had was that Session state and general page state was being shared between each of my tests initially which would cause some tests to break because they expected the page to be in one state, but another test had changed the state to something else.  I had originally scoped my IE instance at the fixture level, which caused some tests to break because of the order they were being run by NUnit.  I ended up having to change my IE scope from fixture level, to test level which was quite a bit slower.  Here’s one of my tests:

[Test]
public void SearchResultsAreDisplayedOnSearchClick()
{
   using (IE ie = CreateIE())
   {
      ie.Link(Find.ById(new Regex(@"m_btnSearch\b"))).Click();
      string borrowerName = GetResultTable(ie).TableRows[1].TableCells[1].Text;

      Assert.AreEqual("George Washington", borrowerName,
          "Search results did not display as expected.");
   }
}

private Table GetResultTable(IE ie)
{
   return ie.Table(Find.ById(new Regex(@"m_resultsGrid\b")));
}

private IE CreateIE()
{
   IE ie = new IE(SearchUrl);
   ie.Refresh();
   return ie;
}

What I need to do is to make my tests less granular, less like a unit test and more like a functional integration test.  I would rather not do that, but I think for more complicated testing scenarios I will have to do this anyway.  I should stop trying to fight what should be natural here.  Basically I need to combine what are now several tests into a single test.  An end user would likely perform several actions on the page before moving on to anther page, and so should my WatiN tests.  After all, these aren’t unit tests – those of course are already all green.

Wednesday, March 14, 2007 6:21:41 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
# Tuesday, March 13, 2007
I ended up modifying my reusable IComparer class to work on any data type that implements IComparable since our data grid now has a decimal data type for one the columns.  I'm now betting that the users will want/need to be able to sort ascending and descending, not just ascending.  Also case insensitive comparisons will probably be required (although my original implementation did have this).

Perhaps its time I Googled a more mature implementation up, CodeProject must have one already.

Tuesday, March 13, 2007 6:58:13 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, March 10, 2007
Right now I'm refactoring an ASP.NET 1.1 application that another team member wrote not too long ago.  When I took it over there were 6 unit tests (4 working ones), but really they weren't true unit tests because the code that went into production was never getting tested.  They weren't really testing anything except for the special case code that only ran when under test.

if (m_testingData)
{
   serviceResults = m_testingData;
}
else
{
   RequestorDataService ds = new RequestorDataService(m_url);
   ds.Message = CreateSOAPRequest();
   ds.Submit();
   serviceResults = ds.GetResults();
}

Does anyone see a problem with the above code fragment?  Some IoC love would go a long way here.

Testing | WTF
Saturday, March 10, 2007 8:55:23 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  | 
I needed to implement sorting in one of our applications that contained a grid with multiple properties.  Normally in .NET 1.1 most people would throw the data into a DataSet and be on their way, but I already had a domain model with some nice POCOs, so I though why bother to load a dataset just to support sorting on a few elements?  I started to write a an IComparer but then I realized I would have to do it 6 more times for each property.  No thanks.

I decided to implement a super easy string property comparer that would get the property it needed to compare using reflection.

/// <summary>
/// Generic and reusable IComparer for string based properties.
/// </summary>
public class StringPropertyComparer : IComparer
{
    private string m_propertyName;
    private Type m_declaringClass;

    public StringPropertyComparer(Type declaringClass, string propertyName)
    {
        m_declaringClass = declaringClass;
        m_propertyName = propertyName;
    }

    private string getPropertyValue(object instance)
    {
        PropertyInfo info = m_declaringClass.GetProperty(m_propertyName, typeof(string));
        return (string) info.GetValue(instance, null);
    }

    public int Compare(object lhsObj, object rhsObj)
    {
        string lhs = getPropertyValue(lhsObj);
        string rhs = getPropertyValue(rhsObj);

        return ((new CaseInsensitiveComparer()).Compare(lhs, rhs));
    }
}

This could really be expanded to support multiple types besides strings, support asc and desc, and to support ordering by n+1 properties.  Perhaps some other day...  This works for now.


Saturday, March 10, 2007 12:27:41 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, March 07, 2007
Sometimes it's the simple things that make you go wow!  I just ran into one of those today while reading up on better HTML/CSS usage, I found there's an HTML element just for providing labels for input control.

Here's an example:

<label for="loanNumber">Loan Number</label>
<input id="loanNumber" type="text"/>



Not only does this render side by side, but its more obvious and provides semantic meaning.  Another cool thing is that when you click on the label text in your browser, then input control associated with becomes activated, try it!


Wednesday, March 07, 2007 10:43:32 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
So I finally added an about me section.  It uses DasBlog URL rewriting and FormatPage.aspx.

Wednesday, March 07, 2007 8:15:20 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
How can you have an invalid enum?  Why would you want an invalid enum?  I know it seems almost contradictory to have an invalid enum, but I have run into the situation once or twice.  Usually its where there is a switch statement that does some particular action based off an enum and in that switch statement there is a default that throws an exception just in case another programmer would add a new enum value without updating the switch statement.  You may actually want to unit test and verify that an invalid enum would throw an exception.  Here's one way to achieve this, use an explicit cast:

enum DayOfWeek
{
    Monday,
    Tuesday
}

DayOfWeek badDayOfWeek = (DayOfWeek)(-1);

Trivial!  Yet its not something you may think of, because we've generally been trained to think that enums are ALWAYS supposed to be valid.

Better yet, get rid of your enums and your switch statements.

Wednesday, March 07, 2007 7:03:29 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, March 05, 2007
My daughter's Dell Inspiron 1150 fell victim once again to bargain basement laptop design and ended up
flat lined on my desk this weekend with its guts completely removed.

The Patient



The culprit was a week power receptacle that popped off the mother board and needed to be resoldered for a second time. 

The culprit



Unfortunately when my daughter has the laptop on her lap, the power cable sometimes gets upward pressure applied from her legs bumping the power cord.  With only weak solder holding the receptacle on the main board its no wonder this thing has popped off twice now.  My IBM Thinkpad would never have this problem, the receptacle on it is firmly attached to not only the mother board, like this Dell, but also the case - freaking brilliant!

Laptop Completely Disassembled



This time was going to be different.  This time I dremiled the case to make a bit more room for a new metal reinforcement piece on the top of the receptacle to provide support for the receptacle from upward forces popping it off the mother board.

Reinstalled Receptacle With New Reinforcement



If you look really closely you can see a tiny piece of shiny metal sticking out above the power receptacle, this is the new reinforcement piece I soldered to the top of the receptacle.
Monday, March 05, 2007 7:56:59 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, February 22, 2007
I have a version of NAntRunner working in Visual Studio 2005.  I was questioning whether there was a real need for NAntRunner in Visual Studio 2005 considering we now have MSBuild, but NAnt is just plain better and I've just gotten too used to running Ant builds from Eclipse.

Unfortunately the conversion from Visual Studio 2003 to 2005 is not exactly just a registry edit since you must recompile the plugin in Visual Studio 2005 to reference EnvDTE80 and remove the Office.dll dependency (see this MSDN article: http://msdn2.microsoft.com/en-us/library/ms165634(VS.80).aspx).  The one nice thing about VS 2005 is that the add-in facilities are easier to work with so I was able to eliminate several of the C++ based hosting projects/dlls.  It seems to work just fine, but I still need to get the configuration loading/saving working.  I also need to fix the installer project to reflect the xcopy based VS 2005 add-in deployment model.

Ant
Thursday, February 22, 2007 8:51:03 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  |