Monday, June 09, 2008

Almost immediately following yesterday's post I got to thinking about supporting static classes / methods.  I see static classes all the time where the class represents a set of related-but-operationally-distinct methods, often utilities.  The post yesterday really had two aspects about it: 1) the retrieval / extraction and the hosting of an assembly embedded as a resource within another assembly and 2) the creation of a proxy type by wrapping the logic surrounding using Reflection to dig into the guts of the referenced object in a base class.

The ante is raised (only slightly) when dealing with static objects.  Static objects have no instance methods and therefore have no inheritance support and no constructors (the static .ctor is really a type initializer and it's quite the same thing).  Our simple example yesterday defines an abstract base class (ProxyClassBase) that encapsulates the logic for creating the proxy instance and invoking the methods within it.

If we were to mimic the structure of the reference object (the object from the extracted assembly) in our proxy class we would be unable to inherit ProxyClassBase because our proxy would be static.  Allow me to flesh out an example illustrating this:

Example 01: Static Proxy

For this to work, I'd have to create a new class.  Let's name it StaticProxyClass.  This class would, in large measure, be quite similar to the ProxyClassBase base type we defined yesterday with a few distinctions:  1) we wouldn't need an Instance (all methods are static) and 2) we can't have a protected .ctor (our proxy would be static and would be unable to inherit the class).

Our type might resemble the following:

namespace HostAsm {

   internal class StaticProxyClass {
      internal StaticProxyClass(string assemblyName, string typeName) {
         _type = AssemblyLoader.GetType(assemblyName, typeName);
      }

      private readonly Type _type;

      internal void InvokePublicVoidMethod(string methodName, object[] parameters) {
         Type[] types = getTypes(parameters);
         MethodInfo method = _type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Standard, types, null);
         method.Invoke(null, parameters);
      }

      private static Type[] getTypes(object[] parameters) {
         Type[] result;
         if ( null == parameters || 0 == parameters.Length )
            result = Type.EmptyTypes;
         else {
            result = new Type[parameters.Length];
            for ( int i = 0; i < parameters.Length; i++ ) {
               result[i] = parameters[i].GetType();
            }
         }
         return result;
      }
   }
  
}

Note that I've included a method (getTypes) that I didn't include in yesterday's example but may well belong in the ProxyClassBase type as well.  This method will assist in resolving overloaded methods (methods with the same name but with differing parameters).

Our static proxy class would effectively wrap an instance of this type and delegate calls to the reference object through it.

namespace HostAsm {

   internal static class CustomStaticClass {
      static CustomStaticClass() {
         _proxy = new StaticProxyClass("EmbeddedAsm.dll", "EmbeddedAsm.CustomStaticClass");
      }

      private static readonly StaticProxyClass _proxy;

      internal static void StaticMethod(string data) {
         _proxy.InvokePublicVoidMethod("StaticMethod", new object[] { data });
      }
   }

}

This is all well and good and it works perfectly well.  There's something missing, however, and a few things bug me about it.

First of all, it bugs me most that we'd end up having to duplicate (in large part) the functionality in one class (ProxyClassBase) in another (StaticProxyClass).  Secondly, we're omitting one major part of the discussion: objects that have both instance methods and static methods.  To me, this is the deal breaker.

To support this and to leverage our ProxyClassBase type even for static methods, I'd do away with the StaticProxyClass and add the methods therein to the ProxyClassBase.  This will necessitate that our proxy type for static types be non-static, but we can pseudo-simulate that by making its .ctor private.  For these, we will have to encapsulate the actual proxy within our proxy type.  In fact, we'd have to take that one more level by creating delegate methods on our proxy class that direct the calls to the base type.  I'd rather do this than muck with the scope of the base class's methods to keep my intentions pure with the base class.

Example 02: Enhancing the ProxyClassBase

The ProxyClassBase will get the functionality we just added to StaticProxyClass as well as a flag indicating whether the wrapped type is a static type.

using System;
using System.Reflection;

namespace HostAsm {

   internal abstract class ProxyClassBase {
      protected ProxyClassBase(string assemblyName, string typeName, bool isStatic) {
         ObjType = AssemblyLoader.GetType(assemblyName, typeName);
         Instance = isStatic ? null : Activator.CreateInstance(ObjType);
      }

      protected Type ObjType { get; private set; }
      protected object Instance { get; private set; }
      protected bool IsStatic { get; private set; }

      protected T InvokePublicMethod<T>(string methodName) {
         MethodInfo method = ObjType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Standard, Type.EmptyTypes, null);
         return ( T )method.Invoke(Instance, null);
      }

      protected void InvokePublicStaticVoidMethod(string methodName, object[] parameters) {
         Type[] types = getTypes(parameters);
         MethodInfo method = ObjType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, types, null);
         method.Invoke(null, parameters);
      }

      private Type[] getTypes(object[] parameters) {
         Type[] result;
         if ( null == parameters || 0 == parameters.Length )
            result = Type.EmptyTypes;
         else {
            result = new Type[parameters.Length];
            for ( int i = 0; i < parameters.Length; i++ ) {
               result[i] = parameters[i].GetType();
            }
         }
         return result;
      }
   }

}

Then, to finish the puzzle, our proxy class that wraps the static type gets a face lift:

using System;

namespace HostAsm {

   internal class CustomStaticClass : ProxyClassBase {
      private CustomStaticClass()
         : base("EmbeddedAsm.dll", "EmbeddedAsm.CustomStaticClass", true) {
      }

      private static readonly CustomClass2 _proxy = new CustomClass2();

      internal static void StaticMethod(string data) {
         _proxy.invokePublicStaticVoidMethod("StaticMethod", new object[] { data });
      }

      private void invokePublicStaticVoidMethod(string methodName, object[] parameters) {
         base.InvokePublicStaticVoidMethod(methodName, parameters);
      }
   }

}

I've not given this approach a great deal of scrutiny.  At first glance I can see it being somewhat fragile.  If the base class changes you have to proliferate changes to the inheriting types.  Then again, I don't see this base class like this changing much if at all except for new additions.

Monday, June 09, 2008 8:20:56 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, June 08, 2008

I've recently developed an application that has the requirement of not having any external dependencies.  That is, the application must, for a variety of reasons, be a stand-alone executable without any bundled libraries or assemblies.  I've already developed some of the functionality that this application relies on, however, and it's packaged in other small utility libraries.  Referencing these assemblies would be the natural decision if I wanted to leverage the functionality.  But that breaks rule #1: no external dependencies.

That aside, I might consider having my project link to the source code files to the other libraries and effectively compile the code directly into my application.  That might, in a simplistic case, be reasonable, but it could easily be unwieldy and unmanagement in the long term.  Not only would I be bringing in classes from another quite distinct namespace into my project, but there's no real tie between them.  A developer may change the source file in a way that breaks my application, introducing other previously-unexpected dependencies.  The list goes on and on as to why this may be a bad idea.

The next thought that came to mind was "What if I were to take the assembly I would otherwise reference and embed it within my application as a resource?  I could load it dynamically at runtime without physically deploying a separate library."  This approach does require a little more work on the part of the developer.

This isn't a new concept.  In fact, several years ago I'd written some code that does this in a similar fashion.  I'm pleased with how effortless it was, however, and I managed to throw this code together in about 20 minutes.

For purposes of the illustration and to test the concept, I created a blank solution in Visual Studio 2008 called 'LoadAssemblyFromResource'.  To this solution, I then added three new projects: EmbeddedAsm (class library), HostAsm (class library), and ClientApp (console application).  EmbeddedAsm is the assembly that will be embedded within HostAsm.  HostAsm represents my application that can't have any external dependencies.  ClientApp is my test harness that will invoke methods on HostAsm.  In turn, HostAsm will leverage the functionality in EmbeddedAsm at runtime.

To set this up, I first created EmbeddedAsm and set the output folder for all configurations to bin\.  Then I and compiled it.  Having functionality within it was not necessary at this point.  Basically, I simply needed to be able to reference the output.  Also, I like having a single target to reference.  This makes the embedding of the assembly easier without having to deal with the bin\Debug or bin\Release directories.

Then, in HostAsm I created a folder called Resources.  I right-clicked that folder and chose 'Add --> Existing Item'.  I then browsed to the bin\ folder of EmbeddedAsm and selected the .dll.  Important: I selected Add As Link rather than Add to add the assembly to the Resources folder.  This enables me to make updates to the EmbeddedAsm and have the HostAsm be updated with the changes.  Were I to have selected Add a copy of the .dll at that point in time would be copied into my Resources folder and any updates to the EmbeddedAsm would be ignored; I'd have to re-add it.

ClientApp has a reference to HostAsm.

The final step in the setup, then, was to right-click on the solution (in the Solution Explorer) and select Project Build Order.  Because HostAsm doesn't actually have a reference to EmbeddedAsm, I had to ensure that it has a dependency on in (on the Dependencies tab).  This forces Visual Studio to compile EmbeddedAsm first so when it gets around to compiling HostAsm it embeds the latest version.

