2

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

我已经阅读了各种解释 MVC 需要WebViewPage有一个无参数构造函数的帖子,所以我需要使用属性注入。我已经配置了 Autofac MVC3 Integration,包括注册一个ViewRegistrationSource. 麻烦的是,当依赖属性被访问时,它总是空的。

这是我正在尝试拨打的电话的自定义视图页面和助手:

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();
    }
}

问题源于在调用之前InitHelpers(通过Layout.Execute())被调用的事实Application_Start,因此没有任何依赖项被注册。我知道将逻辑注入视图不是一个好习惯,视图应该只是愚蠢的,但这是一个应用程序框架,它需要执行某些使用框架的开发人员不能看到的设置步骤。

我可以遵循更好的方法吗?

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

4

1 回答 1

5

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

我认为之前没有调用过某些东西Application_Start。我无法重现您的问题。

以下是我所做的步骤,并且效果很好:

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

    public interface IDataReader
    {
    
    }
    
  4. 还有一个虚拟实现:

    public class DataReader : IDataReader
    {
    
    }
    
  5. 定义一个自定义助手:

    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; }
        }
    
    }
    
  6. 使用此帮助器定义自定义 WebViewPage:

    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);
        }
    }
    
  7. 将默认视图页面替换为自定义视图页面~/Views/web.config

    <pages pageBaseType="MvcApplication1.OuBaseViewPage">
    
  8. 在以下位置配置您的容器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));
    }
    
  9. 现在您可以愉快地在包括 _Layout 在内的所有视图中使用自定义助手,而不会出现任何问题:

    @Ou.DataReader.GetType()
    

当然,在这个例子中,我只是将IDataReader依赖项作为公共属性公开,以说明它总是被注入并且永远不会为空。在您的特定代码中,您当然可以仅使用助手内的私有只读字段来完成您的任务。

于 2013-02-18T11:15:56.257 回答