Saturday, July 23, 2011

Trial and Error–WCF Services Part 3 (split to IIS Hosting)

After a bit of frustration with the WCF host and client, I decided it would be easier to split the client and service host projects.  I did this, relatively easily but now the problem was getting the host to start first and then the client…and having the host start when doing work on the WCF service itself and keeping the client reference updated.  Well, simply put, it was going to be a big pain (having 2 VS 2010’s open isn’t bad…but starting up the host every time I wanted to test or make a change would have been).  I’ve also been considering having a web host to host these services – and the thing with most hosting providers, they don’t allow Windows services nor console/windows applications (and I wasn’t going to pay $45+/mo to have a hosted virtual server) so my only route was having the service hosting in IIS.  Since most providers that allow WCF are running Windows 2008 or 2008 R2, this meant IIS 7 or 7.5, which means it’s compatible with my development environments within Windows 7, thankfully.

So, the client is now in it’s own solution.  The client in this case is only for testing – the real client will be in the app.  The client is “easy” to create as long as VS 2010 can get a service reference – with the client and host in one solution, that was becoming a pain.  With IIS hosting, that pain should go away.

The service solution had a dll that contained the real “service” (the service contract and an implementation of that contract) and a console host.  I’ve added a new WCF Windows Service project as described in the blog post (http://blog.lyalin.com/2008/04/creating-quick-sample-iis-hosted-wcf.html).  Although this blog describes VS 2008, it applies to VS 2010 without any changes.  I tried to cheat and extend my service library dll service class (with changing the SVC code behind as well) but, alas, when I browsed to the service, it basically told me that the ServiceContract cannot be inherited.  So, to avoid that fight, I copied my library code into the new IIS hosted service project and removed the old library – I didn’t see a use for the old library outside of various hosting methods or for debugging…ah, debugging – hard to debug an IIS service with console write’s so I decided to keep the old console host so that I could see what was going on in the service though console writes (yes, archaic, I know – but works).  I added a normal reference to the new Library dll in the host console application – no other code needed to be changed.

Now my hosting/service solution looks like this:

image

To publish the service to IIS, be sure to follow the instructions in the mentioned blog as VS will host it by default if those aren’t followed.  Then right click on the WCF project and click Publish.  A dialog box similar to the following should appear.  For my settings, I set the service URL to my local machine and the site/application to one of the similar examples shown (eg Default Web Site/MyApp).  Since this is a WCF service, I set the “Mark as IIS Application” and left everything else default.

image

After a successful publish, VS appears to update the Web.config file so it may ask if you want to update the file to the most recent changes.

To make sure everything works as expected, right click on the service file [yes, service file, not the project], then go to View In Browser.  The familiar “You have created a service.” should appear.  If not, check the Web config of the service and make sure the following line is set.  VS 2010 creates the web config file and, by default, sets this to true for you.

<serviceMetadata httpGetEnabled="true"/>

Now, if we start the project, we should see the console host, as normal, which, according to it’s app config file will be using port 8000 instead of the IIS default of port 80. So, in the client, this will need to be changed accordingly depending on whether we want the IIS version or the console hosted version.  For proof the host still works:


image


And with the client making a call against the console host


image


Unfortunately no easy way to tell if the IIS hosted version is working as expected (other than the fact it is using the exact same code, just a different hosting method).  The easy way to check communication is to change the app config of the client to point to port 80.


Run the client again and we get:


image


Hmm…EndpointNotFoundException – but why?  Well, let’s look at the service again in IIS – viewing the service in the browser we get and address of http://localhost/ExpressRecipeWCFLibrary/UserService.svc.  But if we look at the client app config file we have:


http://localhost/UserService


Ok, two problems – application name we set when we published is showing in the URL and so is the .svc.  Setting the app config service location fixes the problem, but, debugging with the console hosting app now goes away until it’s changed back.  (just for curiosity sake, I tried to publish without the application name and my VS crashed…so, probably not a good way to get around this issue).  Haven’t tried yet, but defining an endpoint for each the console and IIS host may be an option (an option which would have to be repeated for n services – could easily get nasty)…  A workaround is to set the console base address to be that of the IIS service address, just be sure to change the port number – seems to work for this case.  This may need a more elegant solution soon, maybe modifying the port or endpoint based on if it’s in DEBUG or just a normal build…anyway, something else to think about.

Saturday, July 16, 2011

Trial and Error–WCF Services Part 2

As promised in my last WCF post, in this  post I’ll create the client that connects to the WCF service host that was created earlier.  Since the host is pretty simple at this point, so will the client and test be.

First things first, I need to create a project that’ll use the client – figured it would be easiest to do that in the same solution as the host.  So, I added a new project called ExpressRecipeServiceClient (technically this is poorly named as the client/proxy will be generated elsewhere).

Ok, so far so good – now to add the WCF reference, which in turn will generate the client/proxy code.  So, at the client project, I right click, go down to Add Service Reference.  Easy enough so far and is mostly the same as adding a project reference.  The Add Service Reference dialog comes up and I click Discover – thinking VS would see I have a WCF host.  Nope – nothing happens.  Ok, so I go back to the book and it says I need to manually start the host project without using debug…ok, try literally exactly that, start the host solution using Run, not Debug but I run into the problem of not being able to add any new references to any project that way.  I finally realize it means run it at the command line…so, I navigate over to the bin directory of the project and start the host there…host appears happy so I go back to VS and try to add the service through discover…still nothing.  So, I try making sure the service host is running by accessing the WSDL through IE – yep, works as it did.  I noticed on t e WSDL description that it says to use this URL to create a proxy – in my case, http://localhost:8000/UserService/?wsdl.  I put that in where it asks for address, then press go.  And, guess what, it appears to have worked.


image

Great…now, set the namepace something useful (ExpressRecipeService in my case) and then click ok (ignoring the advanced options – for now).  A new reference will appear under Service Reference with the namespace that was provided earlier.

Now for the test.  I still have the WCF host running from the command line.  In the newly created client project, I make a call similar to this

ExpressRecipeClient.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace ExpressRecipeServiceClient
  7. {
  8.     class Program
  9.     {
  10.         static void Main(string[] args)
  11.         {
  12.             ExpressRecipeService.ExpressRecipeUserContractClient client = new ExpressRecipeService.ExpressRecipeUserContractClient();
  13.             client.AddUser("test1", "test2", "test3", "test4");
  14.         }
  15.     }
  16. }

Basically, create a new client for the host and call the only user-generated procedure, AddUser, with fake test parameters.  My expectation is that those will be printed out on the host console screen.  Guess it’s time to run, so F5.

Oops…”HTTP could not register URL http://+:8000/UserService/. Another application has already registered this URL with HTTP.SYS.”  Guess we should kill the console running host and try again.  Basically the error means something else is using that transport at that same port.

Kill the console host, then F5 again and here’s what I see from the host screen…well, nothing new – client never comes up but host does.  Gotta make the solution start multiple projects so set the host to start first, then set the client to start.  Run again and I get:

image

Ok, that wasn’t goo bad…going to need to do a bit more complicated things in the host but so far so good.

Factories in C#-Basic, Cached, and Dynamic

Introduction

It seems that one of the more common operations in modern object orientated languages is creating new objects.  In most languages, this is accomplished by using the “new” operator…this is nothing new for most of us out there who’ve been doing OO programming for any length of time.  For those who haven’t been, here’s the general idea – we have a class we want to create and use (let’s say a “Dog”) in our main program.  Here’s the Dog class:

Dog.cs
  1. public class Dog
  2. {
  3.     protected string AnimalType { get; private set; }
  4.  
  5.     public Dog()
  6.     {
  7.         AnimalType="Dog";
  8.     }
  9.  
  10.     public void IntroduceSelf()
  11.     {
  12.         System.Console.WriteLine(IntroductionLine);
  13.         System.Console.WriteLine(Speak);
  14.         System.Console.WriteLine();
  15.     }
  16.  
  17.     protected string IntroductionLine
  18.     {
  19.         get
  20.         {
  21.             string introLine = "Hello, I am a " + AnimalType;
  22.             return introLine;
  23.         }
  24.     }
  25.  
  26.     protected string Speak
  27.     {
  28.         get
  29.         {
  30.             return "Woof";
  31.         }
  32.     }
  33. }

And to create a new Dog we do this in our main program:

Program.cs
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         Dog dog = new Dog();
  6.         dog.IntroduceSelf();
  7.  
  8.         System.Console.WriteLine("Press <enter> to end");
  9.         Console.ReadLine();
  10.     }
  11. }

