使用Autofac将属性注入到自定义WebViewPage中 [英] Property injection into custom WebViewPage using Autofac

查看:75
本文介绍了使用Autofac将属性注入到自定义WebViewPage中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个内部应用程序框架,我们组织中的其他开发团队将使用该框架来构建MVC应用程序.作为其中的一部分,我将为所有视图创建菜单结构,该菜单结构是从配置中读取并根据当前用户的权限进行修改的.为了将菜单创建为框架的一部分,我使用自定义HTML Helper类创建了一个自定义WebViewPage实现,该类需要依赖ApplicationDataReader来构建菜单.

I'm creating an internal application framework that other dev teams in our organisation will use to build MVC applications from. As part of that, I'm creating the menu structure for all views, that is read from configuration and modified based on the current user's permissions. To create the menu as part of the framework, I've created a custom WebViewPage implementation with a custom HTML Helper class that needs to take a dependency on an ApplicationDataReader to construct the menu.

我已经阅读了许多说明MVC需要WebViewPage来拥有无参数构造函数的文章,所以我需要使用属性注入.我已经配置了 Autofac MVC3集成,包括注册了ViewRegistrationSource.麻烦的是,当访问依赖属性时,它始终为null.

I've read various posts that explain that MVC needs the WebViewPage to have a paramterless constructor, so I would need to use property injection. I've configured Autofac MVC3 Integration, including registering a ViewRegistrationSource. Trouble is, when the dependent property is accessed, it's always null.

这是我要拨打的电话的自定义视图页面和帮助程序:

Here's the custom view page and helper with the call I'm trying to make:

public abstract class OuBaseViewPage<TModel> : WebViewPage<TModel> where TModel : class
{
    public OuHelper<TModel> Ou { get; set; }

    public override void InitHelpers()
    {
        base.InitHelpers();
        Ou = new OuHelper<TModel>(ViewContext, this);
    }
}

public class OuHelper<TModel> where TModel : class
{
    public OuHelper(ViewContext viewContext, IViewDataContainer viewDataContainer)
        : this(viewContext, viewDataContainer, RouteTable.Routes)
    {
    }

    public OuHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
    {
        ViewContext = viewContext;
        ViewData = new ViewDataDictionary<TModel>(viewDataContainer.ViewData);
    }

    public ViewDataDictionary<TModel> ViewData { get; private set; }

    public ViewContext ViewContext { get; private set; }

    public IList<BusinessFocusArea> ReadFocusAreas()
    {
        // this is null - yes, service location, but an isolated instance of...
        return DependencyResolver.Current.GetService<IDataReader>().Read();
    }
}

问题源于以下事实,即在调用Application_Start之前(通过Layout.Execute())调用了InitHelpers,因此没有任何依赖项被注册.我知道,将逻辑注入视图不是很好的做法,并且视图应该只是愚蠢的,但这是一个应用程序框架,它需要执行某些设置步骤,而使用该框架的开发人员必须对此不具有可见性.

The problem stems from the fact that InitHelpers is being called (via Layout.Execute()) BEFORE Application_Start is called, so none of the dependencies have been registered. I know that it's not good practice to inject logic into views and that views should simply be dumb, but this is an application framework and it needs to perform certain setup steps that the developers using the framework mustn't have visibility of.

我可以采用更好的方法吗?

这里有一个类似的问题:可以将Autofac依赖项注入到布局视图中文件?

There's a similar issue here: Can Autofac inject dependencies into layout view files?

推荐答案

问题源于一个事实,即调用InitHelpers(通过 Layout.Execute())在调用Application_Start之前

The problem stems from the fact that InitHelpers is being called (via Layout.Execute()) BEFORE Application_Start is called

我不认为在Application_Start之前会调用某些东西.我无法重现您的问题.

I don't think that something is called before Application_Start. I cannot reproduce your problem.

这是我执行的步骤,效果很好:

Here are the steps I did and which worked perfectly fine:

  1. 使用Internet模板创建新的ASP.NET MVC 3应用程序
  2. 安装Autofac.Mvc3 NuGet
  3. 定义一个虚拟接口:

  1. Create a new ASP.NET MVC 3 application using the Internet Template
  2. Install the Autofac.Mvc3 NuGet
  3. Define a dummy interface:

public interface IDataReader
{

}

  • 还有一个虚拟实现:

  • And a dummy implementation:

    public class DataReader : IDataReader
    {
    
    }
    

  • 定义自定义助手:

  • Define a custom helper:

    public class OuHelper<TModel> where TModel : class
    {
        private readonly IDataReader dataReader;
        public OuHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, IDataReader dataReader)
            : this(viewContext, viewDataContainer, RouteTable.Routes, dataReader)
        {
        }
    
        public OuHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection, IDataReader dataReader)
        {
            ViewContext = viewContext;
            ViewData = new ViewDataDictionary<TModel>(viewDataContainer.ViewData);
            this.dataReader = dataReader;
        }
    
        public ViewDataDictionary<TModel> ViewData { get; private set; }
    
        public ViewContext ViewContext { get; private set; }
    
        public IDataReader DataReader
        {
            get { return this.dataReader; }
        }
    
    }
    

  • 使用此帮助程序定义自定义WebViewPage:

  • Define a custom WebViewPage using this helper:

    public abstract class OuBaseViewPage<TModel> : WebViewPage<TModel> where TModel : class
    {
        public OuHelper<TModel> Ou { get; set; }
    
        public override void InitHelpers()
        {
            base.InitHelpers();
            var dataReader = DependencyResolver.Current.GetService<IDataReader>();
            Ou = new OuHelper<TModel>(ViewContext, this, dataReader);
        }
    }
    

  • ~/Views/web.config中的自定义页面替换默认视图页面:

  • Replace the default view page with the custom one in ~/Views/web.config:

    <pages pageBaseType="MvcApplication1.OuBaseViewPage">
    

  • Application_Start中配置容器:

  • Configure your container in Application_Start:

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    
        var builder = new ContainerBuilder();
        builder.RegisterControllers(typeof(MvcApplication).Assembly);
        builder.RegisterType<DataReader>().As<IDataReader>();
        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }
    

  • 现在,您可以在包括_Layout在内的所有视图中愉快地使用自定义帮助程序,而不会出现任何问题:

  • Now you could happily use the custom helper in all views including the _Layout without any problems:

    @Ou.DataReader.GetType()
    

  • 当然,在此示例中,我只是将IDataReader依赖项公开为公共属性,以向您说明它将始终被注入并且永远不会为null.当然,在您的特定代码中,您只能使用助手内部的私有只读字段来完成您的任务.

    Of course in this example I have just exposed the IDataReader dependency as a public property to illustrate you that it will always be injected and it will never be null. In your particular code you could of course use only the private readonly field inside the helper to achieve your task.

    这篇关于使用Autofac将属性注入到自定义WebViewPage中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