Jacek
Jacek

Reputation: 12053

Inject object as lazy loading

I have MVC code like below. I use nInject for IoC. I wonder when I push request to do for example SendMail there is create controller object, nInject create subobjects for both readonly objects: _mailSrv and _dbSrv, but I need in this request only one variable.

Is it possible to inject variable as lazy loading. When code will need object, then it will be created?

public class HomeController:Controller
{
    private readonly IMailService _mailSrv;
    private readonly IDatabaseService _dbSrv;

    public HomeController:Controller(IMailService mailSrv, IDatabaseService dbSrv)
    {
        _mailSrv = mailSrv;
        _dbSrv = dbSrv;
    }

    public ActionResult SendMail(string mailAddress)
    {
        _mailSrv.Do(mailAddress);
    }

    public ActionResult SaveToDatabase(int id, string data)
    {
        _dbSrv.Do(id, data);
    }
}

Upvotes: 4

Views: 599

Answers (2)

Greg
Greg

Reputation: 1116

Just tried it out.

Add Ninject.Extensions.Factory to your project and change the member variables to Lazy.

public class HomeController : Controller
{
    private readonly Lazy<IMailService> _mailSrv;
    private readonly Lazy<IDatabaseService> _dbSrv;

    public HomeController(Lazy<IMailService> mailSrv, Lazy<IDatabaseService> dbSrv)
    {
        _mailSrv = mailSrv;
        _dbSrv = dbSrv;
    }

    public ActionResult SendMail(string mailAddress)
    {
        _mailSrv.Value.Do(mailAddress);            
    }

    public ActionResult SaveToDatabase(int id, string data)
    {
        _dbSrv.Value.Do(id, data);            
    }
}

Instances will now be created lazily.

Upvotes: 5

Ewan
Ewan

Reputation: 1285

Hmm, Not sure about ninject in particular, but normally no, you would get instances of the objects when the controller is instantiated.

Alternatives would be:

Make two controllers (I suggest this one)

Inject factories rather than objects

Personally this is not for me, I think the IoC container should be your factory.

public ActionResult SendMail(string mailAddress)
    {
        _mailSrvFactory.Create().Do(mailAddress);
    }

Directly bind the object in the method rather than injecting

This is usually considered 'bad' because you have to pass the IoC container around

public ActionResult SendMail(string mailAddress)
    {
        kernel.Get<IMailServer>().Do(mailAddress);
    }

I guess looking at it at a deeper level, It might be possible to create a custom scope which in effect wrapped the class in a factory in the same way that IoC containers can provide classes as singletons. I'd have to think about that one though

Upvotes: 2

Related Questions