Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have a repository class that impliments a repository Interface. In my Controllers I want a way to access the repository without creating constructors each time in the controller. So now all my Controllers have to do is inherit from Base. Any pitfalls to this, or how I can write it differently.

public class BaseController : Controller
    {
        public IRepository Repo {get;set;}
        public IStudentRepositroy StudentRepo {get;set;};
      public BaseController() : this(new Repository(),new StudentRepository())
      {

      }
      public BaseController(IRepository repo,IStudentRepository studentRepo)
      {
          Repo = repo;
          StudentRepo = studentRepo;
      }

    }
share|improve this question
add comment

1 Answer

up vote 2 down vote accepted

This sounds exactly like a desire for Dependency Injection (using an IoC container). ASP.NET MVC is perfectly setup for this already with plenty of containers out there for you to use!

You can still have a base constructor take arguments if you wish but I would try and limit how many.

So your controllers would look like:

public StudentController(IRepository repo,IStudentRepository studentRepo)
        : base(repo)
{
      StudentRepo = studentRepo;
}

So by using the IoC framework these will be automatically resolved to your desired class. By doing this, it opens up the opportunity to more easily inject mock classes into your controllers and further separates them conceptually from implementation detail of the repositories. Although I typically do not Unit test my controllers (as I try to keep them as skinny as possible), it would also make unit testing easier.

Typically you might do this in the Global.ascx or in the App_Start folder. You can get most DI frameworks by using Nuget packages (which I would recommend). There are many out there but here are a couple of examples from ones I have dealt with in the past.

Autofaq

public class AutofaqConfig
{
    public static void Configure()
    {
        var builder = new ContainerBuilder();
        builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();

        RegisterRepositories(builder);

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }

    private static void RegisterRepositories(ContainerBuilder builder)
    {       
        builder.RegisterType<StudentRepository>().As<IStudentRepository>();
        // And any other repositories here
    }
}

And in your global ascx

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();            
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        AutofaqConfig.Configure();
    }
}

Ninject (Using the MVC3 ninject module)

public static class NinjectWebCommon 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);

        // Install our Ninject-based IDependencyResolver into the Web API config
        GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<StudentRepository>().To<IStudentRepository>();
    }        
}

Using Unity (Using Unit.MVC4)

public class UnityConfig
{
    #region Unity Container
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    /// <summary>
    /// Gets the configured Unity container.
    /// </summary>
    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }
    #endregion

    /// <summary>Registers the type mappings with the Unity container.</summary>
    /// <param name="container">The unity container to configure.</param>
    /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
    /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
    public static void RegisterTypes(IUnityContainer container)
    {
        // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
        // container.LoadConfiguration();

        // Repositories
        container.RegisterType<IStudentRepository, StudentRepository>();
    }
}
share|improve this answer
 
Thanks, I appreciate the time to explain this. –  Stone Temple Aviators Jan 26 at 20:20
 
The thing to remember is any extra param in your base class needs to be mirrored in all your controllers constructors. We've done this in the past, where we have had a basecontroller with say 20 controllers , and then we add a parm on the base constructor. now you need to update all 20 controllers and chain it through. To stop this we created a wrapper class, called "ControllerPayload" and only pass that through. Anything we need to add, like your repo or whatever, we add as properties on this object. Now you can maintain it a lot easier, as you only need to updated the object. –  spaceman Jan 27 at 9:18
 
Nice idea spaceman. One reason why I like keeping parameters in controllers however is it allows me to help identify perhaps design issues. If I find my controller requiring more than 3-4 parameters I start to ask myself what's going on and is there a better way. Your idea is sound though as well. –  dreza Jan 27 at 19:39
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.