2012-06-12 2 views
7

Я пытаюсь реализовать Dependency injection в моем приложении MVC. Я использую Unity.Mvc3.dll для IoC. Мне просто интересно, как Unity не может регистрировать типы из другой сборки. Вот код:Единство: не удается зарегистрировать тип из другой сборки

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

    RegisterGlobalFilters(GlobalFilters.Filters); 
    RegisterRoutes(RouteTable.Routes); 

    var container = new UnityContainer(); 

    // ok: register type from this assembly 
    container.RegisterType<IMessages, Messages>(); 

    // fail: register type from another assembly (service reference) 
    container.RegisterType<IPlayerService, PlayerService>(); 

    DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 
} 

public class UnityDependencyResolver : IDependencyResolver 
{ 
    private readonly IUnityContainer _container; 

    public UnityDependencyResolver(IUnityContainer container) 
    { 
     this._container = container; 
    } 

    public object GetService(Type serviceType) 
    { 
     try 
     { 
      return _container.Resolve(serviceType); 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     try 
     { 
      return _container.ResolveAll(serviceType); 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 
} 

Использование в контроллере MVC:

[Dependency] 
public IPlayerService PlayerService { get; set; } 

[Dependency] 
public IMessages Messages { get; set; } 


public ActionResult Index() 
{ 
    PlayerMessageViewModel vm = new PlayerMessageViewModel(); 
    vm.Messages = Messages; // success! 
    vm.Players = PlayerService.Get(); // fail: null reference exception :PlayerService 

    return View(vm); 
} 

PlayerService всегда нуль в то время как сообщения в порядке.

Вот PlayerService Класс

public class PlayerService : IPlayerService 
{ 
    private readonly MyDbEntities _dbContext; 

    public PlayerService() 
    { 
     _dbContext = new MyDbEntities(); 
    } 

    public PlayerService(MyDbEntities dbContext) 
    { 
     _dbContext = dbContext; 
    } 


    public IQueryable<Player> Get() 
    { 
     return _dbContext.Players.AsQueryable(); 
    } 
} 

это полное сообщение об ошибке

Постановление зависимости не удалось, тип = "System.Web.Mvc.IControllerFactory", имя = «(никто)".
Исключение произошло во время: при разрешении.
Исключение: InvalidOperationException - текущий тип, System.Web.Mvc.IControllerFactory, является интерфейсом и не может быть сконструирован. Вам не хватает картографирования типов?

ответ

6

единства по умолчанию выбирает конструктор с наибольшим количеством параметров, так что я думаю, что он будет пытаться использовать второй конструктор Wi th параметр dbContext, который он не может решить. Если вы помечаете свой конструктор по умолчанию атрибутом [InjectionConstructor], то, надеюсь, это решит вашу проблему.

+0

будет делать, спасибо – lincx

+0

какой атрибут библиотеки InjectionConstructor включен? – lincx

+0

http://msdn.microsoft.com/en-us/library/microsoft.practices.unity.injectionconstructorattribute(v=pandp.20).aspx –

7

Вы скрываете все исключения с помощью catch { return null; }, попробуйте удалить его и посмотреть, какое исключение выбрано при разрешении. Я думаю, что исключение выбрано в конструкторе PlayerService.

РЕДАКТИРОВАТЬ:

От http://mvchosting.asphostcentral.com/post/ASPNET-MVC-3-Hosting-Problem-in-implementing-IControllerActivator-in-ASPNET-MVC-3.aspx

Когда приложение MVC запускается в первый раз, зависимость распознаватель вызывается со следующими типами в следующем порядке:

  • IControllerFactory
  • IControllerActivator
  • HomeController

Если вы не реализовали свой распознаватель вернуть нулевое значение, если тип не зарегистрирован, то вы, вероятно, в конечном итоге увидеть ошибку, подобную:

текущий тип, System.Web .Mvc.IControllerFactory, является интерфейсом и не может быть построены

+0

он должен ударить право на CTOR по умолчанию? Я не могу заставить отладчик перейти к точке останова в ctor. – lincx

+0

Yep, 'public PlayerService()' –

+0

Я удаляю исключение null и replace throw, и это то, что я получаю 'текущий тип, System.Web.Mvc.IControllerFactory, является интерфейсом и не может быть сконструирован. Вам не хватает сопоставления типов? ' – lincx

2

Вы нарушаете авторские права IDependencyResolver. Он должен возвращать null для типов, которые не могут быть разрешены. Проблема с Unity заключается в том, что он пытается построить все классы, которые он может найти, независимо от того, зарегистрированы они в контейнере или нет.

Следовательно, класс не может быть построен.

Существует также Unity.Mvc3 пакета, доступные в nuget.

+0

Вы говорите, что вокруг этого нет никакой работы? – lincx

+0

это на самом деле первоначально возвращает null, но я просто заменяю исключение throe, чтобы увидеть фактическую ошибку, как это было предложено другим плакатом. – lincx

+1

Ваш «бросок» скрывает проблему, которую вы получили с самого начала, так как «IControllerActivator» вызывается перед вызовом любого контроллера. Измените назад, чтобы вернуть null и LOG все исключения (или поместить точку останова в блок catch). – jgauffin

0

Текущий тип, (EX-DI.IBLL.IEmployee), является интерфейсом и не может быть сконструирован. Вам не хватает картографирования типов?

Ans - Просто в Unity.config.cs добавить следующее Thye

public static class UnityConfig 
    { 
     public static void RegisterComponents() 
     { 
      var container = new UnityContainer(); 

      // register all your components with the container here 
      // it is NOT necessary to register your controllers 

      **container.RegisterType<IEmployee,EmployeeManager>();** 
//this could be your interface and the class implementing the interface. 

      DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 
     } 
    } 
Смежные вопросы