Внедрение зависимостей ASP.NET MVC 3 — контроллеры, представления и фильтры действий

Я пытаюсь заставить инъекцию зависимостей работать в приложении ASP.NET MVC 3 с использованием Microsoft Unity. Сначала я реализовал свой собственный IDependencyResolver и активировал его в своем файле Global.asax следующим образом:

DependencyResolver.SetResolver(new UnityDependencyResolver(container));

Я обнаружил, что мне не нужно ничего делать, чтобы заставить работать внедрение контроллера (как через конструктор, так и через атрибут [Dependency]). Я также обнаружил, что с механизмом представления по умолчанию я могу заставить атрибут [Зависимость] работать в стандартных представлениях, но не в представлениях макета. Можно ли заставить это работать и для макетов?

Однако я реализовал свой собственный механизм просмотра, который наследуется от VirtualPathProviderViewEngine, который переопределяет методы CreateView/CreatePartialView и возвращает мое собственное представление (реализует IView). См. метод Render пользовательского представления ниже:

public void Render(ViewContext viewContext, TextWriter writer) {
    var webViewPage = DependencyResolver.Current.GetService(_type) as WebViewPage;
    //var webViewPage = Activator.CreateInstance(_type) as WebViewPage;

    if (webViewPage == null)
        throw new InvalidOperationException("Invalid view type");

    webViewPage.VirtualPath = _virtualPath;
    webViewPage.ViewContext = viewContext;
    webViewPage.ViewData = viewContext.ViewData;
    webViewPage.InitHelpers();

    WebPageRenderingBase startPage = null;

    if (_runViewStartPages)
        startPage = StartPage.GetStartPage(webViewPage, "_ViewStart", _viewStartFileExtensions);

    var pageContext = new WebPageContext(viewContext.HttpContext, webViewPage, null);
    webViewPage.ExecutePageHierarchy(pageContext, writer, startPage);
}

С закомментированной строкой я полностью потерял инъекцию зависимостей в своих представлениях, поэтому я изменил ее на строку выше, которая снова отлично работает для стандартных представлений, но не для представлений макета. Я был бы признателен, если бы вы могли показать мне, как вышеизложенное можно изменить, чтобы оно работало и для представлений макета?

Наконец, я пытаюсь заставить работать инъекцию фильтра действий. Я нашел два разных случая:

  1. Примените фильтр к действию через атрибут.

  2. Определение его как глобального фильтра, например:

    GlobalFilters.Filters.Add(новый TestAttribute());

Похоже, ни один из них не использует преобразователь зависимостей. Поэтому мне нужно сделать дополнительную работу. Пожалуйста, поправьте меня, если есть лучший способ. Чтобы включить первый сценарий, я сделал следующее:

public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider {
    private IUnityContainer _container;

    protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
        var attributes = base.GetControllerAttributes(controllerContext, actionDescriptor);

        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }

    protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
        var attributes = base.GetActionAttributes(controllerContext, actionDescriptor);

        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }
}

А затем определил это в моем файле Global.asax следующим образом:

FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

Это отлично работает, но мне было интересно, правильный ли это способ сделать это? Чтобы решить второй случай, я просто изменил, где я определил свой глобальный фильтр, на следующее:

GlobalFilters.Filters.Add(DependencyResolver.Current.GetService<TestAttribute>());

Теперь это снова работает, но правильно ли это?

Буду признателен за помощь. Спасибо


person nfplee    schedule 30.05.2012    source источник
comment
Похоже, что .Net 4 не предоставляет ASP.NET MVC крючков для внедрения зависимостей в страницы макета. Решение для атрибутов фильтра работает нормально, но вы можете лучше внедрить глобальные зависимости, переопределив метод GetFilters класса FilterAttributeFilterProvider и внедрив зависимости аналогично тому, как это делается в двух других методах.   -  person nfplee    schedule 19.06.2012
comment
Не используйте средство разрешения зависимостей, оно сломано. Придерживайтесь внедрения конструктора.   -  person CrazyCoderz    schedule 06.08.2012
comment
Чтобы ответить на ваш вопрос, это правильный способ сделать это? Я бы так не поступил.   -  person CrazyCoderz    schedule 06.08.2012
comment
Внедрение конструктора не подходит для представлений.   -  person Casey    schedule 25.04.2014