I have built a plugin system, where I can dynamically load classes into my application (IModule is an interface, so I know the plugin will behave correctly):
var dll = Assembly.LoadFile("path/to/a/dll");
foreach (Type t in dll.GetExportedTypes()) {
if (typeof(IModule).IsAssignableFrom(t)) {
IModule mod = (IModule)Activator.CreateInstance(t);
}
}
So, from my "main" application, I can get and instantiate classes in my plugin. What I would like now, is to be able to get to the classes of the "main" application, from the plugin.
I tried using Type.GetType("NameOfClass"), but that returns null.
This is bound to turn ugly if you need to do it without altering the main module at all, which turns out to be the case. So the following suggestion is a kludge, but I think a kludge may be the best you can hope for in this case.
The static method Assembly.GetCallingAssembly() will return the assembly that called the method you're currently in, so one thing you could do is find a place where the main module directly calls some method M of the plugin modules. Fingers crossed, maybe there's some kind of initializer method that gets called early on.
In M, call Assembly.GetCallingAssembly() and stuff the result in some static field that you can use later to create instances of classes that are defined in the main module.
I think you misunderstood plugin-like concept. You should implement API library which purpose will be to store public plugin interfaces. Those interfaces you will be using in your plugins, and just instantiate your classes through some IoC framework. For example, you can use Ninject:
public class MyPlugin : IModule
{
public MyPlugin(MainApp.API.IMainAppInterface instance)
{
//do something with it.
}
}
public class MyPluginModule: NinjectModule
{
protected override void Load(IKernel kernel)
{
kernel.Bind<MyPlugin>().To<IModule>();
}
}
And in your main application you just load those modules from some folder.
Related
I am writing a project which will encapsulate multiple Calendar APIs (Google Calendar, Outlook ect) in one service. This will allow me to integrate different APIs which can be mapped to our domain model. However I am having issues with required dependencies spilling over into other projects. Here's an example:
I have created a generic class which does most of the work and conversions from the API model to our model. Here's an example:
public abstract class CalendarAPIBase<TEventType> : ICalendarAPI
{
public CalendarEvent Get(string id)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id");
return Convert(GetEvent(id));
}
public List<CalendarEvent> GetAll()
{
List<CalendarEvent> result = new List<CalendarEvent>();
List<TEventType> es = GetAllEvents();
foreach (TEventType e in es)
result.Add(Convert(e));
return result;
}
protected abstract List<TEventType> GetAllEvents();
protected abstract CalendarEvent Convert(TEventType obj);
//More stuff below.
}
So this is a beautiful thing, anything that inherits CalendarAPIBase doesn't have to do much work other than getting the data from the API, the base class will handle the conversions.
Ok, so here's where things go wrong. I have created a GoogleCalendarAPI class, which inherits from CalendarAPIBase. It passes in the Event class, which belongs to a NuGet package Google.Apis.Calendar.v3.
public class GoogleCalendarAPI : CalendarAPIBase<Event>
The problem here is that this class is exposing the Event class, therefore anything that references this project will also need to reference Google.Apis.Calendar.v3. Ideally anyone wishing to use this service will only have to reference just the project and not have to worry about installing other NuGet packages.
How can I restructure my classes to prevent this from happening?
The most straightforward way to resolve this stuff is an Abstract factory pattern.
First, you make CalendarAPIBase<TEventType> and all its descendants internal. All the public stuff has to be concentrated within a public ICalendarAPI interface.
Next step is introducing public classes like this:
public static class GoogleCalendarAPIFactory
{
public static ICalendarAPI Instantiate( ....... )
{
.......
return new GoogleCalendarAPI( ..... );
}
}
The factory will make all the TEventType hassle hidden ftom the library user, therefore he will not need to add all the packages containing TEventType implementations.
I'm not sure if you can avoid referencing 3rd party assemblies if you use classes like Google.Apis.Calendar.v3.Event directly in your code.
However, you can use ILMerge to merge 3rd party API into your own, that way the dependencies of your assemblies will be deployed along with your assemblies.
I usually use ILMerge in the post build event.
For example:
After GoogleCalendarAPI project is built, merge GoogleCalendarAPI.dll and Google.Apis.Calendar.v3.dll and save it in "GoogleCalendarAPI_location\mergerd\GoogleCalendarAPI.dll"
Copy "GoogleCalendarAPI_location\mergerd\GoogleCalendarAPI.dll" to the location of the original GoogleCalendarAPI.dll and replace it.
Now you've got GoogleCalendarAPI.dll with Google.Apis.Calendar.v3 baked into it.
Now every assembly that references GoogleCalendarAPI.dll gets both.
I created a class (observer) that will perform some actions based on certain events in other classes (publishers). The observer and publishers all within one dll.
I could create another class in the assembly and require that client applications call something like BootStrapper.Configure() before using other classes; however, I'd like to avoid needing to update all the client applications at the same time.
I could create a base class for the publisher classes and call BootStrapper.Configure() from there; however, the publishers currently inherit different base classes. I'd like to avoid refactoring those classes for now.
What I would really like to do is ensure that the "observer" class is instantiated when the client application is started, or the first time any class in the dll is referenced.
What is the best way to ensure the "observer" class will be instantiated before any "publishers" publish an event?
Sample Project: https://www.box.com/s/0ihvp11kd7bfb6mqlnmc
I would like to make any method in BootStapper.cs execute when LogicLibrary is loaded.
Updated in response to the posted project
The current design in the provided solution constrains the publisher(s) to be within the assembly (since the bootstrapper is hardcoding the delegate hookup) which only adds complexity without benefit. If you had publishers outside the assembly housing the observer, your current pattern would require a bootstrapper in each assembly containing a publisher. This is simply moving lines from one place to a less obvious place and will wind up being harder to maintain.
I'd recommend looking at the IObserver interface and the example implementation given there: http://msdn.microsoft.com/en-us/library/dd783449.aspx
Previous response:
If you are simply using a classic singleton as your observer, and need to reference said singleton to hook up your events, the act of referencing the singleton will ensure its creation.
It seems unnecessary to specify that the observer must be created before any class in the DLL is referenced. You should only need to guarentee that the observer is created before any publisher will raise its event.
A better solution would be to use an IOC container to create the singleton instance of the observer and automatically hook up the event for all publishers.
There are a few methods of going about this. One method might be to use DllMain in a C++/CLR wrapper DLL, but I'd have to give that some extra thought. I'd be more likely to call some sort of instantiation method from the static constructor of every class in the DLL to keep it fully managed.
internal static class DllMain
{
private volatile bool Initialized = false;
public static void OnStaticConstructor()
{
if (!Initialized)
{
Initialized = true;
Initialize();
}
}
private void Initialize()
{
// Put whatever you need to run once here.
}
}
public class A
{
static A()
{
DllMain.OnStaticConstructor();
}
// ...
}
public class B
{
static B()
{
DllMain.OnStaticConstructor();
}
// ...
}
In one of the applications I am working on, there are two basic functionalities included: Create and Update.
However, there is a need sometimes to add custom code, so I thought of extending the code by allowing 3rd parties to write and embed their own code:
OnCreating
OnCreated
OnUpdating
OnUpdated
Is there a way to enable the above across multiple assemblies? MEF might help here?
Thank you
Regards
Thanks all for your replies.
Having such an interface means each external assembly has to implement that interface as needed. Then, my application's code, needs to loop through the currently running assemblies, detect all classes implementing that interface, and run their methods?
Does MEF fit here? I can export the implementation from external assemblies and import them inside my app?
Thank you
Regards
You can't have partical classes accross assemblies because partial classes are a language feature, and not a CLR feature. The C# compiler merges all the partial classes into one real class, and that single class the the only thing left after compilation.
You have a couple of alternatives:
Offer events
Make the methods virtual and override them
Use an interface
Your problem looks like it fits events best. The user can simply subscribe to them in the other assembly.
Regarding your MEF question, you could probably do something like the following to run methods from an interface:
var catalog = new DirectoryCatalog("bin");
var container = new CompositionContainer(catalog);
container.ComposeParts();
var plugins = container.GetExportedValues<IPlugin>();
foreach (IPlugin plugin in plugins)
{
plugin.OnCreating();
}
Or create an interface with events as Brian Mains suggested:
public interface IPlugin
{
event OnCreatingEventHandler OnCreating;
}
then the above code would be more like:
var catalog = new DirectoryCatalog("bin");
var container = new CompositionContainer(catalog);
container.ComposeParts();
var plugins = container.GetExportedValues<IPlugin>();
foreach (IPlugin plugin in plugins)
{
plugin.OnCreating += MyOnCreatingHandler;
}
I think I like the latter for the method names you specified. For my plugin work, I've created an interface similar to the following:
public interface IPlugin
{
void Setup();
void RegisterEntities();
void SeedFactoryData();
}
The RegisterEntities() method extends the database schema at runtime, and the SeedFactoryData() method adds any default data (eg. adding default user, pre-population of Cities table, etc.).
Having partial classes supported across assemblies isn't supported.
The reason being that all partial class definitions are combined into a single class during compile time. That single class resides in a single assembly.
Consider using an interface:
IUpdatableObject<X>
Creating(X obj);
Created(X obj);
Updating(X obj);
Updated(X obj);
And then use this interface to add in custom code; each third party can implement this interface (well either they or you can through a wrapper) and this can be a tie into adding custom business logic.
HTH.
You (or the user) can use extension methods:
http://msdn.microsoft.com/en-us/library/bb383977.aspx
Partial methods and classes must be in the same assembly. Partial methods are compiled out if not used. If you need extension points for you classes you should look into virtual methods or events.
Partial classes across assemblies aren't supported because the concept behind the partial class is to allow multiple developers to contribute different methods and members for the same class under a particular namespace.
This was done in order to help developers to sync the code into a single class, inside one assembly, build after compilation.
Consider the following code.
public interface IFoo { }
public class Bar
{
public Bar(IFoo[] foos) { }
}
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IFoo[]>().ToConstant(new IFoo[0]);
// ToConstant() is just an example
}
}
public class Program
{
private static void Main(string[] args)
{
var kernel = new StandardKernel(new MyModule());
var bar = kernel.Get<Bar>();
}
}
When I try to run the program I get the following exception.
Error activating IFoo
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IFoo into parameter foos of constructor of type Bar
1) Request for Bar
How can I inject / bind to an array in Ninject?
Thanks for your time.
Edit:
My application imports data which is created by a third party component.
The import process applies different kind of filters (e.g. implementations of different filter interfaces). The rules for filtering change quite often but are too complex to be done with pure configuration (and a master filter).
I want to make adding/editing filters as easy as possible. What I have is an assembly where all the filter implementations are located in. I tried to bind every filter interface to the following method (which provides an instance of every implementation of that filter type). Basically I want to avoid the need to change my Ninject module when I add/remove filter classes.
private IEnumerable<TInterface> GetInterfaceImplementations<TInterface>(IContext context)
{
return GetType().Assembly.GetTypes()
.Where(t => typeof (TInterface).IsAssignableFrom(t) && IsConcreteClass(t))
.Select(t => Kernel.Get(t)).Cast<TInterface>();
}
I am feeling a bit guilty in terms of bypassing the containers DI mechanism. Is this a bad practice? Is there a common practice to do such things?
Resolution:
I use a wrapper class as bsnote suggested.
Ninject supports multi injection which would resolve your issue. https://github.com/ninject/ninject/wiki/Multi-injection
public interface IFoo { }
public class FooA : IFoo {}
public class FooB : IFoo {}
public class Bar
{
//array injected will contain [ FooA, FooB ]
public Bar(IFoo[] foos) { }
}
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IFoo>().To<FooA>();
Bind<IFoo>().To<FooB>();
//etc..
}
}
This is largely a restatement of #bsnote's answer (which I've +1d) which may help in understanding why it works in this manner.
Ninject (and other DI / addin frameworks) have two distinct facilities:
the notion of either binding to a single unambiguous implementation of a service (Get)
A facility that allows one to get a set of services [that one then programmatically picks one of or aggregates across in some way] (GetAll / ResolveAll in Ninject)
Your example code happens to use syntax that's associated with 2. above. (e.g., in MEF, one typically use [ImportMany] annotations to make this clear)
I'd need to look in the samples (look at the source - its really short, clean and easy to follow) to find a workaround for this.
However, as #bsnote says, one way of refactoring your requirement is to wrap the array either in a container, or to have an object that you ask for it (i.e., a factory method or repository type construct)
It may also be useful for you to explain what your real case is - why is there a naked array ? Surely there is a collection of items construct begging to be encapsulated underlying all this - this question certainly doesnt come up much?
EDIT: There are a set of scanning examples in the extensions that I imagine would attack a lot of the stuff you're trying to do (In things like StructureMap, this sort of stuff is more integrated, which obviously has pros and cons).
Depending on whether you're trying to achieve convention over configuration or not, you might want to consider sticking a marker interface on each type of plugin. Then you can explicitly Bind each one. Alternately, for CoC, you can make the Module's Load() routine loop over the set of implementations you generate (i.e., lots of individual Gets) in your edit.
Either way, when you have the multiple registrations in place you can happily either 'request' a T[] or IEnumerable<T> and get the full set. If you want to achieve this explicitly (i.e., Service Locator and all it implies - like in you're doing, you can use GetAll to batch them so you're not doing the looping that's implicit in the way you've done it.
Not sure if you've made this connection or if I'm missing something. Either way, I hope it's taught you to stick some code into questions as it speaks > 1000 words :P
It was a problem for me as well. Ninject injects each item of an array instead of the array itself, so you should have a mapping defined for the type of array items. Actually there is no possibility to map the array as a type with the current version of Ninject. The solution is to create a wrapper around the array. Lazy class can be used for example if it suits you. Or you can create your own wrapper.
Since Array implements IReadOnlyList the following works.
// Binding
public sealed class FooModule: NinjectModule
{
public opverride void Load()
{
Bind<IReadOnlyList<IFoo>>().ToConstant(new IFoo[0]);
}
}
// Injection target
public class InjectedClass {
public InjectedClass(IReadOnlyList<IFoo> foos) { ;}
}
I'm a complete newbie to ninject
I've been pulling apart someone else's code and found several instances of nInject modules - classes that derive from Ninject.Modules.Module, and have a load method that contains most of their code.
These classes are called by invoking the LoadModule method of an instance of StandardKernel and passing it an instance of the module class.
Maybe I'm missing something obvious here, but what is the benefit of this over just creating a plain old class and calling its method, or perhaps a static class with a static method?
The Ninject modules are the tools used to register the various types with the IoC container. The advantage is that these modules are then kept in their own classes. This allows you to put different tiers/services in their own modules.
// some method early in your app's life cycle
public Kernel BuildKernel()
{
var modules = new INinjectModule[]
{
new LinqToSqlDataContextModule(), // just my L2S binding
new WebModule(),
new EventRegistrationModule()
};
return new StandardKernel(modules);
}
// in LinqToSqlDataContextModule.cs
public class LinqToSqlDataContextModule : NinjectModule
{
public override void Load()
{
Bind<IRepository>().To<LinqToSqlRepository>();
}
}
Having multiple modules allows for separation of concerns, even within your IoC container.
The rest of you question sounds like it is more about IoC and DI as a whole, and not just Ninject. Yes, you could use static Configuration objects to do just about everything that an IoC container does. IoC containers become really nice when you have multiple hierarchies of dependencies.
public interface IInterfaceA {}
public interface IInterfaceB {}
public interface IInterfaceC {}
public class ClassA : IInterfaceA {}
public class ClassB : IInterfaceB
{
public ClassB(IInterfaceA a){}
}
public class ClassC : IInterfaceC
{
public ClassC(IInterfaceB b){}
}
Building ClassC is a pain at this point, with multiple depths of interfaces. It's much easier to just ask the kernel for an IInterfaceC.
var newc = ApplicationScope.Kernel.Get<IInterfaceC>();
Maybe I'm missing something obvious
here, but what is the benefit of this
over just creating a plain old class
and calling its method, or perhaps a
static class with a static method?
Yes, you can just call a bunch of Bind<X>().To<Z>() statements to setup the bindings, without a module.
The difference is that if you put these statements in a module then:
IKernel.Load(IEnumerable<Assembly>) can dynamically discover such modules through reflection and load them.
the bindings are logically grouped together under a name; you can use this name to unload them again with IKernel.Unload(string)
Maybe I'm missing something obvious here, but what is the benefit of this over just creating a plain old class and calling its method, or perhaps a static class with a static method?
For us, it is the ability to add tests at a later time very easily. Just override a few bindings with mockobjects and voila.....on legacy code without a DI that wired "everything" up, it is near impossible to start inserting test cases without some rework. With a DI in place AND as long as it was used properly where the DI wired everything up, it is very simple to do so even on legacy code that may be very ugly.
In many DI frameworks, you can use the production module for your test with a test module that overrides specific bindings with mockobjects(leaving the rest of the wiring in place). These may be system tests more than unit tests, but I tend to prefer higher level tests than the average developer as it tests the integration between classes and it is great documentation for someone who joins the project and can see the whole feature in action(instead of just parts of the feature) without having to setup a whole system).