ASP.NET MVC и Unity 1.2 Вопрос контейнера
Я пытаюсь использовать контейнер Unity, чтобы упростить unit test мои контроллеры. Мой контроллер использует конструктор, который принимает интерфейс к репозиторию. В файле global.asax я создаю экземпляр UnityContainerFactory и регистрирую его с помощью структуры MVC, а затем регистрирую репозиторий и его реализацию. Я добавил атрибут [Dependency] в параметр контроллера CTOR Repository. Кажется, что все это работает нормально, за исключением того, что время от времени factory GetControllerInstance (Type controllerType) вызывается более одного раза и передается пустой аргумент в качестве типа controllerType.
Первый вызов factory корректен, и в качестве аргумента передается тип контроллера ControlController. Но иногда, factory называется еще пару раз после того, как представление было отображено с нулевым значением для контроллера, и я не уверен, почему. Когда передается правильное значение типа контроллера, что "Call Stack" имеет смысл для меня, но когда передается значение null, я не уверен, почему или кто делает вызов. Любые идеи?
Ниже приведены коды и стеки вызовов для этого примера.
Вызов стека при работе
Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance(System.Type controllerType = {Name = "ProductsController" FullName = "Test.Controllers.ProductsController" }) Строка 23 С#
Test.DLL! Test._Default.Page_Load (object sender = {ASP.default_aspx}, System.EventArgs e = {System.EventArgs}) Строка 18 + 0x1a байты С#
Вызов стека, когда NULL передается по типу controller
Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance(System.Type controllerType = null) Строка 27 С#
Сначала я создал 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 для создания экземпляра контейнера factory
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;
}
}
Ответы
Ответ 1
Вероятно, это связано с тем, что некоторый тип файла не сопоставляется с контроллером на ваших маршрутах. (изображения, например). Это будет происходить чаще, когда вы отлаживаете локально с помощью 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, чтобы узнать, какой файл отсутствует в вашем маршруте. Много раз это не то, что вам нужно контролировать, но это заставит вас почувствовать себя лучше, чтобы узнать, что такое происхождение запроса.