ASP.NET MVC 3依赖注入-控制器、视图和操作筛选器

人气:193 发布:2022-10-16 标签: dependency-injection asp.net-mvc-3 unity-container

问题描述

我正在尝试使用Microsoft Unity在ASP.NETMVC3应用程序中使用依赖项注入。首先,我实现了自己的IDependencyResolver,并在Global.asax文件中激活了它,如下所示:

DependencyResolver.SetResolver(new UnityDependencyResolver(container));

我发现我不需要做任何其他事情就可以让控制器注入(通过构造函数和[Dependency]属性)工作。使用默认的视图引擎,我还发现我可以让[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);
}

使用注释掉的行,我完全失去了视图中的依赖注入,所以我将其更改为上面的行,它同样适用于标准视图,但不适用于布局视图。如果您能告诉我如何将上面的内容修改为同样适用于布局视图,我将不胜感激?

最后,我正在尝试让操作过滤器注入也能正常工作。我发现了两个不同的案例:

通过属性将筛选器应用于操作。

将其定义为全局筛选器,例如:

GlobalFilters.Filters.Add(new 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>());

此操作现在再次起作用,但这是正确的操作方法吗?

我会很感激你的帮助。谢谢

推荐答案

我上次问这个问题已经有一段时间了,但我想我应该分享一下我最终做了什么。

在我不能使用构造函数或属性注入的情况下,我使用DependencyResolver(服务定位器模式)解决了它。例如,如果我需要服务IService,我只需按如下方式注入它:

public IService Service => DependencyResolver.Current.GetService<IService>();

虽然有些人可能认为这是一种反模式,但我发现它运行得很好,问题较少,而且有了C#中的新进步,我认为它看起来还不错。

但是,如果您使用的是ASP.NET Core,则永远不必使用服务定位器模式,因为它已通过依赖项注入进行了重新构建。

427