5

I am having trouble defining bindings using ninject.

I am in a standard ASP.NET WebForms application. I have defined an http handler to Inject dependencies in pages and controls (Property injection).

Here is what I am trying to do:

I am creating a custom combobox usercontrol. Based on the value of an enum on that combobox, I want to be able to Inject a different object in a property (What I am trying to do is a bit more involved than that, but answer to this should be enough to get me going).

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Martin
  • 5,954
  • 5
  • 30
  • 46

2 Answers2

10

A conditional binding based on a property value isn't a good design and isn't even possible (at least for constructor injection) as dependencies are normally created before the object receiving them. What if the property is changed later? The preferable way is to inject a factory or factory method that requests the instance from Ninject and exchange the strategy on initialization and property value change internally.

public enum EntityType { A,B } 
public class MyControl : UserControl
{
    [Inject]
    public Func<EntityType, IMyEntityDisplayStrategy> DisplayStrategyFactory 
    { 
        get { return this.factory; }
        set { this.factory = value; this.UpdateEntityDisplayStrategy(); }
    }

    public EntityType Type 
    { 
        get { return this.type; } 
        set { this.type = value; this.UpdateEntityDisplayStrategy(); };
    }

    private UpdateEntityDisplayStrategy()
    {
        if (this.DisplayStrategyFactory != null)
            this.entityDisplayStrategy = this.DisplayStrategyFactory(this.type);
    }
}

Bind<Func<EntityType, IMyEntityDisplayStrategy>>
    .ToMethod(ctx => type => 
         type == ctx.kernel.Get<IMyEntityDisplayStrategy>( m => 
             m.Get("EntityType", EntityType.A));
Bind<IMyEntityDisplayStrategy>.To<AEntityDisplayStrategy>()
    .WithMetadata("EntityType", EntityType.A)
Bind<IMyEntityDisplayStrategy>.To<BEntityDisplayStrategy>()
    .WithMetadata("EntityType", EntityType.B)

Alternatively add an activation action and inject the dependency manually. But be aware that changing the constraint property will lead to an inconsistent state.

OnActivation((ctx, instance) => 
    instance.MyStrategy = ctx.Kernel.Get<MyDependency>(m => 
        m.Get("MyConstraint", null) == instance.MyConstraint);
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Remo Gloor
  • 32,665
  • 4
  • 68
  • 98
  • I am not sure I understand your answer... :( I know that conditional binding based on a property value might not be ideal, but I don't have control over object creation because creation is controlled by ASP.NET. The enum I was talking about in my question is used to define the type of data to display (Entity). Based on the choice on the enum, a template and an object to query the database needs to be injected. The enum will only be set from the aspx file using the control. Even to inject the right factory, wouldn't I need to know the value of that enum ? – Martin Mar 29 '11 at 15:19
  • Added an example. Note I havent syntax checked the code so it probably won't compile. But it should explain what I have written before. – Remo Gloor Mar 29 '11 at 18:09
  • Thanks, It is nice. I ended up using something a bit different from your first example, but I did not know/realise that you can inject Func objects using ninject. – Martin Mar 29 '11 at 18:54
0

What I'm using (with Ninject 3 now) is a little different but it works for me. I create an array of dependencies and let them decide if they accept to handle the request or not. For example if I had this case

public enum FileFormat
{
    Pdf,
    Word,
    Excel,
    Text,
    Tex,
    Html
}

public interface IFileWriter
{
    bool Supports(FileFormat format)

    ...
}

public class FileProcessor
{
    FileProcessor(IFileWriter[] writers)
    {
        // build a dictionary with writers accepting different formats 
        // and choose them when needed
    }
}

public class MyModule : NinjectModule
{
     public override void Load()
     {
         ...

         Bind<IFileWriter>().To<PdfFileWriter>();
         Bind<IFileWriter>().To<WordFileWriter>();
         Bind<IFileWriter>().To<TexFileWriter>();
         Bind<IFileWriter>().To<TextFileWriter>();
         Bind<IFileWriter>().To<HtmlFileWriter>();
     }
}

I hope that helps!

Eugenio Miró
  • 2,398
  • 2
  • 28
  • 38