views:

91

answers:

2

Hello,

I am trying to use Unity 2.0 for my current project with MVC and having trouble configuring paramter injection in the web.config file.

Here's what I have:

1) A Home Controller:

public class HomeController : Controller
{
    IRepository repository = null;

    public HomeController()
    {
       // Always calls this constructor. Why? 
       // Should be calling the constructor below that takes IRepository.
    }

    public HomeController(IRepository repository)
    {
        // Should be calling this constructor!!!
        this.repository = repository;
    }
    public ActionResult Index()
    {
        List<int> intList = this.repository.GetInts();

        ViewData["Message"] = "Welcome to ASP.NET MVC!";

        return View();
    }

A basic controller with two constructors. The 1st one takes no arguments, and the 2nd one takes IRepository as an argument (that's supposed to be injected by Unity)

2) SQL Repository

public class SQLRepository : IRepository
{
    private string connectionString = null;

    public SQLRepository(string connectionString)
    {
        this.connectionString = connectionString;
    }

    #region IRepository Members

    public List<int> GetInts()
    {
        return new List<int>() { 1, 2, 3, 4, 5 };
    }

    #endregion
}

A future to be SQL repository, but for now it just implements 1 member of the IRepository interface, namely GetInts() and returns a list of integers.

3) IRepository Interace

public interface IRepository
{
    List<int> GetInts();
}

An interface.

4) Application_Start() Event in my Global.asax file.

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterRoutes(RouteTable.Routes);

        IUnityContainer container = new UnityContainer();

        UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
        section.Configure(container, "Default");
    }

This is used to read the Unity 2.0 configuration from the web.config file in order to register and map types etc.

6) The Unity 2.0 Configuration Section in web.config

<unity>
<typeAliases>
  <typeAlias alias="string" type="System.String, mscorlib" />
  <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
  <typeAlias alias="IRepository" type="NewMVCApp.Interfaces.IRepository, NewMVCApp" />
  <typeAlias alias="SQLRepository" type="NewMVCApp.Repository.SQLRepository, NewMVCApp" />
</typeAliases>
<containers>
  <container name="Default">
    <types>
      <type type="IRepository" mapTo="SQLRepository">
        <lifetime type="singleton" />
        <constructor>
          <param name="connectionString">
            <value value="ApplicationServices" />
          </param>
        </constructor>
      </type>
    </types>
  </container>
</containers>

This is Unity 2.0 configuration section that I use. As you can see It typeAlias for both my IRepository and my SQLRepository classes and then maps IRepository to SQLRepository. So that anytime IRepository is requested, SQLRepository instance will be supplied. Also, I want to pass a connection string via the constructor to my SQLRepository.

5) So, what am I trying to do?

I am trying to use Unity 2.0 to pass in the instance of IRepository (SQLRepository) to my HomeController. But for some reason the default, parameterless constructor, for the HomeController() gets invoked. But HomeController(IRepository repository) never gets called. I am pretty sure that I did not set things up properly in the web.config file. But I am not sure how do set things up properly so the correct constructor on the HomeController gets called. Please help:)

&Thank you:)

+1  A: 

Your Unity configuration looks fine. The problem is that you haven't hooked up Unity to the MVC framework, so the framework isn't using the container to create your controller, instead MVC is using the default logic, which calls the default constructor.

You need two things. First, an implementation of IControllerFactory. I usually use this one:

public class UnityControllerFactory : DefaultControllerFactory
{
    private readonly IUnityContainer container;

    public UnityControllerFactory(IUnityContainer container)
    {
        this.container = container;
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if(controllerType != null)
            return container.Resolve(controllerType) as IController;
        return base.GetControllerInstance(requestContext, controllerType);
    }
}

Second, you need to tell the MVC framework to use this controller factory instead of it's default one. You do this in your Application_Start handler. Do this:

ControllerBuilder.Current.SetControllerFactory(
    new UnityControllerFactory(container));

Once you've done that, your controllers will be created through the container and everything should start working.

Chris Tavares
A: 

Thank you so much Chris!! That was it! Here's the how the Application_Start() event should look like in MVC2 using Unity 2.0:

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterRoutes(RouteTable.Routes);

        IUnityContainer container = new UnityContainer();

        IControllerFactory controllerFactory = new UnityControllerFactory(container);
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);

        // Do the line below only if you want to Register IoC programatically
        //container.RegisterType<IRepository, SQLRepository>(new ContainerControlledLifetimeManager());

        UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
        section.Configure(container, "Default");
    }
Boriska64