Castle Windsor as component container for DotNetNuke

by Remco Ros 10. March 2009 14:48

In my previous post I discussed some ideas I have for a DotNetNuke module development framework on top of the standard DotNetNuke library. It should provide clear guidance in writing custom DNN modules using the Model View Presenter pattern and supports transparent use of NHibernate and Fluent NHibernate as an alternative to DNN’s DAL+.

One of the requirements where that it should automatically register basic services, repositories, views and presenters in a dependency container using Convention over Configuration and that the framework itself should be container independent (using ie. CommonServiceLocator).

While scanning trough DotNetNuke’s source I noticed it provides a clean abstraction for a component (DI) container: DotNetNuke.ComponentModel.IContainer and DotNetNuke.ComponentModel.AbstractContainer.

The default implementation DNN provides (SimpleContainer) is not sufficient for the things I wanted to do with it (auto registration, custom lifetime management, etc.). So instead of using CommonServiceLocator in my framework, I went with writing a custom implementation of IContainer utilizing the Castle Windsor container.

Following is an example implementation, feel free to use the code in your own project:

You should know how to change the default container DotNetNuke uses. If not, then you probably won’t need it and can continue reading just for fun ?

As you can see this is called CastleSimpleContainer. In DotNetNukeMVP a more extended implementation is provided to allow a common way for more flexible registration of components.

    1 // --------------------------------------------------------------------------------------------------------------------- 
    2 // <copyright file="CastleSimpleContainer.cs" company="RawSoft">
    3 //   Copyright (c) RawSoft.  All rights reserved.
    4 // </copyright>
    5 // <summary>
    6 //   Defines the CastleSimpleContainer type.
    7 // </summary>
    8 // ---------------------------------------------------------------------------------------------------------------------
    9 namespace DotNetNukeMVP.Castle
   10 {
   11     using System;
   12     using System.Collections;
   13     using System.Collections.Generic;
   14 
   15     using DotNetNuke.ComponentModel;
   16 
   17     using global::Castle.Core;
   18     using global::Castle.Windsor;
   19 
   20     public class CastleSimpleContainer : AbstractContainer
   21     {
   22         private readonly string containerName;
   23 
   24         private readonly IWindsorContainer container;
   25 
   26         private readonly IDictionary<string, IDictionary> componentDependencies = new Dictionary<string, IDictionary>();
   27 
   28         public CastleSimpleContainer()
   29             : this(new WindsorContainer())
   30         {
   31         }
   32 
   33         public CastleSimpleContainer(IWindsorContainer container)
   34             : this(string.Format("Container_{0}", Guid.NewGuid()), container)
   35         {
   36         }
   37 
   38         public CastleSimpleContainer(string name, IWindsorContainer container)
   39         {
   40             this.containerName = name;
   41             this.container = container;
   42         }
   43 
   44         public IWindsorContainer InnerContainer
   45         {
   46             get
   47             {
   48                 return this.container;
   49             }
   50         }
   51 
   52         public override string Name
   53         {
   54             get
   55             {
   56                 return this.containerName;
   57             }
   58         }
   59 
   60         public override void RegisterComponentSettings(string name, IDictionary dependencies)
   61         {
   62             componentDependencies[name] = dependencies;
   63         }
   64 
   65         public override object GetComponent(string name)
   66         {
   67             if (!this.container.Kernel.HasComponent(name))
   68             {
   69                 return null;
   70             }
   71 
   72             try
   73             {
   74                 return this.container.Resolve(name);
   75             }
   76             catch
   77             {
   78             }
   79 
   80             return null;
   81         }
   82 
   83         public override object GetComponent(string name, Type contractType)
   84         {
   85             if (!this.container.Kernel.HasComponent(contractType))
   86             {
   87                 return null;
   88             }
   89 
   90             try
   91             {
   92                 return this.container.Resolve(name, contractType);
   93             }
   94             catch
   95             {
   96             }
   97 
   98             return null;
   99         }
  100 
  101         public override IDictionary GetComponentSettings(string name)
  102         {
  103             if (componentDependencies.ContainsKey(name))
  104             {
  105                 return componentDependencies[name];
  106             }
  107 
  108             return null;
  109         }
  110 
  111         public override void RegisterComponent(string name, Type contractType, Type componentType, ComponentLifeStyleType lifestyle)
  112         {
  113             this.container.AddComponentLifeStyle(name, contractType, componentType, GetLifeStyleType(lifestyle));
  114         }
  115 
  116         public override void RegisterComponentInstance(string name, Type contractType, object instance)
  117         {
  118             this.container.Kernel.AddComponentInstance(name, contractType, instance);
  119         }
  120 
  121         public override object GetComponent(Type contractType)
  122         {
  123             try
  124             {
  125                 return this.container.Resolve(contractType);
  126             }
  127             catch
  128             {
  129             }
  130 
  131             return null;
  132         }
  133 
  134         private static LifestyleType GetLifeStyleType(ComponentLifeStyleType lifeStyleType)
  135         {
  136             LifestyleType scope = lifeStyleType == ComponentLifeStyleType.Singleton
  137                                         ? LifestyleType.Singleton
  138                                         : LifestyleType.Transient;
  139             return scope;
  140         }
  141     }
  142 }

Tags: , ,

DotNetNuke

Comments

3/10/2009 3:20:23 PM #

cathal

Good stuff, nice to see people making use of this.

BTW, Charles Nurse has a number of blogs on the changes made for 5.0 to support better testing that might be worth a read www.dotnetnuke.com/.../Default.aspx

cathal United Kingdom |

3/10/2009 3:28:42 PM #

Remco Ros

I read his posts, it was one of the reasons I began abstracting some of these MVP ideas into a separate deployable framework. Got pretty tired of rewriting all this infrastructure/pattern stuff for every module I create.

Remco Ros Netherlands |

3/10/2009 3:35:25 PM #

Charles Nurse

Great post.  
This is exactly the reason that the Container in 5.0 was abstracted.  We did not want to add a dependency requirement on a 3rd party component (Castle) in the core distro, but recognized that others might want to take advantage of the advanced features of other containers.

Charles Nurse Canada |

3/17/2009 8:45:26 PM #

Paco

I wrote some DNN stuff with NHibernate and StructureMap. I had some threading trouble to create the ISessionFactory/ISessionSource within DNN. The best I could get was unit of work per module, but unit of work per request is better of course. How do you manage your NHibernate unit of work scope in DNN?

Paco United States |

3/17/2009 11:28:49 PM #

Remco Ros

@Paco,

I have this planned for a future blog post, where I will be explaining integration with NHibernate / Fluent-NHibernate.

Feel free to contact me, or add me on MSN: remcoros@live.nl

Remco Ros Netherlands |

About me

Remco Ros

Hey, i'm remco, currently working as a .Net developer in the netherlands, interested in new technologies, physics, and spirituality.

Have a question? contact me.