Jon Flanders' Blog

Magic Methods (or the basics of deriving from ServiceHostBase)

Wednesday, August 08, 2007 6:54:57 PM (GMT Daylight Time, UTC+01:00)

Considering my history using ASP and COM – you can imagine I’ve always been a fan of interface-based design.  Of course, I’m not a religious zealot of any sort, so I’ve always been comfortable with the idea of abstract base classes as another perfectly valid way to create pluggable, extensible systems.  This post is about one such pluggable system which utilizes abstract base classes – and how that kind of design can just be stupid (not based on the concept of abstract base classes, but just based on dumb design of such a system).

Harry has been bugging me to post about creating classes that derive from ServiceHostBase, which I have done quite a few times in the past year or so.  The next technical post I make after this one will be about the ins and outs of creating a class that derives from ServiceHostBase (specifically to host workflows as WCF Endpoints), but I’ve had this post on my chest for a while and I just had to let it out (although as I am writing the post I am finding that it is a pretty decent introduction to ServiceHostBase – interspersed with slight vitriol). 

One of the things I strive for whenever I design an abstract base class is to make sure that it is as simple as possible to derive from and implement that base class.  One of the great features in Visual Studio (VS) is that via reflection VS can determine what methods *must* be implemented for a particular base class when you build a derived class.

Let’s take a simple example.  Imagine a base class named “Base” which is marked as abstract and which has one method, named “VirtualMethod”. (I know this is pretty simplistic, but I feel it may be the only way to get the WCF team at MS to understand the issue).

 public abstract class Base

{

    public abstract string VirtualMethod(string param);

}

Now imagine you want to derive from that base class and create a class named “Derived” which implements all the abstract methods of this base class.  Here is an example implementation:

public class Derived : Base

{

 

    public override string VirtualMethod(string param)

    {

Console.WriteLine("This should work: {0}",param);

        return "Implemented VirtualMethod";

    }

}

 

A cool feature related to abstract base classes in Visual Studio 2005 is that once you type “public class Derived : Base”, there is smart tag hovering over the Base keyword.  If you select that smart tag with the mouse (or use the Alt-Shift-F10 keyboard shortcut as I like to do), you get a context menu which states that it will “Implement abstract class ‘Base’” for you.

I personally find the Alt-Shift-F10 shortcut to be super useful (it can also be used to implement an interface).  I also think from a *moral* point-of-view that, when I derive from an abstract base class and use Alt-Shift-F10 (or just manually implement *all* the abstract methods), my derived class should *work* in whatever context the base class is supposed to work (which is really the point of abstract base classes right?).  The whole point of marking methods “virtual” is to force the derived class implementor to provide an override of those methods.   Whatever code uses the base class methods should work with a complete, correct implementation of the base class (of course the C# or VB.NET compiler won’t let you complie an incomplete implementation, but it certainly will let you compile an incorrect one).

So what would you think  if you downloaded some library from some company which was based on some OO language which supported abstract base classes, and you did the above steps (implementing all the abstract methods), and then when you plugged your class into the framework for that class, your class didn’t work?  What would you think if it didn’t work *and* the exception you got was a blatant lie about why your nicely implemented dervied class didn’t work?

In fact, WCF provides such a framework (and has such an exception – you’ll just have to keep reading for that) for creating derived classes that can plug into its framework.  ChannelListeners are the channel manager used to provide service Endpoints – that is Endpoints which listen for incoming messages in WCF. The way you load up ChannelListeners in WCF, in the general case,  is to use a class named ServiceHost.  ServiceHost is a useful class that enables you to associate one or more endpoints with a .NET class which implements one or more contracts, and thus hosts one or more contracts on one or more endpoints.  ServiceHost is a really useful class in WCF (fairly essential actually).

In the ASP.NET/WPAS hosting scenarios, you don’t actually get to create your own ServiceHost type – the ServiceHost is created implicitly based on your .svc file (with help from your web.config file for the binding and potential behaviors). To create the ServiceHost, the WCF HttpHandler actually uses a class called ServiceHostFactory, which is a fairly typical generic Factory pattern implementation (handing out ServiceHost objects to requestors).  This features is a really cool extensibility point of WCF, one that can be used for things ranging from controlling Behaviors on your ServiceHost (i.e. not relying on configuration for features like ServiceMetadataBehavior or ServiceDebugBehavior) to replacing the ServiceHost/.NET Type pairing paradigm with some other paradigm.  Steve Maine has some good info on ServiceHost/ServiceHostFactory  here.

So more than a year ago I ventured to write my first custom ServiceHost/ServiceHostFactory pairing.  Here’s my story of that adventure.  Just to make it a little more interesting, and to see how the plumbing is put together in WCF,  I chose to derive from ServiceHostBase and ServiceHostFactoryBase (see Steve’s article above about the choices between deriving from ServiceHost or ServiceHostBase).  So I fired up Visual Studio and created classes that derived from ServiceHostFactoryBase and ServiceHostBase. Using my Alt-Shift-F10 trick – this is what I end up with (after removing the throw clauses that Alt-Shift-F10 place inside of each overriding method):

public class MyServiceHostFactory : ServiceHostFactoryBase

{

public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)

    {

    }

}

 