Now for the code...

In EmbeddedAsm I created a very simple class with a simple method:

EmbeddedAsm:

namespace EmbeddedAsm {
   public class CustomClass {
      public string GetMessage() {
         return "Hello from CustomClass";
      }
   }
}

I wrote HostAsm to be a little more robust and reusable.  Rather than simply loading the embedded assembly and running with it, I wanted to put together a bit of a framework (albeit a simple one) to handle the loading of multiple embedded assemblies.

HostAsm:

namespace HostAsm {

   internal static class AssemblyLoader {
      private static Dictionary<string, Assembly> _loadedAssemblies = new Dictionary<string, Assembly>();

      internal static Assembly LoadAssembly(string assemblyName) {
         if ( _loadedAssemblies.ContainsKey(assemblyName) )
            return _loadedAssemblies[assemblyName];

         byte[] bytes;
         using ( Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("HostAsm.Resources." + assemblyName) ) {
            bytes = new byte[(int)stream.Length];
            stream.Read(bytes, 0, bytes.Length);
         }

         Assembly asm = Assembly.Load(bytes);
         if ( null == asm )
            throw new ArgumentException("Unable to load assembly: " + assemblyName);

         _loadedAssemblies.Add(assemblyName, asm);
         return asm;
      }


      internal static Type GetType(string assemblyName, string typeName) {
         Assembly asm = LoadAssembly(assemblyName);

         Type type = asm.GetType(typeName);
         if ( null == type )
            throw new ArgumentException(string.Format("Unable to locate type {0} in assembly {1}", typeName, assemblyName));

         return type;
      }
   }

}

The AssemblyLoader class is responsible for the loading of assemblies (naturally) and for retrieving types from the embedded assemblies.  It loads the assemblies by accessing the manifest resource stream of the executing assembly (HostAsm) and fully-qualifying the reference to the embedded library.  Note that the assembly's root namespace is 'HostAsm' and the embedded library is in the Resources folder so the fully-qualified name to the .dll is HostAsm.Resources.EmbeddedAsm.dll.  We then use the Assembly.Load() method to load the assembly from bytes read from the stream.  The assembly is catalogued so we can avoid quickly retrieve an already-loaded library quickly in a subsequent call.  The assembly is then returned to the caller.

The approach I took for accessing and calling the types in the embedded assembly is that of a proxy class.  In this case, the proxy class is coded such that it's methods match those in the class to be called from the embedded assembly.  Also, I wanted to genericize the proxy type so I could, in a repeatable form, invoke methods on other types in a similar fashion.  Therefore, I created a ProxyClassBase type which abstracts away the reflection plumbing necessary to make the calls.  These classes also exist in the HostAsm library.

ProxyClassBase.cs

namespace HostAsm {

   internal abstract class ProxyClassBase {
      protected ProxyClassBase(string assemblyName, string typeName) {
         InstanceType = AssemblyLoader.GetType(assemblyName, typeName);
         Instance = Activator.CreateInstance(InstanceType);
      }

      protected Type InstanceType;
      protected object Instance;

      protected T InvokePublicMethod<T>(string methodName) {
         return (T)InstanceType.GetMethod(methodName).Invoke(Instance, null);
      }
   }

}

CustomClassProxy.cs

namespace HostAsm {

   /// <summary>
   /// Proxy class for EmbeddedAsm.CustomClass.
   /// </summary>

   internal class CustomClass : ProxyClassBase {
      public CustomClass()
         : base("EmbeddedAsm.dll", "EmbeddedAsm.CustomClass") {
      }

      public string GetMessage() {
         return InvokePublicMethod<string>("GetMessage");
      }
   }

}

Note that the CustomClass proxy class invokes the base class's .ctor which in turn uses the functionality in the AssemblyLoader class to encapsulate the creation and management of the type being wrapped.  The method on the CustomClass proxy matches that of the actual CustomClass in EmbeddedAsm except that it defers to the base class's implementation to invoke the method via Reflection.

Then, within my HostAsm I can simply consume the method as though the object were local and participated in the same namespace of my application:

namespace HostAsm {

   public class Worker {
      public void DoWork() {
         CustomClass cc = new CustomClass();
         Console.WriteLine(cc.GetMessage());
      }
   }

}

It's actually quite easy and straightforward.  Not only does this approach help me in my predicament of not being able to support any external dependencies, but I can see how it might be useful in situations where assemblies are packaged and deployed together, used as Add-Ins, etc.  It's pretty cool stuff.

Sunday, June 08, 2008 3:03:26 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback