The static container already has a kernel associated with it!

873 views
Skip to first unread message

Andrew McInnes

unread,
Aug 15, 2013, 7:53:03 AM8/15/13
to nin...@googlegroups.com
Hi,

I am totally new to ninject and am in the process of completely restructuring my applications to use a new DAL. The issue I am having is that I have a business layer and this has caused me a little confusion in terms of working with ninject.

My application is structured with:
    - Data
    - Data.Contracts
    - Models
    - Business Layer
    - Presentation Layer

I use Unit Of Work and Repository pattern also.

In the business layer I have a NinjectWebCommon as follows:

[assembly: WebActivator.PreApplicationStartMethod(typeof(BusinessLogic.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(BusinessLogic.App_Start.NinjectWebCommon), "Stop")]

namespace
    BusinessLogic.App_Start
{
    using System;
    using System.Web;
    using Data;
    using Data.Contracts;
    using Data.Helpers;
    using Microsoft.Web.Infrastructure.DynamicModuleHelper;
    using Ninject;
    using Ninject.Web.Common;

    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates an instance of IKernal
        /// </summary>
        public static IKernel Kernel { get; private set; }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            Kernel = new StandardKernel();
            Kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            Kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(Kernel);
            return Kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<RepositoryFactories>().To<RepositoryFactories>().InSingletonScope();
            kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
            kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
        }
    }
}

And I inject the UnitOfWork as follows:

        [Inject]
        public IUnitOfWork Uow { get; set; }

 And create methods as follows:

 
        public EMPOS GetPOSByDate(string EmpId, DateTime FindDate)
        {

            EMPOS pos = (from p in Uow.EMPOSs.GetAll()
                         where p.DETNUMBERA == EmpId &&
                         p.POSSTARTC <= FindDate &&
                         (p.POSENDD >= FindDate ||
                         p.POSENDD == null)
                         select p).Single();
            return pos;
        }

This works fine in a test console app I created which uses a base page the same as my webforms app:

using System;
using System.Web.UI;
using Data.Contracts;
using Ninject;

namespace ConsoleApplication1
{
    public abstract class BasePage : Ninject.Web.PageBase
    {
        // NOT NECESSARY TO DISPOSE THE UOW IN OUR CONTROLLERS
        // Recall that we let IoC inject the Uow into our controllers
        // We can depend upon on IoC to dispose the UoW for us
        [Inject]
        public IUnitOfWork Uow { get; set; }
    }
}

This is the NinjectWebCommon in my console app:

[assembly: WebActivator.PreApplicationStartMethod(typeof(ConsoleApplication1.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(ConsoleApplication1.App_Start.NinjectWebCommon), "Stop")]

namespace
    ConsoleApplication1.App_Start
{
    using System;
    using System.Web;
    using Data;
    using Data.Contracts;
    using Data.Helpers;
    using Microsoft.Web.Infrastructure.DynamicModuleHelper;
    using Ninject;
    using Ninject.Web.Common;

    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);
            return kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<RepositoryFactories>().To<RepositoryFactories>().InSingletonScope();
            kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
            kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
        }
    }
}

 And I access the Business layer and UnitOfWork as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Data.Contracts;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Models;
using Ninject;
using BusinessLogic;


namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            var BL = new BusinessLayer();
            var kernel = new StandardKernel();
            kernel.Bind<Data.Helpers.RepositoryFactories>().To<Data.Helpers.RepositoryFactories>().InSingletonScope();
            kernel.Bind<Data.Helpers.IRepositoryProvider>().To<Data.Helpers.RepositoryProvider>();
            kernel.Bind<IUnitOfWork>().To<Data.UnitOfWork>().InSingletonScope();
            kernel.Bind<Leave>().To<Leave>().InTransientScope();
            kernel.Inject(BL);

            while (true)
            {
                try
                {
                    Console.WriteLine("Enter an employee number...");
                    string emp = Console.ReadLine();
                    var cont = BL.GetContinualServiceDate(emp);
                    if (cont == null)
                        throw new Exception("The date returned was null, the employee may be a leaver or may not exist.");
                    Console.WriteLine("Continual Service Start Date : " + (DateTime)cont);
                    Leave lv = kernel.Get<Leave>();
                    lv.FindLeave(emp);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
 
    }

    public class Leave : BasePage
    {
        public void FindLeave(string emp)
        {
            IEnumerable<EMLVE> abc = Uow.EMLVEs.GetAll().Where(a => a.DETNUMBERA == emp).ToList();
            foreach (EMLVE a in abc)
            {
                Console.WriteLine(a.DETNUMBERA + " : " + a.LMDSTARTC + " : " + a.LMDTYPECDA);
            }
        }
    }
}
As I said this all works fine, but when I try to do this in my web forms app I get an error:

The static container already has a kernel associated with it!

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NotSupportedException: The static container already has a kernel associated with it!

Source Error:

Line 26:             DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
Line 27:             DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
Line 28:             bootstrapper.Initialize(CreateKernel);
Line 29:         }
Line 30: 

Source File: c:\Users\AMcInnes\Documents\Visual Studio 2012\Projects\Dash\Dash\App_Start\NinjectWebCommon.cs    Line: 28

Stack Trace:

[NotSupportedException: The static container already has a kernel associated with it!]
   Ninject.Web.KernelContainer.set_Kernel(IKernel value) in c:\Projects\Ninject\ninject.web\src\Ninject.Web\KernelContainer.cs:38
   Ninject.Web.NinjectWebHttpApplicationPlugin.Start() in c:\Projects\Ninject\ninject.web\src\Ninject.Web\NinjectWebHttpApplicationPlugin.cs:62
   Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:52
   Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:32
   Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:52
   Dash.App_Start.NinjectWebCommon.Start() in c:\Users\AMcInnes\Documents\Visual Studio 2012\Projects\Dash\Dash\App_Start\NinjectWebCommon.cs:28

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
   System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) +0
   System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) +192
   System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +108
   System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) +19
   WebActivator.BaseActivationMethodAttribute.InvokeMethod() +236
   WebActivator.ActivationManager.RunActivationMethods() +534
   WebActivator.ActivationManager.RunPreStartMethods() +41
   WebActivator.ActivationManager.Run() +64

[InvalidOperationException: The pre-application start initialization method Run on type WebActivator.ActivationManager threw an exception with the following error message: Exception has been thrown by the target of an invocation..]
   System.Web.Compilation.BuildManager.InvokePreStartInitMethodsCore(ICollection`1 methods, Func`1 setHostingEnvironmentCultures) +550
   System.Web.Compilation.BuildManager.InvokePreStartInitMethods(ICollection`1 methods) +132
   System.Web.Compilation.BuildManager.CallPreStartInitMethods(String preStartInitListPath) +90
   System.Web.Compilation.BuildManager.ExecutePreAppStart() +135
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +516

[HttpException (0x80004005): The pre-application start initialization method Run on type WebActivator.ActivationManager threw an exception with the following error message: Exception has been thrown by the target of an invocation..]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9873784
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +101
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +254


Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18034

The only difference I can see in my implementation is that I create a public static IKernel so that I can insert the BusinessLayer when I need to use it.

This is the NinjectWebCommon for my webforms app:

[assembly: WebActivator.PreApplicationStartMethod(typeof(Dash.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(Dash.App_Start.NinjectWebCommon), "Stop")]

namespace
    Dash.App_Start
{
    using System;
    using System.Web;
    using Data;
    using Data.Contracts;
    using Data.Helpers;
    using Microsoft.Web.Infrastructure.DynamicModuleHelper;
    using Ninject;
    using Ninject.Web.Common;

    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates an instance of IKernal
        /// </summary>
        public static IKernel Kernel { get; private set; }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            Kernel = new StandardKernel();
            Kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            Kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(Kernel);
            return Kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<RepositoryFactories>().To<RepositoryFactories>().InSingletonScope();
            kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
            kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
        }
    }
}

And this is how I use it, (I also have the same basepage as shown above in the webforms app)

        [WebMethod]
        public static AutoCompleteBoxData GetResults(RadAutoCompleteContext context)
        {
            var BL = new BusinessLayer();
            Dash.App_Start.NinjectWebCommon.Kernel.Inject(BL); //now the Uow field is injected

            string searchString = ((Dictionary<string, object>)context)["Text"].ToString();
            List<AutoCompleteBoxItemData> staff =
                (from s in BL.MyStaffSearch()
                     where s.Text.Contains(searchString)
                     select s).ToList();

            AutoCompleteBoxData res = new AutoCompleteBoxData();
            res.Items = staff.ToArray();
            return res;
        }

I would really appreciate any help on resolving this issue, please answer in layman's terms, this is not only day 2 of Ninject but day 2 of IoC in general for me :)

Cheers,

Andy
 
Reply all
Reply to author
Forward
0 new messages