2009-08-20 3 views
10

Я пытаюсь использовать контейнер Unity, чтобы упростить модульное тестирование моих контроллеров. Мой контроллер использует конструктор, который принимает интерфейс к репозиторию. В файле global.asax я создаю экземпляр UnityContainerFactory и регистрирую его с помощью структуры MVC, а затем регистрирую репозиторий и его реализацию. Я добавил атрибут [Dependency] в параметр контроллера CTOR Repository. Все это работает нормально, за исключением того, что иногда GetControllerInstance (Type controllerType) фабрики вызывается более одного раза и передается пустым аргументом в качестве типа controllerType.ASP.NET MVC и Unity 1.2 Вопрос контейнера

Первый звонок на завод правилен, и контроллер «ProductsController» передается в качестве аргумента. Но иногда фабрика называется еще пару раз после того, как представление было отображено с нулевым значением для контроллера, и я не уверен, почему. Когда передается правильное значение типа контроллера, что «Call Stack» имеет смысл для меня, но когда передается значение null, я не уверен, почему или кто делает вызов. Есть идеи?

Ниже приведены коды и стеки вызовов для примера.

Стек вызовов при работает

test.dll! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (System.Type controllerType = {Name = "ProductsController" FullName = "Test.Controllers.ProductsController"}) Строка 23 C# test.dll! Test._Default.Page_Load (объект отправитель = {ASP.default_aspx}, System.EventArgs е = {System.EventArgs}) Строка 18 + 0x1a байт C#

Call Stack, когда NULL передается в controllerType

Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (Syst em.Type controllerType = нуль) Строка 27 C#

Сначала я создал UnityControllerFactory

public class UnityControllerFactory : DefaultControllerFactory 
{ 
    UnityContainer container; 

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

    protected override IController GetControllerInstance(Type controllerType) 
    { 
     if (controllerType != null) 
     { 
      return container.Resolve(controllerType) as IController; 
     } 
     else 
     { 
      return null; // I never expect to get here, but I do sometimes, the callstack does not show the caller 
     } 
    } 
} 

Далее я добавил следующий код в файл global.asax для создания экземпляра контейнера автокрепеж

protected void Application_Start() 
    { 
     RegisterRoutes(RouteTable.Routes); 

     // Create Unity Container if needed 
     if (_container == null) 
     { 
      _container = new UnityContainer(); 
     } 

     // Instantiate a new factory 
     IControllerFactory unityControllerFactory = new UnityControllerFactory(_container); 

     // Register it with the MVC framework 
     ControllerBuilder.Current.SetControllerFactory(unityControllerFactory); 

     // Register the SqlProductRepository 
     _container.RegisterType<IProductsRepository, SqlProductRepository> 
      (new ContainerControlledLifetimeManager()); 
    } 

Приложение имеет один контроллер

public class ProductsController : Controller 
{ 
    public IProductsRepository productsRepository; 

    public ProductsController([Dependency]IProductsRepository productsRepository) 
    { 
     this.productsRepository = productsRepository; 
    } 
} 
+0

Вы на 100% уверены, что эта строка не возвращает null: return container.Resolve (controllerType) в качестве IController; Это кажется маловероятным, но этот приведение может легко вернуть значение null, если результирующий тип не был вызван IController или вызов Resolve. –

+0

Привет Андерсон. Как вы можете видеть из стека вызовов, передается значение null. Я также остановился на линии, используя отладчик, и он был нулевым до начала трансляции. Этот вызов является единственной функцией в стеке в то время. Который я также не понимаю. Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (System.Type controllerType = null) Строка 27 C# – Rick

+0

Это то, что, как я думал, я видел в вашем стеке, но я хотел проверить свои предположения, чтобы убедиться. –

ответ

9

Это, вероятно, связано с некоторым файлом t ype не сопоставляется с контроллером на ваших маршрутах. (изображения, например). Это будет происходить чаще, когда вы отлаживаете локально с помощью Cassini в моем опыте, поскольку Cassini разрешает все запросы на маршрутизацию через ASP.NET, в то время как в IIS многие запросы обрабатываются IIS для вас. Это также было бы причиной того, что вы не видите свой код в стеке для этого запроса. Если вы отключите опцию «Только мой код» в Visual Studio, вы можете иногда лучше понять это.

Это не единственная причина, по которой это может произойти, но это распространено.

Соответствующая вещь должна состоять в том, чтобы позволить базовому методу обрабатывать запрос в этих ситуациях. Обычно это простой запрос на файл и не должен влиять на вас.

Простейшая вещь сделать бы к воротам так:

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

Это должно сделать это.

Для просмотра того, что требуется для запроса, вы можете проверить HttpContext.Current.Request, чтобы узнать, какой файл отсутствует в вашем маршруте. Много раз это не то, что вам нужно контролировать, но это заставит вас чувствовать себя лучше, чтобы узнать, что такое происхождение запроса.

+0

Спасибо за ответ и советы ..... – Rick

+2

Я принял ваше предложение и посмотрел на HttpContext.Current.Request и заметил, что искал favicon.ico. Это объясняет, почему это срабатывало иногда, а не другие. Когда существующий экземпляр браузера был открыт, он не пытался найти favicon.ico. – Rick

+0

Эй, хорошо знать и рад, что я мог бы помочь. –

Смежные вопросы