public class MyServiceHost : ServiceHostBase

{

protected override ServiceDescription CreateDescription(out IDictionary<string,ContractDescription> implementedContracts)

    {

 

    }

}

Of course at this point the code won’t compile, since I haven’t actually provided implementations.  The implemenation of CreateServiceHost is pretty easy – all I need to do there is create an instance of ServiceHostBase.  In the typical case, your ServiceHostBase implementation will have a constructor that takes both of the arguments passed to CreateServiceHost.  The OOB implementation (ServiceHost) uses the first argument to figure out what .NET Type should be used to implement the service Endpoints around, and uses the second argument as list of base Uris that relative Uri’s can hang off of the base addresses (assuming the Endpoint’s transport channel matches the scheme of the base Uri).  So that’s pretty easy.  I’ll store those two parameters in instance fields on the MyServiceHost Type, as we’ll need them later.

The interesting part here is implementing ServiceHostBase::CreateDescription.  CreateDescription is really the key to making your ServiceHostBase implementation work within the WCF infrastructure.  From the look of the return value (ServiceDescription) you might get the mistaken idea that the ServiceDescription is only used by WCF to publish metadata (assuming metadata publishing is enabled on your Service).  This is really pretty far from the truth.  The instance of ServiceDecription returned from your ServiceHost (as well as the out parameter – the generic dictionary of strings and ContractDescriptions) is used for more than just metadata publishing.   It is used by the WCF dispatching layer to route messages received via the Channel layer down to the Service layer (the piece we are trying to implement).  Creating a valid ServiceDescription and returning the list of implemented contracts is essential for making your ServiceHostBase-derived class work.

So let’s assume I create a valid return value and out parameter for CreateDescription (the next post will get into the necessary detail on how exactly to accomplish that).  Once I do so, notice that there are no more virtual method to implement from ServiceHostBase.

Next, I need to get my custom ServiceHostBase derived class loaded by WCF.  In the typical WCF hosting scenario in IIS there is a .svc file.  The .svc links to the “Service Type” – the .NET Type that WCF will use as the basis for the endpoints exposed via the Uri ending in .svc.  Here is a typical example:

<% @ServiceHost Language=C# Debug="true" Service="MyService" CodeBehind="~/App_Code/Service.cs" %>

In the IIS hosting case, the value of the Service attribute from the ServiceHost directive is passes as the parameter to the ServiceHostFactory:CreateServiceHost and to the typical contstructor of ServiceHost. 

To load your own custom ServiceHostFactory all you need to do is add a Factory attribute to the ServiceHost directive.  Like this:

<% @ServiceHost Service="MyService" Factory="MyServiceHostFactory" %>

When I do all this and browse to the URL for the Service, I get this lovely exception in the browser:

 

For search engine purposes - the exception/lie is "InitializeRuntime requires that the Description property be initialized" (this part isn't a lie) - "Either provider a valid ServiceDescription in the CreateDescription method or override the InitializeRuntime method to provide an alternate implementation". 

So I begin to scratch my head (this is me retelling the story when I first wrote this code oh-so-long-ago).   I generally always assume that when something like this happens, *I’ve* done something wrong.  So I assume my instance of ServiceDescription must be invalid, since I *definitely* implemented the abstract methods from ServiceHostBase.

Here is where things get ugly. I spent an afternoon looking through Reflector  to figure out where I had gone wrong.  I even went to the trouble to delegate to an instance of ServiceHost to get what I knew to be a valid ServiceDescription.  Once I had done that and I was still getting the same exception, I began to think it wasn’t *my* implementation of CreateDescription, but something else.  This of course (about 4 hours later) led me down another Reflector expedition into what ServiceHost was doing that I wasn’t.

Finally after another hour or so – I stumbled upon it.  In the *constructor* of ServiceHost (not ServiceHostBase mind you – but WCF’s OOB implementation of ServiceHostBase) there is a call to InitializeDescription.  InitializeDescription calls another method, which in turn sets the ServiceHostBase.description field (which is *private* BTW so I couldn’t set the value myself) to the  return value of the call to CreateDescription.

So the *only* way to make a ServiceHostBase derived class work inside of this infrastructure is to call a “magic” method inside of your ServiceHostBase constructor.  Failure to call IntializeDescription will lead to complete failure when implementing a derived class of ServiceHostBase.

So now that I have all my pent-up frustration out – what are the key points here?

1)      This is a stupid design – if I implement all the abstract methods of an abstract base class my class should work.  Period.  Unless there is some super compelling reason – this should also be the case with interfaces (see ISerializable for what I would consider to be a valid exception to this rule where you must implement a special constructor for deserialization purposes).

2)      WCF has no such special reason.  In fact, if you look at the implemenation of InitalizeRuntime, all it does is check to see if the value of the Description property is null or not (the Description property is a public read-only property on top of the ServiceHostBase.description field).  If it is null, the stupid exception I showed above is displayed.   Are you telling me ServiceHostBase:InitializeRuntime couldn’t reasonably add one line of code to call CreateDescription after discovering that the property is null.  And *then* throw this exception after that call returns null?  Or the Description property itself could be responsible for calling InitializeDescription if the field was null (this was Harry’s suggestion).

So basically this means the exception I got is a blatant lie.  I did provide a perfectly valid ServiceDescription from my CreateDescription method.  It’s just that ServiceHostBase never calls CreateDescription.  Instead - in my derived class – in my constructor – I have to call another method (InitializeDescription) which then in turn will cause the description field to be properly filled in with the return value of my totally correct/valid ServiceDescription (which I have to rely on since the description filed on ServiceHostBase is private).  Which, mind you,  I had created 6 hours before I discovered the magic InitializeDescription method.

Please folks (at MS and elsewhere) don’t design abstract base classes that rely on magic methods to work correctly.  It makes me testy.  It’s dumb.  What else can be said about it? How about – IT’S DUMB (ahh – I feel  better already).

Alt-Shift-F10 plus actually implementing all the methods correctly should be enough (barring some real circumstance which might make making a magic method necessary – and if that’s the case – document the hell out of it).

 

WCF   #    Comments [2]   

Wednesday, August 08, 2007 7:33:07 PM (GMT Daylight Time, UTC+01:00)
Jon -

good post!

But please use Ctrl+. instead of Alt+Shift+F10 in the future ;)
Wednesday, August 08, 2007 7:47:00 PM (GMT Daylight Time, UTC+01:00)
Hey Dom - Ctrl+ doesnt work for me - did you remap your keyboard?
All comments require the approval of the site owner before being displayed.
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview