4

I'm working on an MVC application that will feature a "plugin" architecture.

Basically there will be a main "host" project that will dynamically load other projects at runtime.

We want to move all ASP.NET Identity related stuff into its own separate plugin project.

The main host project already contains an Owin Startup class which has some logic that it needs to run. However, we also need to create an Owin Startup class within the Identity plugin project so we can call ConfigureAuth().

How can I accomplish this?

MvcPluginHost.Web Startup.cs

[assembly: OwinStartupAttribute(typeof(MvcPluginHost.Web.Startup))]
namespace MvcPluginHost.Web
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

MvcPluginHost.Plugins.IdentityPlugin Startup.cs

[assembly: OwinStartupAttribute(typeof(MvcPluginHost.Plugins.IdentityPlugin.Startup))]
namespace MvcPluginHost.Plugins.IdentityPlugin
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}
thiag0
  • 2,199
  • 5
  • 31
  • 51
  • I'm not sure you can or want to have multiple `Startup` classes. There's no reason you can't have a separate Identity assembly, the purpose of the `Startup` class is to allow you to configure which plugins you want to add. Without knowing your specific requirements and current approach, I would bet that you should actually be swapping out authentication plugins using configuration anyways. – mclark1129 Jun 09 '15 at 17:37
  • @MikeC Thanks for the response. I'm not trying to switch out authentication plugins, I'm basically trying to run Owin startup code from multiple places. The main host app doesnt know about the Identity plugin at compile time so I cannot configure owin authentication from there. Also can't make the default Startup class be the one in the Identity plugin becuase the main host app needs to setup SignalR which is not required by the Identity plugin. – thiag0 Jun 09 '15 at 17:45

1 Answers1

4

Partial classes are not meant for this, the first thing that comes to mind is to query the desired assemblies for some interface and call a common method on all of them.

var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

foreach(var implementation in types)
{
    var obj = (IMyInterface)Activator.CreateInstance(implementation);
    obj.RunPlugin() //Interface method you're trying to implement in partials
}
bateloche
  • 699
  • 4
  • 19
  • This would be the route to go in my opinion. Set the main host `Startup` class to support dynamic plugin assemblies. `IMyInterface` could have a `Configure(IAppBuilder app)` method as well so you could just pass the app to each assembly. – mclark1129 Jun 09 '15 at 18:46
  • Thanks guys, I had this option in mind but was hoping there was a "cleaner" way. Was able to implement your solution and it works as expected, thanks again! – thiag0 Jun 09 '15 at 19:18
  • 3
    A cleaner way would be to use some Dependency Injection container to let you configure would plugins would be called, and transparently do the reflection job. – bateloche Jun 09 '15 at 19:23
  • @bateloche Here a possible scenario that would not be covered is, ConfigureAuth() is method of Partial class Startup. In that case the above solution won't be the complete solution. – vendettamit Jun 09 '15 at 19:47
  • @vendettamit I don't know if I understood what you meant, but every implementation of the interface we used is free to call whatever is needed to do the job, as long as the method lies in the scope of the caller (referenced assemblies) it would not matter. – bateloche Jun 09 '15 at 20:39
  • Yes you're absolutely right but here situation is bit tricky. The method in one of the implementation lies in the Partial class which would make this scenario bit tricky to handle. Look at the ConfigureAuth() its definition is part of other partial Startup class that lies with in Owin Identity assembly. Hope you got my point. – vendettamit Jun 09 '15 at 22:35
  • Oh... Got it, but the point is the same, this method would need to be refactored to somewhere else. But anyway nice catch, wouldn't see this if wheren't you... – bateloche Jun 09 '15 at 23:01
  • Needs to remove IMyInterface itself from the types collection, otherwise the code here attempts to create an instance of the interface itself. FYI. – Sean Sherman Oct 09 '18 at 15:08