Sekhat
Sekhat

Reputation: 4479

Ninject, ASP.NET and Custom Controls

I'm currently using ASP.NET (standard, not MVC) and I'm using Ninject as my IOC container.

I'm already using it to inject dependencies into my pages, however, I was wondering if there was a way to inject dependencies into my custom controls?

If not, I'll get underway extending Ninject :)

Upvotes: 4

Views: 1558

Answers (2)

Sekhat
Sekhat

Reputation: 4479

Okay so I ended up extending Ninject and added two classes to Ninject.Framework.Web dll.

Heres the patch for anyone who's interested in adding it themselves:

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 <[email protected]>
+// 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 <[email protected]>
+// 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);
+        }
+        /*----------------------------------------------------------------------------------------*/
+    }
+}

Upvotes: 6

Sjoerd
Sjoerd

Reputation: 75619

I solved this by looping through all controls on the page, and injecting those who implement some interface.

The interface is empty:

public interface INinjectControl { }

I've added a loop to PageBase and MasterPageBase to inject all controls which implement this interface:

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

There are some drawbacks:

  • This only works for controls which are already on the page when OnInit fires. If you add a control later in the process, the loop has already run and the dependencies won't be injected.
  • This calls CreateChildControls() on some controls, because you request the Controls collection. This can lead to problems because this method is now called far earlier in the lifecycle.
  • It loops through all controls, so it is not very efficient.

Upvotes: 1

Related Questions