Ninject knows a new trick

Ninject knows a new trick
by Ivan Porto Carrero
Posted March 15th, 2009 at 1:32 am

Earlier this week Nate already said that I was doing some work on Ninject, now I have it working :) .  Everything I’m about to talk about is currently in the master tree of the ninject github repository.  Getting IronRuby to play nice with Ninject was surprisingly easy :) ,

There was only one place that required some kind of weird workaround and from that workaround I’m entirely sure that it will go away by the time .NET 4.0 will be here.  The DLR duplicates a number of delegates from .NET 4.0 but .NET 3.5 also defines them (i.e. System.Func<T, TT>) and then you get great exception messages like: System.Func is not of type System.Func. The solution is to not reference System.Core in your project. Except that Ninject expects the System.Core variant at some point and that was solved by aliasing the System.Core assembly and talking to the types in that assembly by their alias.

Anyway the juicy stuff :) How can you take advantage of Ninjects newly found friendship with IronRuby.

Ninject now has 2 flavors of Kernels. We have a StandardKernel that knows how to deal with the module configuration system that uses a fluent interface defined in C#.  And now we also have a DlrKernel that extends the StandardKernel with a RubyModuleLoader plugin. If you tell the DlrKernel to look inside a path for configuration files it will scan those folders for *.dll or *.rb files. Those files should contain the configuration for the ninject bindings.

So to create a Kernel that is ruby enabled you would use the following code:

IKernel kernel = new DlrKernel();
kernel.AutoLoadModulesRecursively();

var samurai = kernel.Get<IWarrior>();
System.Console.WriteLine(samurai.Weapon.Name);
 

The above snippet could then for example load a configuration file that has been defined like this:

require File.dirname(__FILE__) + '/../Ninject.Tests.dll'
include Ninject::Tests::Fakes

to_configure_ninject do |ninject|
  ninject.bind IWeapon, :to => Sword
  ninject.bind IWarrior, :to => Samurai
end
 

The configuration above shows how most of a typical configuration would be defined by you the full configuration API at your disposal. All the options for the configuration can be specified in 2 ways. The first way is in a hash like syntax and the second way uses a more fluent syntax.

to_configure_ninject do |ninject|

  ninject.bind IServiceA, :to => ServiceA, :as => :singleton,

    :meta => { :type => "superservice" },

    :name => "aaaaa",

    :with => {

        :parameter => { :my_param => lambda { |context| "param_value" } },

        :constructor_arguments => {:const_arg => 56 },

        :property_values => {:property_name => 94 },

    },

    :o n_activation => lambda { |obj| obj.do_some_work },

    :o n_deativated => lambda { |obj| obj.do_some_cleanup },

    :when => lambda { |context| "a value" } or

    :when => { :injected_into => ServiceB } or

    :when => { :target_has => AnAttribute } or

    :when => { :member_has => AnAttribute } or

    :when => { :class_has => AnAttribute }

    }

end

Or

to_configure_ninject do |ninject|

  ninject.bind IServiceA, :to => ServiceA, :as => :singleton do

    meta :type => "superservice"

    name "aaaaa"

    with :parameter => { :my_param => lambda { |context| "param_value" } }

    with :constructor_arguments => { :const_arg => 56 }

    with :property_values => { property_name => 94 }

    on_activation do |obj|

      obj.do_some_work

    end

    on_deativation { |obj| obj.do_some_cleanup }

    condition do |context|

        true

    end or

    condition :injected_into => SomeClass or …

  end

end

Some of the nicer consequences of using Ruby as a configuration language is the syntax for open generics. The example below shows how to configure types with open generics.

require File.dirname(__FILE__) + '/../Ninject.Tests.dll'
include Ninject::Tests::Fakes
include Ninject::Tests::Integration::StandardKernelTests

# IGeneric is a generic interface and GenericService is a generic type
# we don't have to specify any special notation for open generics

to_configure_ninject do |ninject|
  ninject.bind IGeneric, :to => GenericService, :as => :transient 
  ninject.bind IGeneric, :to => GenericService2
end

To specify a condition the syntax would look like this

require File.dirname(__FILE__) + '/../Ninject.Tests.dll'
include Ninject::Tests::Fakes

to_configure_ninject do |ninject|
  ninject.bind IWeapon, :to => Shuriken do
    condition do |request|
        request.target.nil? 
             ? false 
             : request.target.member.reflected_type == Samurai.to_clr_type
      end
  end
  ninject.bind IWeapon, :to => Sword
  ninject.bind IWarrior, :to => Samurai
end

Well that’s all. I hope you like it. I will be looking into more ways to integrate DLR stuff into Ninject the most obvious is allowing you to inject dynamic types into static classes.

Technorati Tags: ,,
Tags: , ,
7 ResponsesLeave a comment
  • [...] Note: this entry was cross-posted from flanders.co.nz [...]

  • DotNetShoutout
    March 15, 2009 at 22:44

    Ninject knows a new trick – Ivan Porto Carrero…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  • Nicholas Blumhardt
    March 16, 2009 at 18:03

    Nice!

  • Rene
    May 25, 2009 at 22:34

    Do you know a way to add a Ruby class that implements a .net Interface? and bind that so ninject can use that?, im breen trying but no luck,

  • ivan
    May 25, 2009 at 22:41

    you have to include the interface in the ruby class.
    and then define all the methods of that interface with snake case naming.

    public interface IAmAnInterface {
    void SomeMethod();
    void AnotherMethod();
    }

    class Implementor
    include IAmAnInterface

    def some_method
    #implement here
    end

    def another_method
    #implement here
    end
    end

  • Rene
    May 26, 2009 at 14:08

    When i do that i get:

    Additional information: wrong argument type Class (expected Module)

    im doing

    to_configure_ninject do |ninject|
    ninject.bind Interfaces::IEaea, :to => Rubyclass
    end

  • ivan
    May 26, 2009 at 14:14

    Rene can you submit an issue with steps to reproduce on the github page for this project.

    http://github.com/casualjim/ninject-dynamic/issues

Add a commentGet a Gravatar

* Name

* Email Address

Website Address

You can usethese tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Around The Site
Categories
Archives
Tags