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, чтобы узнать, какой файл отсутствует в вашем маршруте. Много раз это не то, что вам нужно контролировать, но это заставит вас почувствовать себя лучше, чтобы узнать, что такое происхождение запроса.