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

Posted

技术标签:

【中文标题】如何在 asp.net Web 窗体上实现 Ninject 或 DI?【英文标题】:How can I implement Ninject or DI on asp.net Web Forms? 【发布时间】:2011-06-23 10:50:52 【问题描述】:

有很多例子可以让它在 MVC 应用程序上运行。它是如何在 Web 表单上完成的?

【问题讨论】:

【参考方案1】:

以下是将 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 步 - 母版页

不可避免地,您将拥有母版页,并且要允许 MasterPage 访问注入的对象,您需要从 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 语法将对象转换为单例 - Bind&lt;ILogger&gt;().To&lt;WebLogger&gt;().InSingletonScope()。无需将 WebLogger 更改为实际的 Singleton 实现,我喜欢这样。

【讨论】:

这是一种享受,但我在一个新的 WebForms 应用程序(来自模板)上尝试了这个,发现当 Global.asax.cs 文件在(例如 Application_Start)应用程序中具有默认会话方法时返回一个神秘的错误。很明显,您需要删除这些(因为它们是在 NinjectHttpApplication 中实现的),但它抓住了我。 很高兴它有帮助。错误听起来很奇怪,异常是什么?我在 Application_Start 中有代码,它工作正常。 我只是忘了从 Global.asax.cs 文件的 Application_Start 方法中调用超类型的方法 NinjectHttpApplication.Application_Start。当我这样做时有效,否则它会坏掉。 当然,我现在正在处理的应用程序有一个基本页面(总是一个好主意),只需获取基本页面来实现 PageBase。 这似乎已经过时了。 NuGet 包 ninject.web 包含一些用于引导应用程序的代码,使得直接从 NinjectHttpApplication 继承的需要已过时?【参考方案2】:

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

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

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

Site.Master

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调试,但它永远不会到达那里......我想添加别的东西吗? @Paul 可以把 Debugger.Break() 放在 RegisterServices 方法中开始调试。 嗨杰森。我无法让它工作,所以我想知道这是否是完整的纲要?我可以看到 NinjectHttpModule 在运行时加载,但没有发生注入。你能想到什么原因会是这种情况吗? 很好的例子谢谢它适用于页面/母版页,但不适用于 Asmx。我怎样才能让它在 Asmx 上工作?谢谢。 @mreyeros 确保您在App_Start 中有一个NinjectWeb.cs。您初始化 Ninject 的代码必须放在这个文件中。如果它在一个单独的文件中(例如NinjectWebCommon.cs 它将不起作用)。如果您使用 NuGet 安装 Ninject.Web 的时间晚于其他 Ninject 包,则会发生这种情况。【参考方案3】:

The answer here 目前由于open bug 而无法工作。这是 @Jason 步骤的修改版本,使用客户 httpmodule 注入页面和控件,无需从 ninject 类继承。

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

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

Site.Master

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

【讨论】:

请注意,这对于没有母版页的页面会失败。我用这个修改了 NinjectWebCommon:if (currentPage.Master!=null) this.lazyKernel().Inject(currentPage.Master); 感谢您抽出宝贵时间记录此内容。我在使用旧版 webforms 项目时遇到了同样的问题。感谢您对我的排序进行了调整 - 在 Page_Init 之前也进行了调整,因为它被调用得太晚了,但在其他方面都很完美。谢谢@Adam! 这个解决方案给我带来了一些非常随机的问题。例如,OnCommand 事件停止在中继器内的 LinkBut​​tons 上运行。不过,它并没有破坏所有代码隐藏事件。【参考方案4】:

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

    在 Global.asax 中实现 NinjectHttpApplication。对于内核,通过实现 NinjectModule 将其传入。 在代码后面的每个 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

【讨论】:

这假设您已经添加了 Ninject.Web 扩展,这正是您需要做的。 @nellbryant 这两个链接现在都失效了。 joeandcode.net 链接现已失效。存档版本在这里:web.archive.org/web/20160324142135/http://joeandcode.net/post/…【参考方案5】:

查看 Steve Sanderson (Apress) 所著的“Pro ASP.NET MVC 2 Framework, 2nd Edition”一书。作者使用 Ninject 连接数据库。我认为您可以使用这些示例并根据您的需要进行调整。

【讨论】:

是的,我有那个触发我问这个问题的原因。如果web应用是web表单怎么办? 这也是我在 WebForms 中通常使用的方式。诀窍是您需要使用内核的 Get 方法。【参考方案6】:
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>();
    

【讨论】:

以上是关于如何在 asp.net Web 窗体上实现 Ninject 或 DI?的主要内容,如果未能解决你的问题,请参考以下文章

HTML 编码字符串 - ASP.NET Web 窗体 VS Razor 视图引擎

如何在 ASP.NET Web 窗体环境中使用 DLL?

asp.net mvc web窗体文件中如何获取HttpContextBase对象

Angular 针对 Asp.Net WebApi,在服务器上实现 CSRF

如何使用 JavaScript/jQuery 从 ASP.NET Web 窗体的 GridView 内部同时上传多个文件?

asp.net web应用程序和asp.net web窗体应用程序的区别?