I am building an extensible framework to separate client-based business logic and data structures from our common infrastructure, based off a MVC4 WebAPI system.
To this end, I created an interface IApiServiceEntryPoint like so:
public interface IApiServiceEntryPoint : IDisposable
{
    /// <summary>
    /// Gets the name of the API Plugin
    /// </summary>
    string Name { get; }
    /// <summary>
    /// Registers the assembly in the application, 
    /// sets up the routes, and enables invocation of API requests
    /// </summary>
    void Register(RouteCollection routes);
    /// <summary>
    /// Gets the routing namespace of the plugin
    /// </summary>
    string UrlNameSpace { get; }
}
Then, in the same assembly, I created a PluginHelper class like so:
public static class PluginHelper
{
    private static readonly List<IApiServiceEntryPoint> _plugins = new List<IApiServiceEntryPoint>();
    public static List<IApiServiceEntryPoint> Plugins { get { return _plugins; } }
    private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(typeof(PluginHelper));
    /// <summary>
    /// Registers all IApiServiceEntryPoint plugin classes.
    /// </summary>
    /// <param name="pluginPath">The directory where the plugin assemblies are stored.</param>
    public static void Register(string pluginPath, RouteCollection routes)
    {
        Logger.InfoFormat("Registering plugins found at \"{0}\"...", pluginPath);
        foreach (var plugin in _plugins)
        {
            Logger.DebugFormat("Disposing plugin {0}...", plugin.Name);
            plugin.Dispose();
        }
        Logger.DebugFormat("Clearing the plugin cache...");
        _plugins.Clear();
        var libraryFiles = System.IO.Directory.GetFiles(pluginPath, "*.*")
            .Where(fn => fn.ToLowerInvariant().EndsWith(".dll") 
                || fn.ToLowerInvariant().EndsWith(".exe"))
            .ToList();
        Logger.DebugFormat("Found {0} assemblies in the plugin directory...", libraryFiles.Count);
        var assemblies = libraryFiles.Select(lf => Assembly.LoadFrom(lf))
            .ToList();
        Logger.DebugFormat("Loaded {0} assemblies into memory: {1}", assemblies.Count, string.Join(", ", assemblies.Select(a=>a.FullName).ToArray()));
        var pluginTypes = assemblies.Where(assy => assy != null)
            .SelectMany(assy => assy.GetTypes())
            .Where(t => !t.IsInterface && !t.IsAbstract && t.Namespace != null) 
            .ToList();
        Logger.DebugFormat("Located a total of {0} classes.", pluginTypes.Count);
        pluginTypes = pluginTypes.Where(t => t.IsTypeOf<IApiServiceEntryPoint>())
            .ToList();
        Logger.DebugFormat("Located a total of {0} plugin entry points.", pluginTypes.Count);
        foreach (var type in pluginTypes)
        {
            Logger.DebugFormat("Registering plugin type '{0}'...", type.Name);
            var plugin = (IApiServiceEntryPoint)Activator.CreateInstance(type);
            Logger.InfoFormat("Registering plugin \"{0}\"...", plugin.Name);
            plugin.Register(routes);
            Logger.InfoFormat("Plugin \"{0}\" Registered.", plugin.Name);
            _plugins.Add(plugin);
        }
        Logger.InfoFormat("All {0} plugin(s) have been registered.", Plugins.Count);
    }
    public static bool IsTypeOf<T>(this Type type)
    {
        return type.GetInterfaces().Any(t =>t.Name == typeof(T).Name); 
    }
}
Note the extension method IsTypeOf()... I originally tried to implement this using a form of IsAssignableFrom() but it never seemed to work... which I think may be related to my issue.
Next I created an abstract class in the same assembly:
public abstract class ApiPlugin : IApiServiceEntryPoint, IAccessControl
{
    private static readonly ILog Logger = log4net.LogManager.GetLogger(typeof(ApiPlugin));
    public abstract string Name { get; }
    public virtual void Register(RouteCollection routes)
    {
        var rt = string.Format("{0}/{{controller}}/{{id}}", UrlNameSpace);
        var nameSpace = this.GetType().Namespace;
        Logger.DebugFormat("Route Template: {0} in namespace {1}...", rt, nameSpace);
        var r = routes.MapHttpRoute(
            name: Name,
            routeTemplate: rt,
            defaults: new { id = RouteParameter.Optional, controller = "Default" }
            );
        r.DataTokens["Namespaces"] = new[] { nameSpace };
        Logger.InfoFormat("Plugin '{0}' registered namespace '{1}'.", Name, nameSpace);
    }
    public abstract string UrlNameSpace { get; }
    public bool IsAuthorized<T>(Func<T> method)
    {
        var methodName = method.Method.Name;
        var userName = User.Identity.Name;
        return
            ValidateAccess(userName, methodName) &&
            ValidateLicense(userName, methodName);
    }
    protected virtual bool ValidateAccess(string userName, string methodName)
    {
        // the default behavior to allow access to the method.
        return true;
    }
    protected virtual bool ValidateLicense(string userName, string methodName)
    {
        // the default behavior is to assume the user is licensed.
        return true;
    }
    public abstract IPrincipal User { get; }
    public abstract void Dispose();
    public virtual bool ClientAuthorized(object clientId)
    {
        return true;
    }
}
So far, all is working swimmingly. Now to write my first plugin in its own assembly. I made it very simple:
public class DefaultPlugin : ApiPlugin
{
    private static readonly ILog Logger = log4net.LogManager.GetLogger(typeof(DefaultPlugin));
    [HttpGet]
    public DateTime GetSystemTimeStamp()
    {
        if (IsAuthorized(GetSystemTimeStamp))
        {
            return DateTime.UtcNow;
        }
        throw new AuthorizationException();
    }
    public override string Name
    {
        get { return "Default API Controller"; }
    }
    public override string UrlNameSpace
    {
        get { return "Default"; }
    }
    public override System.Security.Principal.IPrincipal User
    {
        get { return new GenericPrincipal(new GenericIdentity("Unauthenticated User"), new[] { "None" }); }
    }
    public override void  Dispose()
    {
        //TODO: Unregister the plugin.   
    }
}
I built this, and I referenced the binary directory for this plugin in my MVC project in my invocation of the plugin registration.
When the PluginHelper.Register() method is called, I find the plugin class, but on the following line:
var plugin = (IApiServiceEntryPoint)Activator.CreateInstance(type);
I end up with the following InvalidCastException being thrown:
Unable to cast object of type 'myPluginNameSpace.DefaultPlugin' to type 'myInterfaceNamespace.IApiServiceEntryPoint'
Here's the thing: it absolutely is an implementation of that interface.
Now I've done this sort of plugin thing before, so I know it can work, but for the life of me I cannot figure out what I am doing wrong. I expect it has something to do with specific builds/ versions, or perhaps strong naming? Please advise.
 
     
    