Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
    }
}
like image 781
Jacek Avatar asked Mar 16 '23 07:03

Jacek


2 Answers

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.

like image 154
Greg Avatar answered Mar 25 '23 02:03

Greg


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

like image 24
Ewan Avatar answered Mar 25 '23 02:03

Ewan