Dany
Dany

Reputation: 395

IoC Container doesn't work on WebForms

I want to implement IoC container using ASP.NET web forms. I'm completed these steps:

  1. Install Ninject and Ninject.Web ddl

  2. public class Global : NinjectHttpApplication

  3. Create Kernel

    public override IKernel CreateKernel()
    {
        IKernel kernel = new StandardKernel(new Module.Module());
        return kernel;
    }
    
  4. Create Module

    public override void Load()
    {
        Bind<IMetricService>().To<MetricService>();
    }
    
  5. Using Inject on Page

    public partial class _Default : Page
    {
        [Inject] 
        private IMetricService metricService;
    
        protected void Page_Init(object sender,EventArgs e)
        {
             metricService = new MetricService(metricService);
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
             metricService.GetAllMetrics();
        }
    }
    

And this is my MetricService class

 public class MetricService : IMetricService
 {
        [Inject]
        private IMetricService _metricService;

        public MetricService(IMetricService metricService)
        {
            this._metricService = metricService;
        }

        public void GetAllCriteria()
        {
            _metricService.GetAllCriteria();
            Console.WriteLine("metric service");
        }
 }

As I understand when pass the IMetricService in MetricService constructor the IoC container must bind this MetricService class. I think my mistake is general but I can't understand where.

Upvotes: 2

Views: 203

Answers (2)

Dany
Dany

Reputation: 395

Can I make on this way?

        [Inject]
        private IMetrics metrics;

        protected void Page_Init(object sender, EventArgs e)
        {
            metrics = new Metrics(metrics);
        }

Where I have

 private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IMetrics>().To<Metrics>();
        }      

This is my Metric class

 public class Metrics : IMetrics
    {
        private IMetrics metrics;

        public Metrics(IMetrics metrics)
        {
            this.metrics = metrics;
        }
    }  

And when I put the metric in Page_Init Ninject Container put the real Metric class or I need to user property to do that.My idea is in the Page and in the Metric class this IMetri* interface to have a valid state.


When I make on this way Exception is thrown

        [Inject]
        public IMetrics metrics { get; set; }

        protected void Page_Init(object sender, EventArgs e)
        {
            metrics = new Metrics(metrics);
        }

Error activating IMetrics using binding from IMetrics to Metrics
A cyclical dependency was detected between the constructors of two services.
Activation path:
 3) Injection of dependency IMetrics into parameter metrics of constructor of type Metrics
 2) Injection of dependency IMetrics into property metrics of type _Default
 1) Request for default_aspx

Suggestions:
 1) Ensure that you have not declared a dependency for IMetrics on any implementations of the service.
 2) Consider combining the services into a single one to remove the cycle.
 3) Use property injection instead of constructor injection, and implement IInitializable
    if you need initialization logic to be run after property values have been injected.

Upvotes: 0

mason
mason

Reputation: 32703

You need to use public properties with the Inject attribute, so they can be seen. Also, don't rely on a concrete implementation of the MetricService class. The class consuming the service should only rely on an abstracted implementation (the interface, in this case IMetricService).

public partial class _Default : Page
{
    [Inject]
    public IMetricService metricService { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        metricService.GetAllMetrics();
    }
}

And metric service doesn't need an instance of itself. That's just a recipe for disaster. Change your MetricService class so that it now retrieves all the criteria without the need to call itself via recursion.

public class MetricService : IMetricService
{
    public void GetAllCriteria()
    {
        //this is where you call out to your database
        //or do whatever else you need to do to return the criteria
    }
}

Also, I take it that GetAllCriteria is supposed to return something? That's usually what methods that start with the prefix "get" mean. So you'll need to change the return type from void to the type that you're returning.

Upvotes: 3

Related Questions