Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection / Constructor Injection Help

I have the following classes / interfaces:

public interface IProjectRepository
{
    IQueryably<Project> GetProjects();
}

// Depends on my EF Context
public ProjectRepository : IProjectRepository
{
    private MyDbEntities context;

    public ProjectRepository(MyDbEntities context)
    {
        this.context = context;
    }

    public IQueryable<Project> GetProjects() 
    {
        return context.Projects;
    }
}

My controller:

 // Depends on IProjectRepository
 public class ProjectsController : Controller
 {
     private IProjectRepository projectRepository;

     public ProjectsController(IProjectRepository projectRepository)
     {
         this.projectRepository = projectRepository;
     }

     public ActionResult Index()
     {
         return View(projectRepository.GetProjects());
     }
 }

I need to set up my dependency injection so that it passes in ProjectRepository into my Controller AND it needs to pass in my Entity Framework context into the Project Repository. I need to Entity Context to be HTTP Request scoped.

I'm not sure where I am supposed to put all the mapping code to make the dependency injection work. I also don't understand how MVC will work without the default constructor.

Can someone help me put all the pieces together? I am using StructureMap but I could easily switch to something else because I have no idea what I'm doing.

like image 748
Dismissile Avatar asked Dec 14 '25 07:12

Dismissile


1 Answers

If you are using MVC 3, to do things properly, you should make use of the built in dependency resolution bits. I would highly recommend you read through the series of blog posts from Brad Wilson (member of the ASP.NET MVC team).

As far as a StructureMap specific implementation, I found the following blog posts helpful.

StructureMap and ASP.NET MVC 3 – Getting Started
StructureMap, Model Binders and Dependency Injection in ASP.NET MVC 3
StructureMap, Action Filters and Dependency Injection in ASP.NET MVC 3
StructureMap, Global Action Filters and Dependency Injection in ASP.NET MVC 3

Anyway, here's some code. To start with, I would suggest that you install the StructureMap-MVC3 NuGet package.

I can't remember what exactly it creates in the way of files, but here's what's basically involved.

/App_Start/StructuremapMvc.cs - This hooks into the Application_Start and sets up your container (SmIoC.Initialize()) and then sets the MVC 3 DependencyResolver to a your SmDependencyResolver

using System.Web.Mvc;
using YourAppNamespace.Website.IoC;
using StructureMap;

[assembly: WebActivator.PreApplicationStartMethod(typeof(YourAppNamespace.App_Start.StructuremapMvc), "Start")]

namespace YourAppNamespace.Website.App_Start {
    public static class StructuremapMvc {
        public static void Start() {
            var container = SmIoC.Initialize();
            DependencyResolver.SetResolver(new SmDependencyResolver(container));
        }
    }
}

/IoC/SmDependencyResolver.cs - this is your MVC 3 IDependencyResolver implementation. It's used in the App_Start code above.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StructureMap;

namespace YourAppNamespace.Website.IoC
{
    public class SmDependencyResolver : IDependencyResolver
    {
        private readonly IContainer _container;

        public SmDependencyResolver(IContainer container)
        {
            _container = container;
        }

        public object GetService(Type serviceType)
        {
            if (serviceType == null)
            {
                return null;
            }

            try
            {
                return _container.GetInstance(serviceType);
            }
            catch
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _container.GetAllInstances(serviceType).Cast<object>(); ;
        }
    }
}

/IoC/SmIoC.cs - this is where you setup your container... also used in the App_Start code.

namespace YourAppNamespace.Website.IoC
{
    public static class SmIoC
    {
        public static IContainer Initialize()
        {
            ObjectFactory.Initialize(x =>
                        {
                            x.For<IProjectRepository>().Use<ProjectRepository>();
                            //etc...
                        });

            return ObjectFactory.Container;
        }
    }
}

Now everything is hooked up... (I think ;-) but you still have one last thing to do. Inside your Global.asax, we need to make sure you dispose of everything that is HttpContext scoped.

protected void Application_EndRequest()
{
    ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}

So you should be able to achieve dependency injection through constructor injection, which is the correct way to go about doing things.

like image 65
Charlino Avatar answered Dec 15 '25 20:12

Charlino



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!