Ok, simple enough, right?

Well, let’s say the requirements expand and we now need to create a cat and a dog.  [ok, now, you ol fogies – I know you already know this…just skim down if you’re bored].  So, we create a new class named Cat that does pretty much the same thing as the Dog class did, with obvious exceptions.  [At this point, if you’re an OO programmer, alarm bells should be going off in your head – Cat class does pretty much the same thing as the Dog class].

So, here’s the Cat class -

Cat.cs
  1. public class Cat
  2.     {
  3.         protected string AnimalType { get; private set; }
  4.  
  5.         public Cat()
  6.         {
  7.             AnimalType = "Cat";
  8.         }
  9.  
  10.         public void IntroduceSelf()
  11.         {
  12.             System.Console.WriteLine(IntroductionLine);
  13.             System.Console.WriteLine(Speak);
  14.             System.Console.WriteLine();
  15.         }
  16.  
  17.         protected string IntroductionLine
  18.         {
  19.             get
  20.             {
  21.                 string introLine = "Hello, I am a " + AnimalType;
  22.                 return introLine;
  23.             }
  24.         }
  25.  
  26.         protected string Speak
  27.         {
  28.             get
  29.             {
  30.                 return "Meow";
  31.             }
  32.         }
  33.     }

And our main program to create a dog and cat looks like this:

