Resolving interface dependency in Unity 3.0

Jun 16, 2013 at 8:17 PM
I'm trying to get dependency injection working on a MVC 4 web application using Unity 3.0. I have the Unity bootstrapper for MVC 4 applications installed, and I've set up my web.config file and Global.asax files to start up the Unity configuration. If I use concrete objects, it works without problems, but I start getting exceptions if I start to try to inject concrete implementations of interfaces instead.

For example, my PersonController looks like this:
namespace RebuildingSite.Controllers
{
    public class PersonController : Controller
    {
        private static readonly LogWriter log = LoggingFactory.GetLogWriter();

        [Dependency]
        public PersonDao ThePersonDao { get; set; }

        //
        // GET: /Person/
        public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
        {
            ViewBag.CurrentSort = sortOrder;
            ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
            ViewBag.CitySortParm = sortOrder == "City" ? "City desc" : "City";

            if (Request.HttpMethod == "GET")
            {
                searchString = currentFilter;
            }
            else
            {
                page = 1;
            }

            ViewBag.CurrentFilter = searchString;

            page = page == null ? 1 : page;

            var people = ThePersonDao.GetPeopleByName(searchString, sortOrder, 10, (int)page);

            return View(people);
        }
}
And the Unity section of my web.config looks like this:
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <namespace name="RebuildingModel.Dao" />
    <namespace name="RebuildingModel.Dao.Impl" />
    <namespace name="RebuildingSite.Controllers" />
    
    <assembly name="RebuildingModel" />
    <assembly name="RebuildingSite" />
    
    <container>
      <register type="PersonDao" mapTo="PersonDaoImpl" />
      <register type="PersonController" mapTo="PersonController" />
    </container>
  </unity>
My PersonDaoImpl does implement PersonDao:

PersonDao:
namespace RebuildingModel.Dao
{
    public interface PersonDao : StandardDaoInterface<int, Person>
    {
        /// <summary>
        /// Search for a person by first or last name, sorting and sizing the resultant list as appropriate.
        /// </summary>
        /// <param name="name">Any search string that would be contained in the first or last name.</param>
        /// <param name="sort">The Person field on which to sort</param>
        /// <param name="pageSize">The size of the page</param>
        /// <param name="pageNumber">What page number is being returned</param>
        /// <returns>A list of people with a first or last name containing "name", sorted by "sort", 
        /// on "pageNumber" page number, with no more than "pageSize" people returned.</returns>
        IPagedList<Person> GetPeopleByName(string name, string sortOrder, int pageSize, int pageNumber);
    }
}
PersonDaoImpl:
namespace RebuildingModel.Dao.Impl
{
    public class PersonDaoImpl : PersonDao
    {
        private static readonly LogWriter log = LoggingFactory.GetLogWriter();

        public PersonDaoImpl()
        {
        }

        public PagedList.IPagedList<Person> GetPeopleByName(string name, string sortOrder, int pageSize, int pageNumber)
        {
            log.Write("Searching for person name containing " + name + " sorting by " + sortOrder +
                      " page size " + pageSize + ", page number " + pageNumber);

            using (var db = new RebuildingTogetherEntities())
            {
                var people = from p in db.People
                             select p;

                if (!String.IsNullOrEmpty(name))
                {
                    people = people.Where( p => p.LastName.ToUpper().Contains(name) ||
                                                p.FirstName.ToUpper().Contains(name) );
                }

                switch (sortOrder)
                {
                    case "Name desc":
                        people = people.OrderByDescending(p => p.LastName);
                        break;
                    case "City desc":
                        people = people.OrderByDescending(p => p.City);
                        break;
                    case "City":
                        people = people.OrderBy(p => p.City);
                        break;
                    default:
                        people = people.OrderBy(p => p.LastName);
                        break;
                }

                return people.ToPagedList(pageNumber, pageSize);
            }
        }
}
But, when I start the app, I get this error:
6/16/2013 3:02:07 PM|System.InvalidOperationException: An error occurred when trying to create a controller of type 'RebuildingSite.Controllers.PersonController'. Make sure that the controller has a parameterless public constructor. ---> Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the dependency failed, type = "RebuildingSite.Controllers.PersonController", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type PersonDao does not have an accessible constructor.
-----------------------------------------------
At the time of the exception, the container was:

  Resolving RebuildingSite.Controllers.PersonController,(none)
  Resolving value for property PersonController.ThePersonDao
    Resolving RebuildingModel.Dao.PersonDao,(none)
 ---> System.InvalidOperationException: The type PersonDao does not have an accessible constructor.
   at Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForNullExistingObject(IBuilderContext context)
   at lambda_method(Closure , IBuilderContext )
   at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)
   at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)
...
How do I inject an implementation of PersonDao rather than a concrete class like PersonDaoImpl?

Thanks!
Jun 17, 2013 at 6:01 AM
Did you uncomment the line in the RegisterType method of the App_Start/UnityConfig.cs file to load the configuration?
        /// <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();

            // TODO: Register your types here
            // container.RegisterType<IProductRepository, ProductRepository>();
        }

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jun 17, 2013 at 1:06 PM
I'm actually loading the configuration in another method; I didn't realize that UnityConfig did that for me. Still, I am loading the configuration. I have no problem injecting concrete classes (PersonDaoImpl); I only have problems if I try to inject a concrete implementation of an interface (PersonDaoImpl for a PersonDao).

Thanks...
Jun 17, 2013 at 1:41 PM
Your code and configuration looks OK. I can inject a PersonDao interface into my controller.

Can you post a small sample project?

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jun 18, 2013 at 10:44 PM
Nevermind, it worked when I used the UnityConfig.RegisterTypes() call rather than my code. I guess that class does a better job at registering the container. Thanks!