Archives

Archives / 2005 / January
  • Data access strategy in Whidbey

    Fredrik has blogged some great Whidbey posts  - not to mention his 3,000 or so posts on the www.asp.net forums!  Recently he wrote a couple of articles about some of the data access techniques which are available in Whidbey.  First he looked at the Data Component which allows to quickly and easily create Crud-like data access layers:

    Read more...

  • Next tool - a blogging application

    Before I start my rant I should say that .Text is pretty decent web app.; it's seems way more complex than it needs to be and it's very difficult to install but there's a lot of great implementation code in there. Last week while unsuccessfully trying to get it installed and create some initial users I decided that, for my next application I'm going to build a blogging app.  Much of the API design and feature-set is done and I'm currently working through the technical architecture.

    Read more...

  • Next ProjectDistributor release

    I'll be uploading the source for the next version (1.0.2) of Project Distributor on the weekend and, be upgrading the live site to run off of that version.  Here is the list of new features which appear in this release:

    Read more...

  • Using metadata and reflection to dynamically manage message routing

     

    Most routing systems have a transformation phase where, based on its current state, a message is transformed into a document and routed to an endpoint.  Systems such as BizTalk provide GUI's and designers to remove the need for cumbersome coding by making the rules and subsequent transformations configurable; here's an example of a switch statement in a listener class where the rules of the routing engine are hard-coded:

     

    public static void MessageArrived( Message message ) {
      switch( message.MessageState ) {
        case MessageState.Initial:
            Console.Write( Transformer.CreateRequest( message ) );
            break ;
        case MessageState.Submitted:
            Console.Write( Transformer.CreateApproval( message ) );
            break ;
        case MessageState.Approved:
            Console.Write( Transformer.CreateInvoice( message ) );
            break ;
        case MessageState.Saved:
            Console.Write( Transformer.CreateReport( message ) );
            break ;
        default:
            Console.Write( Notifier.NotifyError( message ) );
        break ;

      }
    }

     

    If there's extra "noise" in the MessageArrived method, it can become hard to maintain as the length of the switch gets longer.  It can also become hard to maintain if there are repetitive code chunks within each case.

     

    In the above cases you can - at a moderate performance cost - re-factor the common code away into a generic method.  Looking at the above example, one neat way to achieve this is to ascribe metadata to the MessageState enum so that it can be inspected at runtime and the routing lookup driven from that metadata.  First, let's create an attribute to contain our lookup data and add it to the MessageState enum:

     

    [AttributeUsage(AttributeTargets.Field, Inherited=false, AllowMultiple=true)]
    public class WorkflowAttribute : Attribute {
      public WorkflowAttribute(Type type, string methodName) {
        this.Type = type ;
        this.MethodName = methodName ;
      }

      public Type Type;
      public string MethodName ;
    }


    public enum MessageState : short {

      [WorkflowAttribute(typeof(Transformer), "CreateRequest")]
      Initial = 1,

      [WorkflowAttribute(typeof(Transformer), "CreateApproval")]
      Submitted = 2,

      [WorkflowAttribute(typeof(Transformer), "CreateInvoice"),

       WorkflowAttribute(typeof(Notifier), "NotifySalesGuy")]
      Approved = 3,

      [WorkflowAttribute(typeof(Transformer), "CreateReport")]
      Saved = 4,

      [WorkflowAttribute(typeof(Notifier), "NotifyError")]
      Unknown = short.MaxValue
    }

     

    Notice that I applied 2 worklow attributes to the MessageState.Submitted enum value.

     

    Now I can re-factor the original MessageArrived method into a generic message handler routine:

     

    public static void MessageArrived( Message message ) {

      MessageState state = message.MessageState ;
      FieldInfo field = state.GetType().GetField(state.ToString()) ;

      object[] attribs = field.GetCustomAttributes(typeof(WorkflowAttribute), false) ;

      for( int i=0; i<attribs.Length; i++ ) {
        WorkflowAttribute att = attribs[i] as WorkflowAttribute ;
        if( att != null ) {
          MethodInfo method = null ;

          if( att.Type.GetMethod(att.MethodName).IsStatic ) {
            method = att.Type.GetMethod(att.MethodName) ;
            Console.Write(method.Invoke(null, new object[] {message}));
          }else{
            object instance = Activator.CreateInstance(att.Type) ;
            method = instance.GetType().GetMethod(att.MethodName);
            Console.Write(method.Invoke(instance, new object[] {message}));
          }
        }
      }
    }

     

     

    I've uploaded a working demo of this to ProjectDistributor:

     

        http://projectdistributor.net/Releases/Release.aspx?releaseId=82

    Read more...

  • 2 interesting Msdn articles

     

    An interesting article about writing code to test UI:

        http://msdn.microsoft.com/msdnmag/issues/05/01/TestRun/default.aspx

     

    Also, there's an article by Kent Sharkey about merging Rss feeds:

     

        http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/mergingrssfeeds.asp

     

    This is a useful article with a great summary of the make-up of the Rss schema and some nice API design tips too!  As an added bonus, the reader is invited to watch as Kent has a Dates induced meltdown towards the end of the article.

    Read more...

  • MbUnit... It's all green baby; it's all green!

    Last night I started moving some of the PD logic out of the web project and into a Framework project so that it is more accessible to other components.  This resulted from some refactoring of the app. That I've been doing since implementing UrlRewriting and Trackbacks.  I created UrlManager, and UrlFormatter classes to handle some of the url matching logic and thought that I'd start building a library of Unit Tests against this new stuff. 

     

    What I'm going to show you now is a bit of a code dump but, take a scan through it then we'll discuss what went on...

     

    [TestFixture]
    public class TestUrlManager {
    
      public TestUrlManager() {}
    
      [RowTest]
      [Row("http://www.projectdistributor.net", false)]
      [Row("http://projectdistributor.net", false)]
      [Row("http://www.projectdistributor.net/Foo", true)]
      [Row("http://www.projectdistributor.net/Projects/Project.aspx?foo=bar", false)]
      [Row("http://projectDistributor.net/", false)]
      [Row("http://projectDistributor.net/Foo/", true)]
      [Row("http://projectDistributor.net/Foo/default.aspx", true)]
      public void TestIsGroupInUrl(string url, bool isGroupUrl) {
        
        bool result = UrlManager.IsGroupNameUsed(url) ;
        Assert.AreEqual(isGroupUrl, result) ;
    
      }
    
    
      [RowTest]
      [Row("http://www.projectdistributor.net", "")]
      [Row("http://projectdistributor.net", "")]
      [Row("http://www.projectdistributor.net/Foo", "Foo")]
      [Row("http://www.projectdistributor.net/Projects/Project.aspx?foo=bar", "")]
      [Row("http://projectDistributor.net/", "")]
      [Row("http://projectDistributor.net/Foo/", "Foo")]
      [Row("http://projectDistributor.net/Foo/default.aspx", "Foo")]
      public void TestExtractName(string url, string groupName) {
        
        string result = UrlManager.ExtractGroupName( url ) ;
        Assert.AreEqual(groupName, result) ;
    
      }
    }

     

    ...ok, as you can see, I'm testing the IsGroupNameUsed and the ExtractGroupName logic of the UrlManager class.  Notice how I can use attributes to drive test data into the test method by using the RowTestAttribute and the RowAttribute classes and attaching them to the methods that I want to run as unit tests.

     

    The ease of TestDriven.NET

     

    Because I'm using TestDriven.NET, I can now right click in the class, choose "Run Tests" and voila!  MbUnit presents me with a  web page representation of the red and green lights that you've seen via other unit testing frameworks such as Nunit.

     

    Duplication kills

     

    So that's pretty easy right?  Well, yes and no.  Look at that duplicated data there.  And what happens when I have 10 tests?  And what happens when I need to change the Row data?  That's right& all this duplication will end up working against me at some point.

     

    Combinatorial Tests to the rescue

     

    I knew that Peli would have the answer - after all, he did write it! - so, after a quick scan of his blog I discovered the combinatorial tests.

     

        http://blog.dotnetwiki.org/archive/2005/01/03/1403.aspx

     

    Combinatorial tests allow me to create a factory which will produce my data and, for each enumerated item returned by the factory, a strongly typed data member can be returned to my unit test method.

     

    Let's start& create a Data Class and a Factory

     

    For my purposes a simple data class to encapsulate my test objects will suffice and then a simple factory method to create and return an array of that data:

     

    // A simple data class to encapsulate the attributes of my driver data
    public class UrlData {
    
      public UrlData( string url, string groupName ) {
        this.Url = url ;
        this.GroupName = groupName ;
      }
    
      public string Url;
      public bool IsGroup{ get{ return this.GroupName.Length > 0 } };
      public string GroupName;
    }
    
    
    [Factory]
    public UrlData[] GetUrlData() {
      
      UrlData[] items = new UrlData[9] ;
    
      items[0] = new UrlData("http://www.projectdistributor.net", string.Empty) ;
      items[1] = new UrlData("http://projectdistributor.net", string.Empty) ;
      items[2] = new UrlData("http://www.projectdistributor.net/Foo", "Foo") ;
      items[3] = new UrlData("http://www.projectdistributor.net/Projects/Project.aspx?foo=bar", string.Empty) ;
      items[4] = new UrlData("http://projectDistributor.net/", string.Empty) ;
      items[5] = new UrlData("http://projectDistributor.net/Foo/", "Foo") ;
      items[6] = new UrlData("http://projectDistributor.net/Foo/default.aspx", "Foo") ;
      
      return items ;
    }

     

    Re-Wire and Re-run

     

    Now, all that remains is to re-wire the test methods to use the factory and right click to re-run the tests again...

     

    [CombinatorialTest]
    public void TestIsGroupInUrl([UsingFactories("GetUrlData")] UrlData item) {
      
      bool result = UrlManager.IsGroupNameUsed( item.Url ) ;
      Assert.AreEqual(item.IsGroup, result) ;
    
    }
    
    
    [CombinatorialTest]
    public void TestExtractName([UsingFactories("GetUrlData")] UrlData item) {
      
      string result = UrlManager.ExtractGroupName( item.Url ) ;
      Assert.AreEqual(item.GroupName, result) ;
    
    }

     

    It's all green baby; it's all green! :-)

     

    Read more...

  • Instant Messenger 7 - good and bad

    I installed the new beta version of the Instant Messenger client last week.  The UI is really nice and they've added some great new features.  The 2 most obvious of these are "Nudges" and "Winks".  Nudges allow you to "shake" the IM client of the person that you are chatting with... I haven't really worked out when is the optimum time to use these yet.

    Read more...

  • AssemblyReflector - event based discovery of assemblies

    AssemblyReflector (Conchango.Code.Reflection) is an event-based assembly parser - it allows assemblies to be searched for Attributes, Events, Fields, Interfaces, Methods, Nested Types, Properties and Types, by subscribing to the relevent OnDiscover event and then performing a search for the member based on several available search methods;

    o Contains(string)
    o EndsWith(string)
    o Named(string)
    o OfType(Type) - Attributes Only
    o StartsWith(string)
    o WithBindingFlags(BindingFlags)

    When an event is raised you can access the discovered member via the EventArgs

    Read more...

  • Melbourne Geek Dinner and future Canberra Geek Dinners

    While I was in Melbourne, I arranged to get a few of the guys together for a geek dinner.  This followed hot on that tail of the first one in Canberra a few weeks back.  People attending this one were:
     
    · Cameron Reilley - http://reilly.typepad.com/ (Australian Podcasting mogul)
    · Matthew Cosier - http://weblogs.asp.net/autocrat/ (Melbourne Microsoft guy and InfoPath extraordinaire)
    · William Luu - http://www.will.id.au/blog/ (active Melbourne community guy)

    Read more...

  • Presenting and Facilitating

    I spent the past couple of days in Melbourne with several other Readify guys doing a course about "presenting and facilitating".

     

    There were some great moments and also some real highlights.  It was fascinating to learn some of the little tip-n-tricks that you can use when you are speaking/facilitating that can help to get your message across and also to make your talks more participatory.

     

    Some of my most important learning's were:

     

    • Eye contact.  It's important to make eye contact with the people that you are talking to and to maintain eye contact for about the length of a thought.
    • Structure.  On the first day I had a presentation which was a sea of data& by day 2 this was packaged nicely into a structure that made it much easier to present and also, for the audience, much easier to digest.
    • Interventions.  We discussed interventions - which are small break-up activities designed to get people up on their feet.  These are used to get things going and to stimulate everyone.
    • The humble 'B' key.  When you are doing PowerPoint presentations, you can press the 'B' key to make the screen go black and again to bring back your presentation to the screen.  Use this when you want to talk and not compete with your slide.

     

    Overall it was an awesome experience which taught me a lot.  It was also great to catch up with the other Readify guys.  For those of you who know any of the guys you can imagine how vibrant, collaborative and enthusiastic the sessions were :-) 

    Read more...

  • Justin's fine; busy, but fine.

    Finally managed to get in touch with Justin over the last night.  He's been busy getting things done and drifting in and out due to Christmas activities... added to that, he had taken the Christmas break to rebuild his home intranet.  Not sure when we'll see him around again but it's good to know that everything is OK.

    Read more...

  • Today was a day of software installation

    So, today I installed:

     

    SVGViewer so that I could view the Assembly Graphs generated by Reflector.Framework

     

    MicrosoftAntiSpyWare - this looks great.

     

    NCover so that I can see how much of my total code base is being exercised by my unit tests

     

    TestDriven.NET so that I can run unit tests from VS.NET

     

    MbUnit so that I can write unit tests (MbUnit actually comes with the TestDriven download).

    Read more...

  • Partial Book Review: Extreme Programming Adventures in C#

    While reading "Extreme Programming Adventures in C#" over the past couple of days it was interesting to see how the author - Ron Jeffries - abstracts out a "model" in a GUI app that he builds and then shows that Unit tests can be run off of that. 
     
         
     
    My feeling - after reading this stuff - is that, in applying the discipline of using unit tests (not necessarily TDD) would potentially have the added benefit of improve the style of your code/architecture.
     
    I'm only part way through the book but I'm really enjoying it.  The style of the book is adventurous.  One of the things that have turned me off of books on this topic in the past is that they edit out all of the ugliness and uncertainty that you face when you attempt to implement this stuff.  Ron makes no secret of the fact that he was often uncertain when deciding over which path to take at key decision points - this makes it much easier to jump in and have a play.

    Read more...

  • Chuck is blogging

    Charles Sterling, Developer Evangelist extroadinaire is blogging.  Charles (aka Chuck) looks after the scuba diving technologies from the shores of sunny Gold Coast, Australia.  I can just picture him sitting down by the waterfront by his home there blogging away while reeling in a Mackerel and swigging away on a nice cold Fosters :-)

    Read more...