Program.cs
  1. class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             Dog dog = new Dog();
  6.             dog.IntroduceSelf();
  7.  
  8.             Cat cat = new Cat();
  9.             cat.IntroduceSelf();
  10.  
  11.             System.Console.WriteLine("Press <enter> to end");
  12.             Console.ReadLine();
  13.         }
  14.     }

Ok, not bad…and we solved the requirements…but, look at all that duplicated code…what if the requirements change again (and, believe me, they will)?  What if we added 50 animal types and then we found a bug that was common in all that code…50 classes would have to change to fix that bug.  What’s the answer?  Using the OO concept of inheritance.

Brief Overview of Inheritance (as it pertains to Factories)

One of the key features of inheritance is the ability to reuse code from a class higher up the inheritance chain (such as a parent or grandparent [or from a base class in C# terms]).  This reused code can be in the form of functions/procedures, data members, or properties (I’m specifically referring to class inheritance here, not inheritance via interfaces).  So, what does this have to do with factories and creation of objects – inheritance is a prerequisite to getting a factory to work for object creation.  So, let’s go ahead and use inheritance and get rid of some of this duplicated code…and, while we’re at it, let’s create a new animal class for a pig.

We’ll start with an abstract base class.  We really don’t want to be creating an animal by itself and there are some things the animals themselves will know how to do that this base animal class won’t (i.e. how to speak).

AbstractAnimalBase.cs
  1. public abstract class AbstractAnimalBase
  2.     {
  3.         protected string AnimalType { get; private set; }
  4.  
  5.         public AbstractAnimalBase(string type)
  6.         {
  7.             AnimalType = type;
  8.         }
  9.  
  10.         public void IntroduceSelf()
  11.         {
  12.             System.Console.WriteLine(IntroductionLine);
  13.             System.Console.WriteLine(Speak);
  14.             System.Console.WriteLine();
  15.         }
  16.  
  17.         protected virtual string IntroductionLine
  18.         {
  19.             get
  20.             {
  21.                 string introLine = "Hello, I am a " + AnimalType;
  22.                 return introLine;
  23.             }
  24.         }
  25.  
  26.         protected abstract string Speak
  27.         {
  28.             get;
  29.         }
  30.     }

Ok, now for the dog, cat, and pig classes that will use this base class.  Take a look at how much shorter these are than the original version that didn’t use inheritance.

Dog.cs
  1. public class Dog : AbstractAnimalBase
  2.     {
  3.         public Dog()
  4.             : base("Dog")
  5.         {
  6.         }
  7.  
  8.         protected override string Speak
  9.         {
  10.             get { return "Woof"; }
  11.         }
  12.     }

 

Cat.cs
  1. public class Cat : AbstractAnimalBase
  2.     {
  3.         public Cat()
  4.             : base("Cat")
  5.         {
  6.         }
  7.  
  8.         protected override string Speak
  9.         {
  10.             get { return "Meow"; }
  11.         }
  12.     }

 

Pig.cs
  1. public class Pig : AbstractAnimalBase
  2.     {
  3.         public Pig()
  4.             : base("Pig")
  5.         {
  6.         }
  7.  
  8.         protected override string Speak
  9.         {
  10.             get { return "Oink"; }
  11.         }
  12.     }

Ok, now to the meat of this post.

Introduction to Factories

So, what is a factory anyway and what can it do for us?  In layman terms, a factory is a piece of code that returns back a specific object from a given input.  Ok, so what’s so special about that, right? – new does that for me.  That’s correct, but, what if you don’t know what type of object you want while you’re coding?  That’s where the factory comes in – you tell the factory what type of object you want and it will return the object needed for that type to you.  In more programmer speak, a factory is one of the Gang of Four design patterns that is used to create objects without having to specify the exact class that will be created.

Yes, I know, you’re the programmer and you will always know what object you need and when - will you though?  Let’s say you’re reading a config file and wanting to do certain operations or load certain values based on the config – do you always know what and how it will be configured?  Or, let’s say you’re reading a database and you’ll have to load data from different tables depending on what the value of a specific field is…or, you’re looking at the file system for images and you come across a JPG and the next image is a GIF.  Each of these is a good candidate for a factory.

Typically, a factory is a static class and/or a static method.  Having the factory class static allows access to it without having to create an instance of the factory class.

Basic Factories

Factories using Strings

The factory method will generally return the common base class or common interface of the objects that could be created by the method…normally the structure is simple, either in a if-else or in a switch statement.  So, for the animal factory, we’d have something like the following code:

AnimalFactory.cs
  1. public static class AnimalFactory
  2.     {
  3.         public static AbstractAnimalBase CreateAnimal(string type)
  4.         {
  5.             type = type.ToLower().Trim();
  6.             switch (type)
  7.             {
  8.                 case "dog":
  9.                     return new Dog();
  10.                 case "cat":
  11.                     return new Cat();
  12.                 case "pig":
  13.                     return new Pig();
  14.                 default:
  15.                     throw new Exception(String.Format("Unknown animal type {0}", type));
  16.             }
  17.         }
  18.     }

Factories using Enumerations

A complaint with the above code is that it’s using strings to do the matching, which some claim is inefficient (due partly to the to lower and trim calls) and error prone (if you misspell, it’ll fail).  This can easily be changed to use an enumeration, which will gain some speed (no need for string manipulation) and is less error prone but adds a little bit more maintenance to the code – the programmer has to update the enum as well as the factory code.  Here’s the same code but using an enumeration instead:

AnimalFactory.cs
  1. public static class AnimalFactory
  2.     {
  3.         public enum AnimalEnum
  4.         {
  5.             Dog,
  6.             Cat,
  7.             Pig
  8.         };
  9.  
  10.         public static AbstractAnimalBase CreateAnimal(AnimalEnum type)
  11.         {
  12.             switch (type)
  13.             {
  14.                 case AnimalEnum.Dog :
  15.                     return new Dog();
  16.                 case AnimalEnum.Cat:
  17.                     return new Cat();
  18.                 case AnimalEnum.Pig:
  19.                     return new Pig();
  20.                 default:
  21.                     throw new Exception(String.Format("Unknown animal type {0}", type));
  22.             }
  23.         }
  24.     }

Well, that’s it for the factory, right?  Well, in the general case, yes…but, there are a couple specific instances that I’ve found a use for lately that someone else may be interested in.

Cached Factories

There are times when creating a class is a long running process and you want to cache this data so you don’t kill your performance, but, the classes that do this all inherit from a base class so they are candidates for a factory pattern.  The sample factories above would create a new animal each time that type is requested – which could run a long-running process.  The cached factory helps with this situation…one thing to note with the cached factory it will return back the same object instance for a specific given type (not that this isn’t necessarily a singleton instance of a class).  So, for example, using the animal example above, the program requests a dog for the first time, a dog (#1) is created and returned back to the caller…on the second call to get a dog, dog (#1) is still returned to the caller…let’s say the code is slightly different than above and we return back a dog for an input of “mut”…with this situation, the program passes in “mut” and we get back a different instance of a dog (#2).  So, don’t get cached returns confused with singletons.

Now, for the code for a cached factory.  Pretty similar to the others but it uses a dictionary to keep hold the type and the returned value.  The code could easily be expanded to allow removal of cached values, etc, if needed.

AnimalFactory.cs
  1. using System.Collections.Generic;
  2.     public static class AnimalFactory
  3.     {
  4.         private static Dictionary<string, AbstractAnimalBase> AnimalCache { get; set; }
  5.  
  6.         public static AbstractAnimalBase CreateAnimalCached(string type)
  7.         {
  8.             if (AnimalCache == null)
  9.             {
  10.                 AnimalCache = new Dictionary<string, AbstractAnimalBase>();
  11.             }
  12.  
  13.             type = type.ToLower().Trim();
  14.  
  15.             if (!AnimalCache.ContainsKey(type))
  16.             {
  17.                 AbstractAnimalBase animal;
  18.                 switch (type)
  19.                 {
  20.                     case "dog":
  21.                         animal = new Dog();
  22.                         break;
  23.                     case "cat":
  24.                         animal = new Cat();
  25.                         break;
  26.                     case "pig":
  27.                         animal = new Pig();
  28.                         break;
  29.                     default:
  30.                         throw new Exception(String.Format("Unknown animal type {0}", type));
  31.                 }
  32.                 AnimalCache.Add(type,animal);
  33.             }
  34.             return AnimalCache[type];
  35.         }
  36.     }

Alternate “Factory” (Cache)

An alternate version of the above factory eliminates the switch statement – so, each animal object will be created and cached…but, each object must manually be created outside the factory (hmm, kinda longer a factory if the object is created elsewhere, is it?) – but that add could be technically done from anywhere, according to the permission of the function/class.  So, the main method could add to the factory and other classes within the application use the factory with what was loaded from main.

AnimalFactory.cs
  1. using System.Collections.Generic;
  2.     public static class AnimalFactory
  3.     {
  4.         private static Dictionary<string, AbstractAnimalBase> AnimalCache { get; set; }
  5.  
  6.         internal void AddAnimalToCache(string type, AbstractAnimalBase animal)
  7.         {
  8.             if (AnimalCache == null)
  9.             {
  10.                 AnimalCache = new Dictionary<string, AbstractAnimalBase>();
  11.             }
  12.  
  13.             type = type.ToLower().Trim();
  14.  
  15.             if (!AnimalCache.ContainsKey(type))
  16.             {
  17.                 AnimalCache.Add(type, animal);
  18.             }
  19.             else
  20.             {
  21.                 throw new Exception(String.Format("Animal type {0} already exists", type));
  22.             }
  23.         }
  24.  
  25.         public static AbstractAnimalBase GetAnimalFromCache(string type)
  26.         {
  27.             if (AnimalCache == null)
  28.             {
  29.                 AnimalCache = new Dictionary<string, AbstractAnimalBase>();
  30.             }
  31.  
  32.             type = type.ToLower().Trim();
  33.  
  34.             if (!AnimalCache.ContainsKey(type))
  35.             {
  36.                 throw new Exception(String.Format("Unknown animal type {0}", type));
  37.             }
  38.  
  39.             return AnimalCache[type];
  40.         }
  41.     }

Dynamic Factories

One thing that has always bothered me about the factory is having to add a class for what I want and then having to also modify the factory and maybe even an enum.  There has to be a way for classes to “self register” themselves with a factory…well, there is with the above code – the constructor of each subclassed animal can add itself to the factory.  Well, that’s great…but who is going to call the constructor for each of those sub-classes?  Too bad the base class can’t determine it’s subclasses…or, wait, it can, but indirectly – through reflection.

Couple words on reflection and creating a factory in this way – reflection is “slow” in general, so you’ll probably want to cache the objects that are created and you probably only want to discover your classes once – on start up or on first use of the factory.  Also, with this method, I’ve only used no-parameter constructors…and all the classes match that no-parameter constructor rule – probably ways around it but it will be a bit more coding to deal with that (i.e. it’s not as easy to do as with a normal factory).  And, while this may be a way to dynamically discover classes for your factory, it raises some security concerns as well so code accordingly.  So, use at your own risk basically.

Ok, enough with the legal warnings and notices.  On to the code…

Brief Introduction to Reflection (as it pertains to Dynamic Factories)

So, the first question is how do we find out what classes are within a file?  .Net actually makes this fairly simple…we have to load the assembly (i.e. dll or exe) into memory, then we can get all the types within that file.  Essentially the code to do this is:

Code Snippet
  1. Assembly assembly = Assembly.LoadFrom(filename);
  2. Type[] types = assembly.GetTypes();

Where filename is the full path to an exe or dll that we want to inspect.

Discovering Interested Types

Next, we just iterate over all the types to see if they match what we’re looking for.  We’ve got to be careful here as a type could be an interface, an abstract class, or not even a class that we’re interested in.  For this, I’ve written a routine to verify a type is what I’m interested in.

Code Snippet
  1. protected static bool IsValidAnimal(Type type, ref AbstractAnimalBase animal)
  2. {
  3.     //is it a sub-class
  4.     if (type.BaseType != null)
  5.     {
  6.         //make sure it's not an interface
  7.         if (!type.IsInterface)
  8.         {
  9.             //is it a sub-class of what we're interested in
  10.             if (type.IsSubclassOf((typeof(AbstractAnimalBase))))
  11.             {
  12.                 //make sure the type is a concrete type (i.e. not abstract)
  13.                 if (!type.IsAbstract)
  14.                 {
  15.                     try
  16.                     {
  17.                         animal = (AbstractAnimalBase)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { });
  18.                         return true;
  19.                     }
  20.                     catch (Exception ex)
  21.                     {
  22.                         throw new Exception(String.Format("Failed to load {0} as a add on command from {1}", type.Name, type.AssemblyQualifiedName), ex);
  23.                     }
  24.                 }
  25.             }
  26.         }
  27.     }
  28.     return false;
  29. }

So, to put the loading all together into a single class…

AnimalLoader.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4.  
  5. public class AnimalLoader
  6. {
  7.     public static List<AbstractAnimalBase> LoadAnimals(string filename)
  8.     {
  9.         List<AbstractAnimalBase> animals = new List<AbstractAnimalBase>();
  10.         Assembly assembly = Assembly.LoadFrom(filename);
  11.         Type[] types = assembly.GetTypes();
  12.  
  13.         foreach (Type type in types)
  14.         {
  15.             AbstractAnimalBase animal = null;
  16.             if (IsValidAnimal(type,ref animal))
  17.             {
  18.                 animals.Add(animal);
  19.             }
  20.         }
  21.         return animals;
  22.     }
  23.  
  24.     protected static bool IsValidAnimal(Type type, ref AbstractAnimalBase animal)
  25.     {
  26.         //is it a sub-class
  27.         if (type.BaseType != null)
  28.         {
  29.             //make sure it's not an interface
  30.             if (!type.IsInterface)
  31.             {
  32.                 //is it a sub-class of what we're interested in
  33.                 if (type.IsSubclassOf((typeof(AbstractAnimalBase))))
  34.                 {
  35.                     //make sure the type is a concrete type (i.e. not abstract)
  36.                     if (!type.IsAbstract)
  37.                     {
  38.                         try
  39.                         {
  40.                             animal = (AbstractAnimalBase)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { });
  41.                             return true;
  42.                         }
  43.                         catch (Exception ex)
  44.                         {
  45.                             throw new Exception(String.Format("Failed to load {0} as a add on command from {1}", type.Name, type.AssemblyQualifiedName), ex);
  46.                         }
  47.                     }
  48.                 }
  49.             }
  50.         }
  51.         return false;
  52.     }
  53. }

Ok, so we can now load the animals that’re in a dll or exe, but how do we load them into our factory?  Need a key for each of the animals and also a way to load them before the factory is first used.

Making the Abstract Class “Keyable”

Well, we actually have a key in the AbstractAnimalBase class but it’s protected – let’s fix that and make it public so that the factory can access the keys (yes, it can be marked as internal instead as long as the factory and animal base class are in the same exe or dll).  So the new AbstractAnimalBase class is changed to:

AbstractAnimalBase.cs
  1. public abstract class AbstractAnimalBase
  2. {
  3.     public string AnimalType { get; private set; }
  4.  
  5.     public AbstractAnimalBase(string type)
  6.     {
  7.         AnimalType = type;
  8.     }
  9.  
  10.     public void IntroduceSelf()
  11.     {
  12.         System.Console.WriteLine(IntroductionLine);
  13.         System.Console.WriteLine(Speak);
  14.         System.Console.WriteLine();
  15.     }
  16.  
  17.     protected virtual string IntroductionLine
  18.     {
  19.         get
  20.         {
  21.             string introLine = "Hello, I am a " + AnimalType;
  22.             return introLine;
  23.         }
  24.     }
  25.  
  26.     protected abstract string Speak
  27.     {
  28.         get;
  29.     }
  30. }

Dynamic Factory Class

Now, to get that factory working.  What would be nice would be for the factory to load the add ins when it’s first used…well, it can – by using a static constructor.

AnimalFactory.cs
  1. public static class AnimalFactory
  2. {
  3.     private static Dictionary<string, AbstractAnimalBase> Animals { get; set; }
  4.  
  5.     static AnimalFactory()
  6.     {
  7.         Animals = new Dictionary<string, AbstractAnimalBase>();
  8.  
  9.         List<AbstractAnimalBase> animals;
  10.         
  11.         string filename="Animals.dll";
  12.         string path=Assembly.GetExecutingAssembly().Location;
  13.         path=System.IO.Path.GetDirectoryName(path);
  14.         string fileToLoad=System.IO.Path.Combine(path,filename);
  15.  
  16.         try
  17.         {
  18.             animals = AnimalLoader.LoadAnimals(fileToLoad);
  19.  
  20.             foreach (AbstractAnimalBase animal in animals)
  21.             {
  22.                 string animalType = animal.AnimalType.ToLower().Trim();
  23.                 if (!Animals.ContainsKey(animalType))
  24.                 {
  25.                     Animals.Add(animalType, animal);
  26.                 }
  27.                 else
  28.                 {
  29.                     throw new Exception(String.Format("Duplicate animal type {0} found", animalType));
  30.                 }
  31.             }
  32.         }
  33.         catch (Exception ex)
  34.         {
  35.             throw new Exception(String.Format("There was a problem loading the assembly {0}", fileToLoad),ex);
  36.         }
  37.     }

For this factory, for demo purposes, I’ve set the filename to be a static dll named Animals.dll, which the static constructor will use to pass to the AnimalLoader – you’ll more than likely want to use something different, but, remember, static constructors cannot accept parameters so you’ll have to find another way or just loop through all dlls.  Also, this uses the current executing path – change as needed for your own purposes.  Really, not a lot here – animals are discovered and loaded by the AnimalLoader method, then the animal types and the animal are added to the static list of animals for the factory.  If you’ve been paying attention, yes, this is a cached factory at this point as reflection is slow.

Now, for getting the animals out of the factory.

AnimalFactory.cs
  1. public static AbstractAnimalBase GetCachedAnimal(string type)
  2. {
  3.     type=type.ToLower().Trim();
  4.     if (Animals.ContainsKey(type))
  5.     {
  6.         return Animals[type];
  7.     }
  8.     else
  9.     {
  10.         throw new Exception(String.Format("Unknown animal type {0}", type));
  11.     }
  12. }
  13.  
  14. public static AbstractAnimalBase GetAnimal(string type)
  15. {
  16.     AbstractAnimalBase cachedAnimal = GetCachedAnimal(type);
  17.     Type animalAssemblyType = cachedAnimal.GetType();
  18.  
  19.     AbstractAnimalBase animal = (AbstractAnimalBase)animalAssemblyType.Assembly.CreateInstance(animalAssemblyType.FullName);
  20.     return animal;
  21. }

Two things to notice here, there’s a method to get a cached animal as well as creating a new one based on the cached version.  I’ve supplied both just to show how to get a new animal from a cached version (this could also work for a normal cached factory as well as one using reflection to dynamically add classes).

Discovering what is available

And, that pretty much wraps up the factories and how to load classes dynamically.  What, you want to know what types are available to show to your UI?  Ok, here’s how you do that (requires “using System.Linq” namespace to be added thanks to the ToList extension method)…

AnimalFactory.cs
  1. public static List<string> GetAnimalTypes()
  2. {
  3.     return Animals.Keys.ToList<string>();
  4. }

Dynamic Cached Factory Code

Now, for all the dynamic cached factory code.

AbstractAnimalBase
  1. using System;
  2.  
  3. public abstract class AbstractAnimalBase
  4. {
  5.     public string AnimalType { get; private set; }
  6.  
  7.     public AbstractAnimalBase(string type)
  8.     {
  9.         AnimalType = type;
  10.     }
  11.  
  12.     public void IntroduceSelf()
  13.     {
  14.         System.Console.WriteLine(IntroductionLine);
  15.         System.Console.WriteLine(Speak);
  16.         System.Console.WriteLine();
  17.     }
  18.  
  19.     protected virtual string IntroductionLine
  20.     {
  21.         get
  22.         {
  23.             string introLine = "Hello, I am a " + AnimalType;
  24.             return introLine;
  25.         }
  26.     }
  27.  
  28.     protected abstract string Speak
  29.     {
  30.         get;
  31.     }
  32. }

 

Dog.cs
  1. using System;
  2.  
  3. public class Dog : AbstractAnimalBase
  4. {
  5.     public Dog()
  6.         : base("Dog")
  7.     {
  8.     }
  9.  
  10.     protected override string Speak
  11.     {
  12.         get { return "Woof"; }
  13.     }
  14. }

 

Cat.cs
  1. using System;
  2.  
  3. public class Cat : AbstractAnimalBase
  4. {
  5.     public Cat()
  6.         : base("Cat")
  7.     {
  8.     }
  9.  
  10.     protected override string Speak
  11.     {
  12.         get { return "Meow"; }
  13.     }
  14. }

 

Pig.cs
  1. using System;
  2.  
  3. public class Pig : AbstractAnimalBase
  4. {
  5.     public Pig()
  6.         : base("Pig")
  7.     {
  8.     }
  9.  
  10.     protected override string Speak
  11.     {
  12.         get { return "Oink"; }
  13.     }
  14. }

 

AnimalLoader.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4.  
  5. public class AnimalLoader
  6. {
  7.     public static List<AbstractAnimalBase> LoadAnimals(string filename)
  8.     {
  9.         List<AbstractAnimalBase> animals = new List<AbstractAnimalBase>();
  10.         Assembly assembly = Assembly.LoadFrom(filename);
  11.         Type[] types = assembly.GetTypes();
  12.  
  13.         foreach (Type type in types)
  14.         {
  15.             AbstractAnimalBase animal = null;
  16.             if (IsValidAnimal(type, ref animal))
  17.             {
  18.                 animals.Add(animal);
  19.             }
  20.         }
  21.         return animals;
  22.     }
  23.  
  24.     protected static bool IsValidAnimal(Type type, ref AbstractAnimalBase animal)
  25.     {
  26.         //is it a sub-class
  27.         if (type.BaseType != null)
  28.         {
  29.             //make sure it's not an interface
  30.             if (!type.IsInterface)
  31.             {
  32.                 //is it a sub-class of what we're interested in
  33.                 if (type.IsSubclassOf((typeof(AbstractAnimalBase))))
  34.                 {
  35.                     //make sure the type is a concrete type (i.e. not abstract)
  36.                     if (!type.IsAbstract)
  37.                     {
  38.                         try
  39.                         {
  40.                             animal = (AbstractAnimalBase)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { });
  41.                             return true;
  42.                         }
  43.                         catch (Exception ex)
  44.                         {
  45.                             throw new Exception(String.Format("Failed to load {0} as a add on command from {1}", type.Name, type.AssemblyQualifiedName), ex);
  46.                         }
  47.                     }
  48.                 }
  49.             }
  50.         }
  51.         return false;
  52.     }
  53. }

 

AnimalFactory.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Linq;
  5.  
  6. public static class AnimalFactory
  7. {
  8.     private static Dictionary<string, AbstractAnimalBase> Animals { get; set; }
  9.  
  10.     static AnimalFactory()
  11.     {
  12.         Animals = new Dictionary<string, AbstractAnimalBase>();
  13.  
  14.         List<AbstractAnimalBase> animals;
  15.  
  16.         string filename = "Animals.dll";
  17.         string path = Assembly.GetExecutingAssembly().Location;
  18.         path = System.IO.Path.GetDirectoryName(path);
  19.         string fileToLoad = System.IO.Path.Combine(path, filename);
  20.  
  21.         try
  22.         {
  23.             animals = AnimalLoader.LoadAnimals(fileToLoad);
  24.  
  25.             foreach (AbstractAnimalBase animal in animals)
  26.             {
  27.                 string animalType = animal.AnimalType.ToLower().Trim();
  28.                 if (!Animals.ContainsKey(animalType))
  29.                 {
  30.                     Animals.Add(animalType, animal);
  31.                 }
  32.                 else
  33.                 {
  34.                     throw new Exception(String.Format("Duplicate animal type {0} found", animalType));
  35.                 }
  36.             }
  37.         }
  38.         catch (Exception ex)
  39.         {
  40.             throw new Exception(String.Format("There was a problem loading the assembly {0}", fileToLoad), ex);
  41.         }
  42.     }
  43.  
  44.     public static AbstractAnimalBase GetCachedAnimal(string type)
  45.     {
  46.         type = type.ToLower().Trim();
  47.         if (Animals.ContainsKey(type))
  48.         {
  49.             return Animals[type];
  50.         }
  51.         else
  52.         {
  53.             throw new Exception(String.Format("Unknown animal type {0}", type));
  54.         }
  55.     }
  56.  
  57.     public static AbstractAnimalBase GetAnimal(string type)
  58.     {
  59.         AbstractAnimalBase cachedAnimal = GetCachedAnimal(type);
  60.         Type animalAssemblyType = cachedAnimal.GetType();
  61.  
  62.         AbstractAnimalBase animal = (AbstractAnimalBase)animalAssemblyType.Assembly.CreateInstance(animalAssemblyType.FullName);
  63.         return animal;
  64.     }
  65.  
  66.     public static List<string> GetAnimalTypes()
  67.     {
  68.         return Animals.Keys.ToList<string>();
  69.     }
  70. }