如何在asp.net Web窗体上实现Ninject或DI?


Answers:


79

以下是将Ninject与WebForms结合使用的步骤。

步骤1-下载

需要进行两次下载-Ninject-2.0.0.0-release-net-3.5和WebForm扩展Ninject.Web_1.0.0.0_With.log4net(有NLog替代方法)。

Web应用程序中需要引用以下文件:Ninject.dll,Ninject.Web.dll,Ninject.Extensions.Logging.dll和Ninject.Extensions.Logging.Log4net.dll。

第2步-Global.asax

Global类需要派生自Ninject.Web.NinjectHttpApplication并实现CreateKernel(),这将创建容器:

using Ninject; using Ninject.Web;

namespace Company.Web {
    public class Global : NinjectHttpApplication


        protected override IKernel CreateKernel()
        {
            IKernel kernel = new StandardKernel(new YourWebModule());
            return kernel;
        }

StandardKernel构造需要Module

步骤3-模组

在这种情况下YourWebModule,模块定义了Web应用程序所需的所有绑定:

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public class YourWebModule : Ninject.Modules.NinjectModule
    {

        public override void Load()
        {
            Bind<ICustomerRepository>().To<CustomerRepository>();
        }   

在此示例中,无论在何处ICustomerRepository引用接口,都CustomerRepository将使用具体的接口。

第4步-页面

完成后,每个页面都需要继承自Ninject.Web.PageBase

  using Ninject;
    using Ninject.Web;
    namespace Company.Web
    {
        public partial class Default : PageBase
        {
            [Inject]
            public ICustomerRepository CustomerRepo { get; set; }

            protected void Page_Load(object sender, EventArgs e)
            {
                Customer customer = CustomerRepo.GetCustomerFor(int customerID);
            }

InjectAttribute -[Inject]-告诉Ninject注入ICustomerRepository到CustomerRepo属性。

如果您已经有了基本页面,则只需获取基本页面即可从Ninject.Web.PageBase派生。

步骤5-母版页

不可避免地,您将拥有母版页,并且要允许母版页访问注入的对象,您需要从Ninject.Web.MasterPageBase以下对象派生母版页:

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public partial class Site : MasterPageBase
    {

        #region Properties

        [Inject]
        public IInventoryRepository InventoryRepo { get; set; }     

步骤6-静态Web服务方法

下一个问题是无法注入静态方法。我们有一些Ajax PageMethods,它们显然是静态的,因此我不得不将这些方法移到标准的Web服务中。同样,Web服务需要派生自Ninject类- Ninject.Web.WebServiceBase

using Ninject;
using Ninject.Web;    
namespace Company.Web.Services
{

    [WebService(Namespace = "//tempuri.org/">http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]    
    [System.Web.Script.Services.ScriptService]
    public class YourWebService : WebServiceBase
    {

        #region Properties

        [Inject]
        public ICountbackRepository CountbackRepo { get; set; }

        #endregion

        [WebMethod]
        public Productivity GetProductivity(int userID)
        {
            CountbackService _countbackService =
                new CountbackService(CountbackRepo, ListRepo, LoggerRepo);

在JavaScript中,您需要引用标准服务- Company.Web.Services.YourWebService.GetProductivity(user, onSuccess),而不是PageMethods.GetProductivity(user, onSuccess)

我发现的唯一另一个问题是将对象注入到用户控件中。虽然可以使用Ninject功能创建自己的基本UserControl,但我发现可以更快地将属性添加到所需对象的用户控件中,并在容器页面中设置属性。我认为开箱即用地支持UserControls在Ninject的“待办事项”列表中。

添加Ninject非常简单,这是一种雄辩的IoC解决方案。许多人喜欢它,因为没有Xml配置。它还有其他有用的“技巧”,例如仅使用Ninject语法-将对象变成Singleton Bind<ILogger>().To<WebLogger>().InSingletonScope()。我喜欢将WebLogger更改为实际的Singleton实现。


1
这可以解决问题,但是我在新的WebForms应用程序(从模板)上进行了尝试,发现当Global.asax.cs文件具有(例如Application_Start)中的默认会话方法时,该应用程序返回了一个神秘的错误。很明显,您需要删除它们(因为它们是在NinjectHttpApplication中实现的),但它使我感到困惑。
马特

很高兴这很有帮助。错误听起来很奇怪,异常是什么?我在Application_Start中有代码,并且工作正常。
Joe Ratzer 2011年

3
我只是忘了从Global.asax.cs文件的Application_Start方法调用超类型的方法NinjectHttpApplication.Application_Start。我这样做的时候就可以了,否则就坏了。
马特

1
绝对,我正在使用的应用程序现在有一个基础页(总是一个好主意),只需获取基础页即可实现PageBase。
乔·拉特泽

2
现在看来这已经过时了。NuGet软件包ninject.web包含一些用于引导应用程序的代码,因此需要直接从NinjectHttpApplication继承吗?
RyanW '04 -4-2

68

Ninject v3.0的发布(截至2012年4月12日)变得更加容易。注入是通过HttpModule实现的,因此无需从自定义Page / MasterPage继承您的页面。以下是快速执行操作的步骤(和代码)。

  1. 创建一个新的ASP.NET WebForms项目
  2. 使用NuGet添加Ninject.Web库(也将关闭Ninject.Web.Common和Ninject库)
  3. 在App_Start / NinjectWebCommon.cs / RegisterServices方法中注册自定义绑定
  4. 在页面上使用属性注入

NinjectWebCommon / RegisterServices

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IAmAModel>().To<Model1>();
    } 

默认

public partial class _Default : System.Web.UI.Page
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
    }
}

网站主

public partial class SiteMaster : System.Web.UI.MasterPage
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("From master: " 
            + Model.ExecuteOperation());
    }
}

楷模

public interface IAmAModel
{
    string ExecuteOperation();         
}

public class Model1 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 1";
    }
}

public class Model2 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 2";
    }
}

