【问题标题】:Ninject, ASP.NET and Custom ControlsNinject、ASP.NET 和自定义控件
【发布时间】:2023-12-23 07:01:01
【问题描述】:

我目前使用的是 ASP.NET(标准,不是 MVC)并且我使用 Ninject 作为我的 IOC 容器。

我已经在使用它将依赖项注入到我的页面中,但是,我想知道是否有办法将依赖项注入到我的自定义控件中?

如果没有,我将着手扩展 Ninject :)

【问题讨论】:

    标签: asp.net webforms custom-controls ninject ioc-container


    【解决方案1】:

    好的,所以我最终扩展了 Ninject 并向 Ninject.Framework.Web dll 添加了两个类。

    这是给有兴趣自己添加的人的补丁:

    Index: src/Framework/Web/Ninject.Framework.Web.csproj
    ===================================================================
    --- src/Framework/Web/Ninject.Framework.Web.csproj  (revision 158)
    +++ src/Framework/Web/Ninject.Framework.Web.csproj  (working copy)
    @@ -2,7 +2,7 @@
       <PropertyGroup>
         <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
         <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    -    <ProductVersion>9.0.21022</ProductVersion>
    +    <ProductVersion>9.0.30729</ProductVersion>
         <SchemaVersion>2.0</SchemaVersion>
         <ProjectGuid>{C46075DB-A0FB-466B-BA76-C093227FA9C7}</ProjectGuid>
         <OutputType>Library</OutputType>
    @@ -42,17 +42,24 @@
         <Reference Include="System.Core">
           <RequiredTargetFramework>3.5</RequiredTargetFramework>
         </Reference>
    +    <Reference Include="System.Data" />
    +    <Reference Include="System.Drawing" />
         <Reference Include="System.Web" />
         <Reference Include="System.Web.Services" />
    +    <Reference Include="System.Xml" />
       </ItemGroup>
       <ItemGroup>
         <Compile Include="..\..\GlobalAssemblyInfo.cs">
           <Link>Properties\GlobalAssemblyInfo.cs</Link>
         </Compile>
    +    <Compile Include="WebControlBase.cs" />
         <Compile Include="NinjectHttpApplication.cs" />
         <Compile Include="HttpHandlerBase.cs">
         </Compile>
         <Compile Include="NinjectHttpModule.cs" />
    +    <Compile Include="UserControlBase.cs">
    +      <SubType>ASPXCodeBehind</SubType>
    +    </Compile>
         <Compile Include="WebServiceBase.cs">
           <SubType>Component</SubType>
         </Compile>
    Index: src/Framework/Web/UserControlBase.cs
    ===================================================================
    --- src/Framework/Web/UserControlBase.cs    (revision 0)
    +++ src/Framework/Web/UserControlBase.cs    (revision 0)
    @@ -0,0 +1,65 @@
    +#region License
    +//
    +// Author: Nate Kohari <nkohari@gmail.com>
    +// Copyright (c) 2007-2008, Enkari, Ltd.
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//   http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +//
    +#endregion
    +#region Using Directives
    +using System;
    +using Ninject.Core.Logging;
    +using Ninject.Core;
    +using System.Web.UI;
    +#endregion
    +
    +namespace Ninject.Framework.Web
    +{
    +    /// <summary>
    +    /// A <see cref="UserControl"/> that supports injection
    +    /// </summary>
    +    public class UserControlBase : UserControl
    +    {
    +        /*----------------------------------------------------------------------------------------*/
    +        private ILogger _logger;
    +        /*----------------------------------------------------------------------------------------*/
    +        /// <summary>
    +        /// Gets or sets the logger associated with the object.
    +        /// </summary>
    +        [Inject]
    +        public ILogger Logger
    +        {
    +            get { return _logger; }
    +            set { _logger = value; }
    +        }
    +        /*----------------------------------------------------------------------------------------*/
    +        /// <summary>
    +        /// Raises the <see cref="E:System.Web.UI.Control.Init"></see> event to initialize the page.
    +        /// </summary>
    +        /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
    +        protected override void OnInit(EventArgs e)
    +        {
    +            base.OnInit(e);
    +            RequestActivation();  
    +        }
    +        /*----------------------------------------------------------------------------------------*/
    +        /// <summary>
    +        /// Asks the kernel to inject this instance.
    +        /// </summary>
    +        protected virtual void RequestActivation()
    +        {
    +            KernelContainer.Inject(this);
    +        }
    +        /*----------------------------------------------------------------------------------------*/
    +    }
    +}
    Index: src/Framework/Web/WebControlBase.cs
    ===================================================================
    --- src/Framework/Web/WebControlBase.cs (revision 0)
    +++ src/Framework/Web/WebControlBase.cs (revision 0)
    @@ -0,0 +1,65 @@
    +#region License
    +//
    +// Author: Nate Kohari <nkohari@gmail.com>
    +// Copyright (c) 2007-2008, Enkari, Ltd.
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//   http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +//
    +#endregion
    +#region Using Directives
    +using System;
    +using System.Web.UI.WebControls;
    +using Ninject.Core.Logging;
    +using Ninject.Core;
    +#endregion
    +
    +namespace Ninject.Framework.Web
    +{
    +    /// <summary>
    +    /// A <see cref="WebControl"/> that supports injection
    +    /// </summary>
    +    public class WebControlBase : WebControl
    +    {
    +        /*----------------------------------------------------------------------------------------*/
    +        ILogger _logger;
    +        /*----------------------------------------------------------------------------------------*/
    +        /// <summary>
    +        /// Gets or sets the logger associated with the object.
    +        /// </summary>
    +        [Inject]
    +        public ILogger Logger
    +        {
    +            get { return _logger; }
    +            set { _logger = value; }
    +        }
    +        /*----------------------------------------------------------------------------------------*/
    +        /// <summary>
    +        /// Raises the <see cref="E:System.Web.UI.Control.Init"></see> event to initialize the page.
    +        /// </summary>
    +        /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
    +        protected override void OnInit(EventArgs e)
    +        {
    +            base.OnInit(e);
    +            RequestActivation();
    +        }
    +        /*----------------------------------------------------------------------------------------*/
    +        /// <summary>
    +        /// Asks the kernel to inject this instance
    +        /// </summary>
    +        protected virtual void RequestActivation()
    +        {
    +            KernelContainer.Inject(this);
    +        }
    +        /*----------------------------------------------------------------------------------------*/
    +    }
    +}
    

    【讨论】:

    • 能否请您至少发布原始 XML 而不是您从 IE 获得的格式化内容?
    • 这是 Ninject 的 SVN 补丁,增加了在 ASP.NET 中将 Ninject 与用户控件和自定义控件一起使用的功能
    【解决方案2】:

    我通过遍历页面上的所有控件并注入实现某些接口的控件来解决这个问题。

    界面为空:

    public interface INinjectControl { }
    

    我在 PageBase 和 MasterPageBase 中添加了一个循环来注入所有实现此接口的控件:

    protected virtual void RequestActivation()
    {
        KernelContainer.Inject( this );
        InjectControls(this.Controls);
    }
    
    private void InjectControls(ControlCollection controls)
    {
        foreach (Control control in controls)
        {
            if (control is INinjectControl)
                KernelContainer.Inject(control);
            this.InjectControls(control.Controls);
        }
    }
    

    有一些缺点:

    • 这仅适用于页面上已经存在的控件 OnInit 触发。如果您稍后在该过程中添加控件,则循环具有 已经运行并且依赖项不会被注入。
    • 这会在某些控件上调用 CreateChildControls(),因为您请求 Controls 集合。这可能会导致问题,因为现在在生命周期的早期调用此方法。
    • 它循环遍历所有控件,因此效率不高。

    【讨论】: