简体   繁体   中英

How do I inject dependencies into a model?

Typically, an action method will end with something like this:

return View(new Model());

But if my model is going to have services injected, it won't have a default ctor. So it would have to look like this:

return View(new Model(new Service());

But if the service has dependencies it'd be more like this:

return View(new Model(new Service(new Repository())));

...which starts to get ridiculous. Isn't this what a IoC container is for? So I'd be tempted to write something more like this:

return View(container.Resolve<IModel>());

but in order to get container it would have to be injected into my controller, and I hear that injecting the container itself is an anti-pattern .

So what is the right way? How do I pass my dependencies to my model when I return the view from the action method?

But if my model is going to have services injected

Prevent letting your view models from having dependencies in the first place. View models should be dumb data containers and they should be fully constructed when the controller action returns. This simplifies the view and the model and prevents the situation completely.

In case however you really want to pass on dependencies to the view model, there should be no reason to pass a dependency's dependencies. You only have to pass in the dependency, and since your controller is an application component, it will have that dependency injected into its constructor. So it will typically look as follows:

public class HomeController : Controller
{
    private readonly IService service;

    public HomeController(IService service)
    {
        this.service = service;
    }

    public ViewResult Index()
    {
        return View(new Model(this.service));
    }
}

Since HomeController will be built-up by the DI Container with its dependencies (which means Service will be built-up using Repository ), you can just pass on the service dependency without having to know anything about its dependency.

and I hear that injecting the container itself is an anti-pattern.

That's correct. Using the Container outside the Composition Root is a bad idea.

You are right. Doing dependency injection properly makes your code cleaner, but adds cluttered code that does injection and initialisation. That's where DI frameworks come in place. Their major aim is to handle exactly situations like yours - remove cluttered constructor injection code without the need of passing along the container. With a DI framework like Ninject your code would look like this:

IKernel kernel = new StandardKernel();
Bind<View>();
Bind<Model>();
Bind<Service>();
Bind<Repository>();
var view = kernel.Get<View>();

Contrast between what you would do manually and what a DI framework would do is shown in these two articles:

BTW there are many other good DI frameworks around. You don't need to take Ninject, basic idea of all of them is the same.

I've used a static container object initialized in the bootstrapper code, but at times I have had to pass the container in a param. Some code smell, but imagine a procedure with a lot of dependencies. But if you use DI with MVC you get the container injected automatically, and that is the pattern that I see (check out Autofac MVC ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM