【问题标题】:Ninject + ASP.NET Web Forms Not WorkingNinject + ASP.NET Web 表单不工作
【发布时间】:2011-11-20 10:23:02
【问题描述】:

我已经在一个 MVC3 应用程序中成功实现了 Ninject,但是在使用 ASP.NET Web 窗体做同样的事情时遇到了一些麻烦。每次尝试访问业务层中的注入属性时,我都会得到空引用。在 CreateKernel 方法以及 ServiceLocator 类中的几个地方设置断点后,看起来它们都没有被命中,所以它甚至没有加载。

我确定我只是在处理这个错误,但是在 Web 表单应用程序中连接 Ninject 的文档或信息很少。

基本上这是我目前所拥有的:

背后的代码

public class ReviewManager
    {
        [Inject] private IReviewRepository _reviewRepository { get; set; }

        public ReviewManager() { }

        public ReviewManager(IReviewRepository reviewRepository)
        {
            _reviewRepository = reviewRepository;
        }

        public Review GetById(int id)
        {
            if (id <= 0) throw new ArgumentException("ID must be greater than zero");

            **I get a null reference exception on the next line. _reviewRepository is null**
            return _reviewRepository.GetById(id);
        }
}

global.asax.cs

public class Global : NinjectHttpApplication
{
    protected override IKernel CreateKernel()
    {
        return ServiceLocator.Kernel;
    }

    // deleted for brevity
}

ServiceLocator.cs(为简洁而编辑,相关部分在这里)

public static class ServiceLocator
    {
        public static IKernel Kernel { get; set; }

        public static ILogger Logger { get; set; }

        static ServiceLocator()
        {
            Kernel = new StandardKernel(new INinjectModule[] {
                new LoggerBindings(),
                new DataBindings()
            });

            if (Logger == null)
                Logger = Kernel.Get<ILogger>();
        }
}
public class LoggerBindings : NinjectModule
    {
        public override void Load()
        {
            Bind<ILogger>().To<NLogLogger>();
        }
    }

    public class DataBindings : NinjectModule
    {
        public override void Load()
        {
            Bind<IReviewRepository>().To<ReviewRepository>();
        } 
    }

【问题讨论】:

  • 这里的关键问题是:谁在实例化 ReviewManager??
  • 它是从任何 ASP.NET 代码隐藏中实例化的。
  • 使用您的 ServiceLocator 还是使用新的 ReviewManager?
  • 这就是它没有被注入的原因。如果您只是执行 new ReviewManager(),则无需注入其依赖项。您需要使用 ServiceLocator 来创建 ReviewManager...或者如果您希望它自动发生,请创建一个自定义处理程序工厂,如下所示 stackoverflow.com/questions/589374/…
  • 那么这个属性的 [Inject] 属性的作用是什么: [Inject] private IReviewRepository _reviewRepository { get;放; }?在我看来,这应该向 Ninject 表明我希望它解决具体的实现......

标签: c# dependency-injection webforms inversion-of-control ninject


【解决方案1】:

通过 WebForms 的 ASP.Net 不允许您管理所有对象实例的生命周期(就像 MVC 一样)。例如,框架实例化页面对象。这意味着您可能无法以与在 MVC/WPF/Silverlight 中完全相同的方式实现 DI(WinForms IIRC 中存在相同的问题)。您可能必须直接在每个代码背后启动依赖关系图。

翻译:您需要在页面加载时调用ServiceLocator.Kernel.Get&lt;IReviewRepository&gt;(或作为属性上的惰性初始化)。

【讨论】:

  • 谢谢,这确实有效。我已经看到一些关于如何模拟与 MVC 相同类型的生命周期管理的帖子,所以我将保持这个线程开放,但如果几天内没有其他解决方案可以说明这一点,我'将此标记为答案。
【解决方案2】:

MVC 最酷的地方在于它可以在同一个应用程序中同时运行 ASP.NET WebForm 页面。在我看来,扩展 ASP.NET WebForms 网站的最佳方式是使用 MVC3 创建新页面,并重构每个需要对 MVC3 进行重大更改的页面。

如果没有选择,请使用 Ninject.Web 扩展。它包含一个 IHttpModule,该属性在初始化后注入所有网页和控件。这样,您就可以将服务注入属性,它们也由 Ninject 创建。

【讨论】:

  • 我完全同意 MVC 是更好的选择,但我正在尝试对现有的 Web 表单应用程序进行一些架构更改。我去看看 Ninject.Web。
【解决方案3】:

一种潜在的解决方法,通过如下更改 DataBindings 类:

 public class DataBindings : NinjectModule 
    { 
        public override void Load() 
        { 
            Bind<IReviewRepository>().To<ReviewRepository>(); 
            Bind<ReviewManager>().ToSelf();
        }  
    } 

在你的调用者中,而不是

var rm = new ReviewManager();

尝试使用

var rm = ServiceLocator.Kernel.Get<ReviewManager>();

我没有测试过这段代码,但我认为它会解决你的空引用问题。

【讨论】:

    【解决方案4】:

    我对页面、母版页和用户控件使用属性注入。例如,我的所有页面都继承自一个基类,该基类使用以下代码覆盖 RequestActivation 方法:

        ''' <summary>
        ''' Asks the kernel to inject this instance.
        ''' </summary>
        Protected Overridable Sub RequestActivation()
            ServiceLocator.Kernel.Inject(Me)
        End Sub
    

    并且在每个页面中我都声明了可注入属性:

        <Inject()>
        Property repo As IMyRepository
    

    【讨论】:

      猜你喜欢
      • 2013-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多