How to inject dependency into CompositeControl?
I tried the following approach - MyServerControl's Calculate is still null.
Thanks!
public class MyServerControl : CompositeControl
{
private TextBox TextBox1;
private TextBox TextBox2;
private Label Label1;
[Inject] // **** This is null ****
public ICalculate Calculate { get; set; }
protected override void CreateChildControls()
{
TextBox1 = new TextBox {ID = "TextBox1", Text = "1"};
Controls.Add(TextBox1);
TextBox2 = new TextBox {ID = "TextBox2", Text = "2"};
Controls.Add(TextBox2);
var button1 = new Button {ID = "Button1", Text = "Calculate"};
button1.Click += button1_Click;
Controls.Add(button1);
Label1 = new Label {ID = "Label1"};
Controls.Add(Label1);
}
private void button1_Click(object sender, EventArgs e)
{
int value1 = Int32.Parse(TextBox1.Text);
int value2 = Int32.Parse(TextBox2.Text);
Label1.Text = "Result:" + Calculate.Add(value1, value2);
}
}
public interface ICalculate
{
int Add(int x, int y);
}
public class Calculate : ICalculate
{
public int Add(int x, int y)
{
return x + y;
}
}
Default Ninject.Web.Common Bootstrapper from NuGet:
using System.Net.NetworkInformation;
[assembly: WebActivator.PreApplicationStartMethod(typeof(NinjectDemo.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(NinjectDemo.App_Start.NinjectWebCommon), "Stop")]
namespace NinjectDemo.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
IKernel kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICalculate>().To<Calculate>().InSingletonScope();
}
}
}
Updated:
I'm not able to get instance to kernel in Page_Load. Am I missing something?
<my:MyServerControl ID="MyServerControl1" runat="server" />
public partial class Default : Page
{
[Inject]
public ICalculate _calculate { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
kernel.Inject(MyServerControl1); // kernel is not available
}
}
Your Default page doesn't know about NinjectWebCommon class existence. It also cannot know about the kernel variable which is a NinjectWebCommon.CreateKernel() method's member. The simplest solution is the following:
The other way would be to use Ninject magic. Your application class would probably need to inherit from a class provided by Ninject. In MVC it's a NinjectHttpApplication class, which overrides the bootstrapper. Than you could probably go with Wiktor's answer.
Honestly I don't like that Ninject magic, as it sometimes doesn't work for me and than it's very hard to find out why. In my MVC application I ended up creating my own ConfrollerFactory, which injected the dependencies explicitly. It also may be a pain if you want to change your IOC container.
I think you could just use the feature that satisfies dependencies on an existing object. In this particular case, in any context your control is used, you just call
where myControl is an existing instance of your composite control. This has to be called from the code behind, somewhere in the pipeline where the instance is already created. Page_Load would most probably be fine.
Edit: there are numerous ways to be able to resolve anywhere in your application. You could for example have a global service locator. But since you are using the Bootstrapper, you should be able to resolvd your kernel anywhere
you need to register your Ioc config, see example:
Add this class in your App_start folder, and then write in Global.asax.cs: