Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Gareth Evans 12 posts 71 karma points c-trib
    Jul 23, 2013 @ 19:59
    Gareth Evans
    0

    Umbraco 6 and Dependancy Injection

    All,

    Just wondering, has anybody ever got DI/IoC working in Umbraco 6?

    Been swearing at Umbraco all day trying to get Castle.Windsor and Autofac (seperatly not both at the same time!) working but no joy.

    Thanks

    Gareth

     

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Jul 24, 2013 @ 13:04
    Jeroen Breuer
    0

    Hello,

    I haven't used it with Umbraco yet, but these docs might help: http://our.umbraco.org/Documentation/Reference/Mvc/using-ioc

    Jeroen

  • Luke Goodrich 9 posts 29 karma points
    Jul 24, 2013 @ 14:15
    Luke Goodrich
    0

    I use Castle Windsor with Umbraco using WebActivator to register the container. When using this method there is no difference between using Castle Windsor with Umbraco and a native MVC application.

     <packages>
      <package id="Castle.Core" version="3.2.0" targetFramework="net40" />
      <package id="Castle.Windsor" version="3.2.0" targetFramework="net40" />
      <package id="WebActivatorEx" version="2.0.1" targetFramework="net40" />
    </packages>&nbsp


    In AssemblyInfo.cs;

    [assembly: WebActivatorEx.PreApplicationStartMethod(typeof((MyApp.StartupHandler), "PreApplicationStart")]
    [assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(MyApp.StartupHandler), "ApplicationShutdown")]
      

    Startup Class

    public class StartupHandler

        private static IWindsorContainer container;   
    public static void PreApplicationStart()
        {
            SetupWindsorContainer();
            DependencyResolver.SetResolver(new WindsorDependencyResolver(container));
            DynamicModuleUtility.RegisterModule(typeof(PerWebRequestLifestyleModule));
        }
        public static void ApplicationShutdown()
        {
            DestroyWindsorContainer();
        }
     
        private static void SetupWindsorContainer()
        {
            string binDirectory = GetBinDirectoryPath();
            AssemblyFilter filter = new AssemblyFilter(binDirectory, "MyApp*.dll");        container = new WindsorContainer();
            container.AddFacility<TypedFactoryFacility>();
            container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel, true));
            container.Install(FromAssembly.InDirectory(filter));
        }    private static void DestroyWindsorContainer()
        {
            if (container != null)
            {
                container.Dispose();
                container = null;
            }
        }        private static string GetBinDirectoryPath()
        {
            bool isWebApplication = !string.IsNullOrEmpty(HttpRuntime.AppDomainId);
            string binDirectory;
            if (isWebApplication)
            {
                binDirectory = HttpRuntime.BinDirectory;
            }
            else
            {
                Assembly thisAssembly = Assembly.GetExecutingAssembly();
                string assemblyLocation = thisAssembly.Location;

                binDirectory = Path.GetDirectoryName(assemblyLocation);
            }

            return binDirectory;
        }    
    }

     
    Dependency Resolver Class;


    /// <summary>
    /// Castle windsor implementation of MVCs <see cref="System.Web.Mvc.IDependencyResolver"/> interface.
    /// </summary>
    public class WindsorDependencyResolver : System.Web.Mvc.IDependencyResolver
    {
        #region Fields and Constants

        /// <summary>
        /// The Castle Windsor kernel.
        /// </summary>
        private readonly IKernel kernel;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="WindsorDependencyResolver"/> class.
        /// </summary>
        /// <param name="kernel">The Castle Windsor kernel.</param>
        public WindsorDependencyResolver(IKernel kernel)
        {
            this.kernel = kernel;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Resolves singly registered services that support arbitrary object creation.
        /// </summary>
        /// <param name="serviceType">The type of the requested service or object.</param>
        /// <returns>The requested service or object.</returns>
        public object GetService(Type serviceType)
        {
            return this.kernel.HasComponent(serviceType) ? this.kernel.Resolve(serviceType) : null;
        }

        /// <summary>
        /// Resolves multiply registered services.
        /// </summary>
        /// <param name="serviceType">The type of the requested services.</param>
        /// <returns>The requested services.</returns>
        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this.kernel.ResolveAll(serviceType) as IEnumerable<object>;
        }

        #endregion
    }

     

  • Gareth Evans 12 posts 71 karma points c-trib
    Jul 24, 2013 @ 14:24
    Gareth Evans
    0

    Thank you Jeroen and Luke.

    Jeroen - I found this on the weekend but it didnt work.

    Luke - Looks promising, I will give it a go and see how I get on. The problem I was having is it must of overwritten the default ControllerFactory and basically wasn't doing any DIing lol. Cue lots of swearing!

    Thanks

    Gareth

  • Luke Goodrich 9 posts 29 karma points
    Jul 24, 2013 @ 14:28
    Luke Goodrich
    0

    I use Castle Windsor with Umbraco using WebActivator to register the container. When using this method there is no difference between using Castle Windsor with Umbraco and a native MVC application.

     <packages>
      <package id="Castle.Core" version="3.2.0" targetFramework="net40" />
      <package id="Castle.Windsor" version="3.2.0" targetFramework="net40" />
      <package id="WebActivatorEx" version="2.0.1" targetFramework="net40" />
    </packages>&nbsp


    In AssemblyInfo.cs;

    [assembly: WebActivatorEx.PreApplicationStartMethod(typeof((MyApp.StartupHandler), "PreApplicationStart")]
    [assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(MyApp.StartupHandler), "ApplicationShutdown")]
      

    Startup Class

    public class StartupHandler

        private static IWindsorContainer container;   
    public static void PreApplicationStart()
        {
            SetupWindsorContainer();
            DependencyResolver.SetResolver(new WindsorDependencyResolver(container));
            DynamicModuleUtility.RegisterModule(typeof(PerWebRequestLifestyleModule));
        }
        public static void ApplicationShutdown()
        {
            DestroyWindsorContainer();
        }
     
        private static void SetupWindsorContainer()
        {
            string binDirectory = GetBinDirectoryPath();
            AssemblyFilter filter = new AssemblyFilter(binDirectory, "MyApp*.dll");        container = new WindsorContainer();
            container.AddFacility<TypedFactoryFacility>();
            container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel, true));
            container.Install(FromAssembly.InDirectory(filter));
        }    private static void DestroyWindsorContainer()
        {
            if (container != null)
            {
                container.Dispose();
                container = null;
            }
        }        private static string GetBinDirectoryPath()
        {
            bool isWebApplication = !string.IsNullOrEmpty(HttpRuntime.AppDomainId);
            string binDirectory;
            if (isWebApplication)
            {
                binDirectory = HttpRuntime.BinDirectory;
            }
            else
            {
                Assembly thisAssembly = Assembly.GetExecutingAssembly();
                string assemblyLocation = thisAssembly.Location;

                binDirectory = Path.GetDirectoryName(assemblyLocation);
            }

            return binDirectory;
        }    
    }

     
    Dependency Resolver Class;


    /// <summary>
    /// Castle windsor implementation of MVCs <see cref="System.Web.Mvc.IDependencyResolver"/> interface.
    /// </summary>
    public class WindsorDependencyResolver : System.Web.Mvc.IDependencyResolver
    {
        #region Fields and Constants

        /// <summary>
        /// The Castle Windsor kernel.
        /// </summary>
        private readonly IKernel kernel;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="WindsorDependencyResolver"/> class.
        /// </summary>
        /// <param name="kernel">The Castle Windsor kernel.</param>
        public WindsorDependencyResolver(IKernel kernel)
        {
            this.kernel = kernel;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Resolves singly registered services that support arbitrary object creation.
        /// </summary>
        /// <param name="serviceType">The type of the requested service or object.</param>
        /// <returns>The requested service or object.</returns>
        public object GetService(Type serviceType)
        {
            return this.kernel.HasComponent(serviceType) ? this.kernel.Resolve(serviceType) : null;
        }

        /// <summary>
        /// Resolves multiply registered services.
        /// </summary>
        /// <param name="serviceType">The type of the requested services.</param>
        /// <returns>The requested services.</returns>
        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this.kernel.ResolveAll(serviceType) as IEnumerable<object>;
        }

        #endregion
    }

     

  • Ismail Mayat 4511 posts 10090 karma points MVP 2x admin c-trib
    Jul 24, 2013 @ 16:26
    Ismail Mayat
    2

    Guys,

    I just done this with ninject its really really easy. So in your umbraco website nuget in ninject https://www.nuget.org/packages/Ninject.MVC3/3.0.0.6 that will add in your app_start folder class called NinjectWebCommon in there you have method 

            private static void RegisterServices(IKernel kernel)

            {

                kernel.Bind<ISearchService>().To<SearchService>().InSingletonScope(); //this is my call gotcha make sure you have public constructor on the target

            }   

    then in your surface controller

            private readonly ISearchService _searchService;

            

            /// <summary>

            /// inject in this dependancy using ninject 

            /// </summary>

            /// <param name="searchService"></param>

            public SearchFormSurfaceController(ISearchService searchService)

            {

                _searchService = searchService;

            }

     

    and boh selectah you can haz ioc separation of concerns and all that other cool kid stuff ;-}

  • Gareth Evans 12 posts 71 karma points c-trib
    Jul 25, 2013 @ 00:01
    Gareth Evans
    0

    Ismail - worked like a charm dude. Thanks

    Gareth

  • Brendan Rice 538 posts 1099 karma points
    Jul 25, 2013 @ 00:34
    Brendan Rice
    0

    That looks really easy Ismail, Kudos.

  • Ismail Mayat 4511 posts 10090 karma points MVP 2x admin c-trib
    Jul 25, 2013 @ 10:21
    Ismail Mayat
    0

    Have blogged about it as well http://ismailmayat.wordpress.com/2013/07/25/umbraco-6-mvc-and-dependency-injection/ I still cannot get over how easy it is lol

  • Martin Meixger 17 posts 75 karma points
    Jul 25, 2013 @ 11:04
    Martin Meixger
    0

    I use Castle Windows and integrate it by subclassing UmbracoApplication and registering a WindsorControllerFactory

  • Gareth Evans 12 posts 71 karma points c-trib
    Jul 27, 2013 @ 16:11
    Gareth Evans
    0

    Martin, any code you can share?

    Thanks

    Gareth

  • Martin Meixger 17 posts 75 karma points
    Jul 29, 2013 @ 14:28
    Martin Meixger
    0

    you need at least version >= 6.1.2 https://github.com/umbraco/Umbraco-CMS/commit/aecc3d28bf2723877ce3f5a2b7db12eb20f799a3

    using System;
    using System.Web.Routing;
    using Umbraco.Web;
    
    public class MyApplication : UmbracoApplication, Castle.Windsor.IContainerAccessor
    {
        public Castle.Windsor.IWindsorContainer Container { get; private set; }
    
        protected override void OnApplicationStarting(object sender, EventArgs e) {
            base.OnApplicationStarting(sender, e);
    
            Container = InitializeContainer();
    WindsorControllerFactory.Kernel = Container.Kernel;
    Umbraco.Web.Mvc.FilteredControllerFactoriesResolver.Current.InsertType<WindsorControllerFactory>(0);
    } private Castle.Windsor.IWindsorContainer InitializeContainer() { var container = new Castle.Windsor.WindsorContainer(); //container.Register(Component.......); return container; } } public class WindsorControllerFactory : System.Web.Mvc.DefaultControllerFactory, Umbraco.Web.Mvc.IFilteredControllerFactory { private static Castle.MicroKernel.IKernel _kernel; public static Castle.MicroKernel.IKernel Kernel { get { if (_kernel == null) { throw new ArgumentNullException("Set Kernel in WindsorControllerFactory."); } return _kernel; } set { _kernel = value; } } public virtual bool CanHandle(RequestContext request) { var controllerName = request.RouteData.Values["controller"] as String; var controllerType = GetControllerType(request, controllerName); return Kernel.HasComponent(controllerType); } public override System.Web.Mvc.IController CreateController(RequestContext requestContext, string controllerName) { Type controllerType = GetControllerType(requestContext, controllerName); return (System.Web.Mvc.IController) Kernel.Resolve(controllerType); } public override void ReleaseController(System.Web.Mvc.IController controller) { Kernel.ReleaseComponent(controller); } }
  • Paul Stoker 39 posts 72 karma points c-trib
    Aug 09, 2013 @ 21:47
    Paul Stoker
    0

    Hi, Martin,

    I just tried your approach in the example provided but I get an error on this line below, the error is

    Cannot access internal class 'FilteredControllerFactoriesResolver' here.

    Do you have a solution for this?

    Thanks, Paul

    Umbraco.Web.Mvc.FilteredControllerFactoriesResolver.Current.InsertType<WindsorControllerFactory>(0);
  • Martin Meixger 17 posts 75 karma points
    Aug 09, 2013 @ 22:22
    Martin Meixger
    0

    Hi Paul,

    on what version do you work?

    Only version >= 6.1.2 have a public accessible. FilteredControllerFactoriesResolver. See https://github.com/umbraco/Umbraco-CMS/blob/release-6.1.2/src/Umbraco.Web/Mvc/FilteredControllerFactoriesResolver.cs

     

  • Paul Stoker 39 posts 72 karma points c-trib
    Aug 18, 2013 @ 17:07
    Paul Stoker
    0

    Hi Martin,

    Thanks for replying so quick but apologies for my delayed response. I'm on 6.1.1 which would explain why, I'll upgrade now and see what happens. thanks

  • andrew shearer 506 posts 653 karma points
    Aug 19, 2013 @ 00:53
  • Martin Meixger 17 posts 75 karma points
    Aug 19, 2013 @ 09:44
    Martin Meixger
    0

    TL;DR
    If you use Castle Windsor with MVC3-4 Controllers, dont use IDependencyResolver but IControllerFactory
    If you use Castle Windsor with MVC4 Web Api Controllers, use IDependencyResolver and implement IDependencyScope

    MVC:

    Castle Windsor could have problems to Release() your dependencies if you use System.Web.Mvc.IDependencyResolver, because this interface lacks a Release() method and a Scope mechanism.

    ( AutoFac/Ninject use a HttpModule for tracking and releasing per-web-request dependencies [graphs]. )

    System.Web.Mvc.IControllerFactory on the other hand, has a explicit Release() method.

    Web API:

    The Web API Dependency Resolver System.Web.Http.Dependencies.IDependencyResolver has a Scope mechanism to let Castle Windsor know when to release the dependency.

     

    http://mikehadlow.blogspot.it/2011/02/mvc-30-idependencyresolver-interface-is.html

    http://stackoverflow.com/questions/4140860/castle-windsor-dependency-resolver-for-mvc-3

    http://nikosbaxevanis.com/blog/2012/06/04/using-the-web-api-dependency-resolver-with-castle-windsor-part-2/

     

  • Luke Goodrich 9 posts 29 karma points
    Sep 18, 2013 @ 16:27
    Luke Goodrich
    0

    I have been using the ControllerFactory method with Castle Windsor for some time, but I've noticed the number of calls to CreateController and ReleaseController do not match up. 

    I think I have traced this to a bug in Umbraco. There is documented functionality in https://github.com/umbraco/Umbraco-CMS/blob/6.2.0/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs which means 2 controller instances are created for each request. One is created by Umbraco in StoreControllerInRouteDefinition and the other by MVC itself in the MvcHandler class as per standard MVC functionality. However I don't think the instance created in the StoreControllerInRouteDefinition method in UmbracoMvcHandler is ever passed to the controller factory for release.

    Has anybody else using Castle Windsor or other customer ControllerFactory implementations seen this?

  • Martin Meixger 17 posts 75 karma points
    Sep 19, 2013 @ 15:01
    Martin Meixger
    0

    Hi Luke,

    as long as the controllers are registered correctly within Windsor with a PerWebRequest Lifestyle ( and not Transient Lifestyle, witch would anyway be wrong ), the ControlleFactory.CreateController(...) would return same instance. So eventually there is only 1 instance to release.

    The following test code ...

    public override IController CreateController(RequestContext requestContext, string controllerName) {
        Type controllerType = GetControllerType(requestContext, controllerName);
        var controller = (IController) Kernel.Resolve(controllerType);
        Debug.WriteLine("CreateController '{0}' HashCode: '{1}'", controller.GetType().Name, controller.GetHashCode());
        return controller;
    }
    
    
    public override void ReleaseController(IController controller) {
        Debug.WriteLine("ReleaseController '{0}' HashCode: '{1}'", controller.GetType().Name, controller.GetHashCode());
        Kernel.ReleaseComponent(controller);
    }
    

    ... would log:

    • CreateController 'HomePageController' HashCode: '43469086' <- same hash
    • CreateController 'HomePageController' HashCode: '43469086' <- same hash
    • ReleaseController 'HomePageController' HashCode: '43469086'
Please Sign in or register to post replies

Write your reply to:

Draft