输出窗口的结果

I am a model 1
From master: I am a model 1

嗨,Jason,您好...我正在尝试实现该方法...从NuGet中获得了Ninject.Web库。它在App_Start上创建了Bootstrapper ...我试图在RegisterServices上添加一个断点来进行调试,但从未实现...我是否要添加其他内容?
保罗

1
@Paul您可以将Debugger.Break()放入RegisterServices方法中以开始调试。
Boggin 2012年

5
嗨杰森。我很难让它正常工作,所以我想知道这是否是完整的清单?我可以看到NinjectHttpModule是在运行时加载的,但是没有注入。您能以任何理由想到这种情况吗?
rusmus 2013年

3
很好的例子谢谢它在页面/母版页上有效,但在Asmx上不可用。我如何使其在Asmx上工作?谢谢。
lawphotog 2014年

1
@mreyeros确保您有NinjectWeb.csin App_Start。您初始化Ninject的代码必须放在此文件中。如果在单独的文件中(例如NinjectWebCommon.cs,它将不起作用)。如果您晚于其他使用NuGet的Ninject软件包安装Ninject.Web,则会发生这种情况。
nebffa 2014年

12

由于存在打开的bug,此处的答案当前不起作用。这是@Jason步骤的修改版本,该步骤使用客户的httpmodule注入到页面和控件中,而无需继承ninject类。

  1. 创建一个新的ASP.NET WebForms项目
  2. 使用NuGet添加Ninject.Web库
  3. 在App_Start / NinjectWebCommon.cs / RegisterServices方法中注册自定义绑定
  4. 添加InjectPageModule并在NinjectWebCommon中注册
  5. 在页面上使用属性注入

InjectPageModule.cs

 public class InjectPageModule : DisposableObject, IHttpModule
{
    public InjectPageModule(Func<IKernel> lazyKernel)
    {
        this.lazyKernel = lazyKernel;
    }

    public void Init(HttpApplication context)
    {
        this.lazyKernel().Inject(context);
        context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
    }

    private void OnPreRequestHandlerExecute(object sender, EventArgs e)
    {
        var currentPage = HttpContext.Current.Handler as Page;
        if (currentPage != null)
        {
            currentPage.InitComplete += OnPageInitComplete;
        }
    }

    private void OnPageInitComplete(object sender, EventArgs e)
    {
        var currentPage = (Page)sender;
        this.lazyKernel().Inject(currentPage);
        this.lazyKernel().Inject(currentPage.Master);
        foreach (Control c in GetControlTree(currentPage))
        {
            this.lazyKernel().Inject(c);
        }

    }

    private IEnumerable<Control> GetControlTree(Control root)
    {
        foreach (Control child in root.Controls)
        {
            yield return child;
            foreach (Control c in GetControlTree(child))
            {
                yield return c;
            }
        }
    }

    private readonly Func<IKernel> lazyKernel;
}

NinjectWebCommon / RegisterServices

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IHttpModule>().To<InjectPageModule>();
        kernel.Bind<IAmAModel>().To<Model1>();

    } 

默认

public partial class _Default : System.Web.UI.Page
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
    }
}

网站主

public partial class SiteMaster : System.Web.UI.MasterPage
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("From master: " 
            + Model.ExecuteOperation());
    }
}

楷模

public interface IAmAModel
{
    string ExecuteOperation();         
}

public class Model1 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 1";
    }
}

public class Model2 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 2";
    }
}

输出窗口的结果

I am a model 1
From master: I am a model 1

4
请注意,对于没有母版页的页面,此操作将失败。我用以下方法修改了NinjectWebCommon: if (currentPage.Master!=null) { this.lazyKernel().Inject(currentPage.Master); }
H.Wolper 2015年

1
感谢您抽出宝贵的时间对此进行记录。使用旧版Webforms项目时,我遇到了同样的问题。多亏了您进行了这种排序-调整后的矿井也可以在Page_Init之前工作,因为它被调用为时已晚,但在其他方面还是完美的。谢谢@亚当!
PoorbandTony

这个解决方案给我造成了一些真正的随机问题。例如对于OnCommand事件停止在转发器中的LinkBut​​tons上运行。但是它并没有破坏所有的代码隐藏事件。
Mike Cole,

8

我认为这是在ASP.NET Web窗体上实现Ninject.Web的步骤。

  1. 在Global.asax上实现NinjectHttpApplication。对于内核,请通过实现NinjectModule将其传递。
  2. 在每个Web表单页面加载事件的后面代码中,实现Ninject.Web.PageBase。在其顶部添加带有[Inject]过滤器的实例类。

对于更详细的示例,下面是我找到的一些有用的链接:

1. http://joeandcode.net/post/Ninject-2-with-WebForms-35

2. http://davidhayden.com/blog/dave/archive/2008/06/20/NinjectDependencyInjectionASPNETWebPagesSample.aspx


1
假设您已经添加了Ninject.Web扩展名,这正是您需要做的。
戴夫·蒂本

7
@nellbryant这两个链接现在都已失效。
Boggin 2012年

joeandcode.net链接现在已死。存档版本在这里:web.archive.org/web/20160324142135/http
克里斯·沃尔什

4

看看Ninject.Web扩展。它提供了基础架构 https://github.com/ninject/ninject.web


5
我知道我应该以身作则,但是自述文件应该> 0个字节!
Ruben Bartelink

@Ruben:我同意更新文档是列表atm上的重要任务之一。
Remo Gloor

2
这与优先级以及社区提供多少帮助有关。在过去的一年中增加了很多文档。不适合Ninject.Web,因为我认为它不如其他功能重要,因为:a)WebForms已过时-使用MVC代替b)我没有编写此扩展。像其他所有人一样,我必须从代​​码中获得有关此扩展的知识。c)我自己不使用它-有其他人可以比我自己写更好的文档。但是似乎对他们中的任何一个都不重要。我的业余时间像您一样有限,因此我无能为力。
Remo Gloor'4

6
@RyanW仅由于缺少文档而拒绝投票不会真正增加我的动力或增加为您编写此文档的优先级!
Remo Gloor 2012年

1
@RyanW您从哪里得到您的想法?我对一年前发表的nar昧言论感到难过,但a)伴随有up悔b)讽刺但不抱怨。请驳斥Remo优先提出的完全合法的观点,而不是扔掉玩具。顺便说一句,我敢肯定Unity有很棒的文档,并且可能在您的胡同中。并查看nellbryant或Jor R的答案,并尝试查找与此有关的问题或使用它自己编写自述文件或示例。
Ruben Bartelink '04年

0

查看Steve Sanderson(Apress)的书“ Pro ASP.NET MVC 2 Framework,第二版”。作者使用Ninject连接数据库。我认为您可以使用这些示例并使其适合您的需求。


是的,我有那个促使我提出这个问题的。如果Web应用程序是Web表单,如何完成?
nellbryant

这也是我通常在WebForms中使用它的方式。诀窍是您需要使用内核的Get方法。
Didaxis 2011年

0
public IGoalsService_CRUD _context { get; set; }

_context对象被设置为null。以下是其余设置

public partial class CreateGoal : Page
{
    [Inject]
    public IGoalsService_CRUD _context { get; set; }
}

对于全局文件

protected override IKernel CreateKernel()
{
    IKernel kernel = new StandardKernel(new Bindings());
    return kernel;
}

public class Bindings : NinjectModule
{
    public override void Load()
    {
        Bind<goalsetterEntities>().To<goalsetterEntities>();
        Bind<IGoalsService_CRUD>().To<GoalsService_CRUD>();
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.