views:

528

answers:

5

I write some C# class libary and I want to use Ninject to provide dependency injection for my classes. Is it possible for class libary to declare some code (method) that would be executed each fime the class libary is loaded. I need this to define bindings for Ninject.

+4  A: 

It sounds like you are looking for the equivalent of C++'s DllMain. There is no way to do this in C#.

Can you give us some more information about your scenario and why you need code to execute in a DllMain style function?

Defining a static constructor on a type does not solve this problem. A static type constructor is only guaranteed to run before the type itself is used in any way. You can define a static constructor, use other code within the Dll that does not access the type and it's constructor will never run.

JaredPar
A: 

As far as I know the answer is no .As I understand you want to configure your IoC container in your class library and If that's the case it's not a good idea to do that.If you define your bindings in your class library then what's the use of dependency injection? we use dependency injection so that we can inject dependencies at runtime then we can inject different objects in different scenarios.Although the best place to configure an IoC container is the start up of your application (since an IoC container is like a backbone for an application :) ) but it should be placed at a bootstrap that is responsible to start the application.In simple applications it can be the Main method.

Beatles1692
There are plenty of situations where you'd like to define bindings in a class library. You could potentially have different implementations of the same service in different libraries, both of which may be relevant in the same application at the same time based on the context in which the service is used. Ninject (as do other IoC's) offers the ability to define contextual bindings, thus having the ability to activate different concrete services based some supplied context.
Peter Meyer
A: 

Can you control the client code? If yes, instead of trying to do magic when loading assembly, I would go for implementing a single class like Registry which does the bindings, implementing an interface IRegistry. Then during loading you can look for the implementation of IRegistry in your assembly and fire necessary methods.

You can also have attributes on your classes:

[Component(Implements=typeof(IMyDependency)]

look for these attributes and load them to the container on the client side.

Or you can take a look at MEF which is a library for these kind of situations.

bbmud
+1  A: 

Have you tried the AppDomain.AssemblyLoad event? It fires after an assembly has been loaded.

AppDomain.CurrentDomain.AssemblyLoad += (s, e) =>
{
    Assembly justLoaded = e.LoadedAssembly;
    // ... etc.
};
Daniel Earwicker
+1  A: 

I have used Ninject quite a bit over the last 9 months. Sounds like what you need to do is "load" your modules that exist in your libray into the Ninject kernel in order to register the bindings.

I am not sure if you're using Ninject 1.x or the 2.0 beta. The two versions perform things slightly differently, though conceptually, they are the same. I'll stick with version 1.x for this discussion. The other piece of information I don't know is if your main program is instantiating the Ninject kernel and your library is simply adding bindings to that kernel, or if your library itself contains the kernel and bindings. I am assuming that you need to add bindings in your library to an existing Ninject kernel in the main assembly. Finally, I'll make the assumption that you are dynamically loading this library and that it's not statically linked to the main program.

The first thing to do is define a ninject module in your library in which you register all your bindings -- you may have already done this, but it's worth mentioning. For example:

public class MyLibraryModule : StandardModule {
  public override void Load() {
    Bind<IMyService>()
      .To<ServiceImpl>();
    // ... more bindings ...
  }
}

Now that your bindings are contained within a Ninject module, you can easily register them when loading your assembly. The idea is that once you load your assembly, you can scan it for all types that are derived from StandardModule. Once you have these types, you can load them into the kernel.

// Somewhere, you define the kernel...
var kernel = new StandardKernel();

// ... then elsewhere, load your library and load the modules in it ...

var myLib = Assembly.Load("MyLibrary");
var stdModuleTypes = myLib
                       .GetExportedTypes()
                       .Where(t => typeof(StandardModule).IsAssignableFrom(t));


foreach (Type type in stdModuleTypes) {
  kernel.Load((StandardModule)Activator.CreateInstance(type));
}

One thing to note, you can generalize the above code further to load multiple libraries and register multiple types. Also, as I mentioned above, Ninject 2 has this sort of capability built-in -- it actually has the ability to scan directories, load assemblies and register modules. Very cool.

If your scenario is slightly different than what I've outlined, similar principles can likely be adapted.

Peter Meyer