Saturday, October 23, 2004

Many developers (especially those involved in OOP at some level) are aware of interface inheritance.  Usually interface inheritance (also frequently referred to as interface implementation) comes in the form of a class providing functionality for an interface, wherein the interface is nothing more than a signature, a set of methods, properties, and/or events.

Interface inheritance provides a mechanism for different classes to be treated in like fashion, despite the fact that they are completely distinct.  By implementing an interface within a class you designate that that class will abide by the interface's contract; clients can expect to be able to invoke the various interface-specified methods.

Take, for example, the IDisposable interface.  If we were to define this interface ourselves, it would resemble the following:

namespace System {
   public interface IDisposable {
      void Dispose();
   }
}


If a class were to implement the interface, it can do so in a variety of manners.  For example, here are two:

using System;

namespace MyNamespace {

   public class MyClass1 : IDisposable {
      // implement the interface by signature (implicitly)
      // this method, though publically available via the class's interface will
      // be mapped at compile time to the IDisposable interface because it matches the
      // method signature in name, type, parameters, and is a public, non-static method.
      public void Dispose() {
         // clean up the object here...
      }
   }
  
  
   public class MyClass2 : IDisposable {
      // implement the interface explicitly
      // this method is not callable via the class's interface directly
      // instead it is only available via an IDisposable reference to the class
      void IDisposable.Dispose() {
         // clean up the object here...
      }
   }

}

Ok, please forgive the brief lesson.  All OOP developers know and fully understand these precepts.  In my experience, however, it seems that not as many developers are familiar with what I like to term interface aggregation.  Interface aggregation, though not true aggregation, occurs when you define an interface that implements another interface.  Now we know an interface cannot itself provide implementation (otherwise it'd be an abstract class - which is a slightly different beast).  So what happens?  Suppose we have the following:

namespace MyNamespace {
   public interface IAnimal : ICloneable {
      string Name { get; set; }
   }
}

In this case we have an interface (IAnimal) which has one property (Name).  The IAnimal interface also implements the ICloneable interface (which has a method called Clone()).  Therefore, a deriving class must also implement the Clone() method, but does it do it via the IAnimal or the ICloneable interface?

Well, it turns out that my moniker 'Aggregation' is not entirely true...the Clone() method does not actually get aggregated to the IAnimal interface.  We have to implement the interface either implicitly or explicitly via the ICloneable interface as such:

namespace MyNamespace {

   public class Goat : IAnimal {
      private string _name;
     
      // implicit implementation
      string Name {
         get { return _name; }
         set { _name = value; }
      }
     
      object Clone() {
         return this.MemberwiseClone(); // for demo, simply return a shallow copy
      }
   }


   public class Sheep : IAnimal {
      private string _name;
     
      // explicit implementation
      string IAnimal.Name {
         get { return _name; }
         set { _name = value; }
      }
     
      object ICloneable.Clone() {
         return this.MemberwiseClone();   // for demo, simply return a shallow copy
      }
   }
  
}

After seeing this we start to think...so?!  What's the big deal?  Well, here's the kicker.  By having an interface implement another interface, you aggregate your expectations.  After all, isn't an interface a set of expectations?  By defining an interface, I can enforce that a deriving class also implement another interface and ensure that behavior.

The coolest thing about interface aggregation is that while the methods on the inherited interface do not merge with the deriving interface, I can call them via a reference to the deriving interface!  You're not required to cast to the second (or base) interface in order to call the method.  Isn't that cool?!  Taking the above example, while the Clone() method isn't truly a part of IAnimal, I can call it via an IAnimal variable.

namespace MyNamespace {

   public class PetriDish {
      public void Mix() {
         // create the animal
         IAnimal sheep = new Sheep();
         sheep.Name = "Dolly";
        
         // clone it via the IAnimal interface
         Sheep duplicate = (Sheep)sheep.Clone();
      }
   }  

}

Where I have found this to be the most beneficial, in all honesty, is with respect to COM+ (Enterprise Services) components.  Call me crazy, but I am still in love with COM+.  In the traditional COM+ world, your components get pooled and as such, you want to release them back to the pool as quickly as possible after you're done using them.  A convenient way to do this is to call the Dispose() method on a ServicedComponent (which internally calls ServicedComponent.DisposeObject()).

ServicedComponent already implements IDisposable so half of our work is done.

Being the good COM+ programmers that we are, we decide to create a public interface for our COM+ component rather than define methods directly on class...if you want, I can elaborate on this in another post.  In this simple example, we will create a COM+ component that retrieves a customer name from the database; contrived, yes I know, but I'm typing everything in Notepad2 and don't have the luxury of a syntax checker so it's all off the cuff.

COMPONENT CODE

using System;
using System.Data;
using System.Data.SqlClient;
using System.EnterpriseServices;

namespace MyComPlus {

   public interface IDataCustomer : IDisposable {
      string GetName(int custId);
   }
  
  
   [EventTracking()]
   [ClassInterface(ClassInterfaceType.None)]
   [ObjectPooling(true)]
   [JustInTimeActivation(true)]
   [Transaction(TransactionOption.Supported)]
   public class DataCustomer : IDataCustomer {
      string IDataCustomer.GetName(int custId) {
         using ( SqlCommand cm = new SqlCommand("SELECT Name FROM Customers WHERE ID = @ID") ) {
            cm.CommandType = CommandType.Text;
            cm.Parameters.Add("@ID", SqlDbType.Int).Value = custId;
           
            return (string)cm.ExecuteScalar();
         }
      }
   }

}


CLIENT CODE

using System;
using System.EnterpriseServices;
using MyComPlus;


namespace MyClient {

   public class EntryPoint {
      public static void Main() {
         Customer c = new Customer(15);
         Console.WriteLine("Customer Name: ", cust.Name);
      }
   }
  
  
   public class Customer {
      private int _id;
     
      public Customer(int id) {
         _id = id;
      }
     
      public string Name {
         get {
            // create a new Customer via the IDataCustomer interface
            // the using block will automatically invoke the IDisposable.Dispose() method
            // when it finishes, effectively returning the object to the pool
            using ( IDataCustomer customer = new DataCustomer() ) {
               return customer.GetName(_id);
            }
         }
      }
   }
  
}

NOTE:  None of this code has been checked for syntax, spelling, or run through a compiler, so I'm hoping it works as entered.  If not, please let me know and I'll be happy to fix it for you and update the post.

The ability to create an interface is powerful, but it's also fundamental.  The ability for an interface to force a deriving class to implement another interface by deriving from it itself, is extremely enabling and provides a rich object model to your applications.

Saturday, October 23, 2004 9:51:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Sunday, October 17, 2004

In order to provide runtime configuration settings for your applications it's customary to provide a .config file (e.g. web.config, app.exe.config, etc).  Usually, this .config file resides along side your application's .exe file.  The .NET runtime automatically loads the appropriate .config file and examines its contents at runtime as needed.  When developing COM+ applications there are a few other things to be aware of, namely the Activation model used.

COM+ applications can be either Library Applications or Server Applications.  Though there are several important distinctions between the two, the most noticeable difference is that Library Applications are always run in-proc with the calling/host applications.  Library applications, therefore just like any other dll, utilize the host application's .config file for settings.  Server Applications are different, however, in that they are run out-of-proc.  What does this mean?  Well, for starters, a process named dllhost.exe actually provides the application isolation.  dllhost.exe is the host application and is found in the %WINDIR%\System32 folder.  Therefore it is traditional to place your application's configuration settings in a file named dllhost.exe.config within the same folder.

I've cringed everytime I recommended that strategy.  It has pitfalls:

  • all COM+ applications share the same config file.  This has problems.
    • First of all, name clashes can easily occur if you're brave/foolish enough to use and not custom configuration settings.
    • Second, if the application has already started it won't recycle automatically if the .config file changes (a la ASP.NET applications).  You have to actually stop and restart all applications that rely on the new values.
  • it's not a recommended strategy to place files in the %WINDIR%\System32 folder

This issue has been fixed/remedied with COM+ 1.5 (XP and Windows Server 2003).  In the COM+ catalog you can set the Application Root Directory for an application on the Activation tab.  At runtime now, COM+ will look in that folder for two files: application.manifest and application.config.

Your application.manifest file should contain the following:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" />

Set up your application.config file just as you would for any .config file.

Sunday, October 17, 2004 5:55:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [10]  |  Trackback
 Friday, October 15, 2004

I'm doing a little probe here.  We hear developers constantly talk about their business objects.  Pretty much every discussion revolving around application design mentions them in conjunction with UI objects and Data objects.  What are they?  What is a business object to you and what functionality does one have?

Is a business object...

  • a data container (just a fancy struct)?
  • an object that can "get" an instance of itself from the data store (via static methods)?
  • an object that can "save" itself to the data store?
  • something else?

Where do your business objects live?

  • right along side the UI objects?
  • In a separate library? separate process? separate machine?
  • in the same application but functionally distinct from the UI objects?

How much about the data store do your business objects know and understand?
How do you "get" one? via a data layer? directly?

Suppose you had a "business object" called Customer.  The Customer class is defined within a distinct library; it's physically separate from your UI and your database objects.  How would you design Customer?  How would you distinguish between a "new" Customer and one that had been retrieved from the data store (i.e. an "existing" one)?  Is there any way your data tier can distinguish the two?

For example:  Is there anything you can do to prevent the UI from creating a Customer object that, when saved, wouldn't overwrite an existing Customer from the database?  Is it important to have this level of distinction?

There's no right or wrong answer here, as the answer may be based on context or usage.  I'm just curious what anyone else has to say about these matters.  For the most part we encounter issues such as these (on some level) almost on a daily basis in designing applications.  I have my solutions, but I want to see what feedback I can get before revealing what I think would be an appropriate answer.

Friday, October 15, 2004 10:15:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |  Trackback

Over the past weeks, I've had the opportunity to periodically devote my efforts to the design and maintenance of a home-grown website that I use(d) to track defects, issues, tasks, etc for my projects that I develop, among other things.  This project has been a pet project for a long time and was, in fact, one of the very first projects that I ever created using the .NET platform.

Since the time of its inception (back in 2001/2002) I have learned a lot and have wanted to take my new-found intelligence and apply it to my old project.  Unfortunately, the application had grown to a point that it wasn't feasible to simply go in with a small hand broom or a dust-vac and straighten things up a bit...it was going to take some heavy lifting.

I therefore put on the gloves and decided to rip the house down and start from a brand new foundation.  I've blogged about some of these underpinnings periodically over the past months, but I wanted to share some of the insights and inroads I've made toward the completion of the project.

First of all, the application performed extremely well with a small number of users.  Granted the application and its back-end database were on the same server.  Being that the application is an ASP.NET application, I want to be able to accommodate many (100+ simultaneously).  This application (now called DevTracker) is designed to be used by a team of developers and provide the experience that a user would expect from a Windows application.  Well, my original design was not very flexible and would be hindered with more than just a handful of users.  I had no clear separation of UI-logic and data access logic.  Except for just a few objects, the lines were very blurred.

<RANT>

In fact, I think this is one of the dangers with ASP.NET development.  Just like VB made it very easy for non-developers to be productive but at the same time create horrendous, terrible code, ASP.NET makes it very easy to create non-object-oriented websites.  Pre-.NET, the push from Microsoft was the Distributed iNternet Application Architecture (DNA).  This set of principles encouraged the separation and distinction of the logical layers (UI, Business, and Data) using technologies such as MTS and COM.  I, along with many others, subscribed to these principles.  With the advent of .NET (particularly ASP.NET) it seemed to be that the lines became more hazy.  All of the sudden people were recommending bringing DataReaders up to the UI level and binding to them, of dropping Connections and Commands right on their .aspx pages and querying the database directly.  For simple applications this might be fine, but I'd far from recommend it for anything that's gonna have to take a lot of load.

Sure, it used to be done before (even in the DNA days).  People would bind to Recordsets and perform database queries right on their pages, but while the rest of the .NET world was moving forward with nice clean OOP, ASP.NET seemed to be left behind; though I hear things will be changing with v2.0.  It's not as easy in an ASP.NET application to separate the layers - especially when it's so darned convenient to copout and do it the easy way.

I believe that developers feel that they need the raw performance available with DataReaders directly on their pages.  They don't want the perceived overhead of offloading the work to another server (say a COM+ server) when that's the kind of work that an application server does best...probably better than anyone could do on their .aspx pages.  What they don't always realize is that the physical distribution of the network can play a HUGE part in an application's performance.  If the IIS server is the same box as the SQL server, there's no IO on the NIC, so it might make more sense to bind to a DataReader.  However, if the IIS server is separate from the database server which is better? 1) performing a round trip to the database server for each DataReader.Read() call? or 2) having the application server gather all the information from the database right there and return it to the web server in one batch?  People often confuse the issues.  Few objects doesn't necessarily mean better performance.

Anyway, enough of that.

</RANT>

I wanted, in DevTracker, to design an optimal architecture that would cleanly support the physical separation of the application layers while at the same time allowing for optimal performance when located on a single machine.  To accomplish this, as a developer I have to maintain a level of discipline - I can't simply decide to do something the quick and dirty way because in the event of component relocation I don't want the application to break.

Many of the services that are presently tightly coupled within DevTracker really affect the larger whole.  These objects should be available outside the scope of the website, but still within the context of the “application“.  For example, I'm wanting to design a Windows/MSN Messenger plugin that would display a user's set of issues, giving the user direct access to them.  I also want to complete a Windows-based UI that feeds off of the same data.  If all of these objects were directly within the ASP.NET application intertwined on my pages there would be no real way to get to them cleanly.  Instead, by distributing the objects (or at least separating them), I can design interfaces (Web Services?) that expose the objects more naturally.

The best way I can envision to do this, and the obvious choice, is to make the libraries available within COM+.  By leveraging the capabilities of Enterprise Services, I am able to offload much of the horsepower to a second server.  That server therefore acts as a floodgate for all database activity, object JITA/pooling, connection pooling, security, and much more; relieving my IIS web server to do what it does best - serve pages.  So far, this strategy has proven to be beneficial and highly performant.  I'll let you all know what my performance tests yield in comparison.

Friday, October 15, 2004 9:54:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, October 08, 2004

As followers of my blog might recall, a few days ago I had my router go out due to a power outage.  Well, as it turns out, I don't believe it was my router after all.  In fact I know it wasn't.  It was my switch.  I had a switch sitting between my router/firewall and my servers and that got fried - literally.  The problem wasn't made manifest to a greater scale until today when smoke started to come out of the top of the switch.  All I can say is thank goodness I was home!  I wouldn't want to have an electrical fire start in my office.

Needless to say, I disconnected it and ran down to Circuit City and purchased a Netgear 8-port switch.  So far so good.

Friday, October 08, 2004 4:15:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, October 07, 2004

There are times in ones life where one is happy to be affiliated with great people and great organizations.  Today, I am very happy to be associated with our local Utah .NET User Group.  We have some fantastic people here that participate.  In many levels, today's user group presentations was a great success.  Rob Howard (formerly of Microsoft, now of TelligentSystems) came to our user group (via INETA) and provided a power-packed presentation on ASP.NET and some advanced, black-belt techniques for optimizing our web applications and making them as performant as possible.

As key points, Rob discussed the importance of properly using the cache.  In particular, leveraging the @ OutputCache page/control directive to cache page/control instances, but also the HttpContext.Items collection (for a per-request caching mechanism).  Rob's talk also mentioned strategies for caching data on the web server side, expiring it only when the data in the database changed.  In order to accomplish this, he proposed having a background task running in the web server that isn't tied to a request.  His solution, which I thought was pretty elegant, was to have a static System.Threading.Timer in an HttpModule (or even in Global.asax) that would periodically run and poll the database for changes.  If the underlying data had changed, the background thread would expire the cache to which the data was bound so that the next request would retrieve fresh data and cache it again for the timer to find yet again - pretty sweet solutions to common, real-world issues.

It was great having Rob there to present to us and spend time with us here in Utah!

If I have any regrets they are minor.  It turns out that INETA (the sponsor for the event) will reimburse a fixed $ amount per head at the event for food (pizza) and drinks based on the evaluations returned.  We didn't have quite as many people attend as we had anticipated so I'm going to end up in the hole some $60-$80 on refreshments...oh well, make that twice that I've ended up paying for pizza for the user group out of my own pocket.

It's all good, I'm happy to do it - I love the camaraderie and the association that I have with such fantastic people - it's well worth it.


Now, I'm looking forward to a great November meeting.  We've done some planning for what looks like it could be a great, interactive meeting.  We're hoping to have a great turnout and have lots of participation!  Stay tuned - I don't want to reveal too much yet...but it'll be loads of fun!

Thursday, October 07, 2004 8:57:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, October 06, 2004

Today is a very exciting day for me (as well as those in our local Utah .NET User Group).  It is with great pleasure that we welcome Rob Howard (formerly of Microsoft on the ASP.NET/.NET Framework teams and now founder of Telligent Systems).  Rob will be providing a presentation entitled “10 'Killer' Performance Tips and Tricks for ASP.NET”.  I'll provide a report of the event later tonight after the meeting...this is going to be awesome!

If you'd like to attend, please 1) RSVP and let me know and 2) show up.  It's free and anyone and everyone is welcome.  Our local .NET User Group meets at Northface University which is kind enough to offer us space at their facilities each month.

Here are the details about tonight's meeting:

Date: October 06, 2004
Time: 6:00 PM
Northface University
10701 South River Front Pkwy, 2nd Floor
South Jordan, Utah 84095

Wednesday, October 06, 2004 8:04:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I have found it's a lot easier to blog about solutions to problems because of the turmoil and heartache involved as well as the victorious feeling of relief when the issue has been resolved.  In an attempt to be more proactive to coding solutions, rather than reactive, I will work on providing more valuable blog entries not so much about problems overcome, but techniques and strategies that I employ in my day-to-day programming because I feel that some of that experience would be valuable to someone out there in the wild wild web.

Today's blog entry, however, is not one of those blog entries.  I'm going to talk about a problem solved.  I was taught a very valuable lesson today - again.  Here's the deal:

I am working on an ASP.NET application that dynamically loads various controls depending on the user's context with the application.  Some of the controls I wrote as Server Controls while others are User Controls.  Within a particular user control (.ascx) I had placed some hidden controls (HtmlInputHidden) that provide UI feedback to the server so I can take appropriate action.

When the form was posting back to the server I couldn't see the values within the controls.  That is, the .Value property would ALWAYS return the default value (at least it would return the value assigned in the <input /> tag).  No matter what I did.  Interestingly, however, I could SET the value and that would get posted back to the server.  The only way I could ascertain this was to inspect the form's posted values - indeed the correct value was always there, but it was never associated with the control variable.

As it turns out, and it is with much embarrassment that I even admit this, I was loading the control too late in the hosting page's lifecycle.  I had the call to LoadControl(”...ascx”) in the OnLoad() method.  Instead, it belongs in the OnInit() method andthat's because the ViewState is loaded back in the controls after the OnInit and before OnLoad.  I don't know how I overlooked that, but I did.  I don't think I'm going to forget that lesson ever again.

In order to properly associate control values, property values, events, etc with dynamically loaded user controls, you must always instantiate the control in the OnInit() method (or the Page_Init() event) and add it to the parent control's .Controls collection therein:

protected override void OnInit(EventArgs e) {
   MyControl ctl = (MyControl)LoadControl(”MyControl.ascx”);
   Page.Controls.Add(ctl);
}

Wednesday, October 06, 2004 7:56:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, October 05, 2004

Sorry for the non-technical post, but I must agree with Sam Gentile.  I saw Sky Captain and the World of Tomorrow on opening weekend and thought it was a blast.  I couldn't precisely nail down what I liked about it, but I think Sam hits the nail on the head: it's a mixture of (semi-)modern sci-fi with a Flash Gordonesque, 30's style.  I absolutely love the pastel, sepia color used throughout the flick.  I am definitely one for nostalgia, and watching this movie I felt once again like a kid.  Watching the characters travel over the globe with the super-imposed lat/long lines and compass beneath the surface of the water was fantastic; that and the abnormally enlarged radio tower summoning Sky Captain...Watching it reminded me too much of the old George Reeves Superman...though the movie wasn't that corny.

I normally wouldn't be posting something like this, but it turns out that during my weekly programming session with a group of friends last night we were talking about just this movie.  Then reading Sam's blog I couldn't help it.  Go see the movie if you haven't yet!

Tuesday, October 05, 2004 7:45:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, October 04, 2004

By no stretch am I an Xml guru.  I know enough to get by and can be pretty dangerous with it.  I stumbled upon this tool by Jeff Key that I find extremely useful.  I deal with a lot of XML as single, long strings.  I want to view the Xml in a hierarchical node-tree view and while IE gives me that (to a limited degree), this tool gives me much more power with a very small learning curve.

  • You can view your Xml loaded from a file
  • You can view your Xml loaded from the clipboard.  Nice!  While this functionality might be expected, I'm glad the Jeff took the time to support such functionality.
  • Organizes your Xml indented (regardless of whether it came in in that format or not)

Now if you're wanting more power and capabilities, but at a steeper learning curve, there is also the XMLSpy 2004 Home Edition (which is free) or the Professional or Enterprise versions.

Unless I absolutely need the added functionality, though, I'll be sticking with Jeff's tool...thanks Jeff!

Request:  Support XPath queries for searching; it would help facilitate using a single tool for my basic XML needs, rather than having to jump between tools to perform those queries.

As you can see, sometimes the simplest of things gets me excited because I've been wanting this capability for a long time, but haven't taken the time to write it myself.

Monday, October 04, 2004 8:47:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Saturday, October 02, 2004

I consider myself a pretty good ASP.NET developer.  However, it doesn't matter how many times I try to do it, I can't seem to remember how each of the path functions on the Request and Page/Control objects work.  Invariably I find myself opening MSDN or tediously debugging and stepping through my code, making heavy use of the Command Window or the Quick Watch dialog.

Thanks to Rick Strahl for consolidating these functions in a manner that's easy to read and understand. :-)

Saturday, October 02, 2004 3:54:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback