views:

323

answers:

2

I have created an ASP.NET MVC application and am trying to use Castle Windsor as my IOC

However, when the controllers are trying to resolve I am getting 'Content' and 'Scripts' into the 'controllerName' parameter in the CreateController(RequestContext requestContext, string controllerName) method. Needless to say these are not controllers. They appears to be the folders of the web site

Why is it trying to register these as controllers?

How do I ignore these folders??

thanks

exception from WindsorControllerFactory

Due to not being able to post the image I have to describe it - it basically just says

'The contentcontroller was not found'

Global.asax.cs

public static IIocContainer Ioc;

            protected void Application_Start()
            {
                InitialiseIocContainer();
                RegisterViewEngine(ViewEngines.Engines);
                RegisterRoutes(RouteTable.Routes);
                StartProfiling();
            }


private void InitialiseIocContainer()
        {
            IWindsorContainer _container = new WindsorContainer();

            var controllerTypes = typeof (GidgetController).Assembly.GetTypes();
            foreach (var controllerType in controllerTypes.Where((t=>typeof(IController).IsAssignableFrom(t))))
            {
                _container.AddComponentLifeStyle(controllerType.Name.ToLower(), controllerType, LifestyleType.Transient);   
            }


            _container.AddComponent("a",typeof(IGidgetService), typeof(GidgetService));
            _container.AddComponent("b",typeof(IGidgetRepository), typeof(GidgetRepository));
            _container.AddComponent("c",typeof(IGidgetValidator), typeof(GidgetValidator));


            ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_container));

        }

windsorControllerFactory.cs

public IController CreateController(RequestContext requestContext, string controllerName)
        {
            try
            {
                controllerName = controllerName.ToLower() + "controller";
                var controller = _container.Resolve<IController>(controllerName);
                return controller;
            }
            catch (ComponentNotFoundException)
            {
                throw new HttpException(404, string.Format("The {0} controller was not found", controllerName));

            }

        }
A: 

I follow Steve Sanderson's pattern in creating a WindsorControllerFactory, which works quite well. I've modified his to actually return proper 404s when there isn't a controller by the name (i.e. someone types "/garbageblahblah") because his pattern didn't pick it up. So, I use Reflector to grab the bits that are built into the default controller factory for handling bad urls.

His pattern uses reflection to find all controllers within your Mvc project, and register them all upon app startup. You don't want to use CreateController, but instead GetControllerInstance() as this is only called by the underlying Mvc framework when a controller is going to be invoked. /Content is ignored by convention, and therefore is not called.

My CastleWindsorControllerFactory:

/// <summary>
/// Represents a special controller factory.
/// </summary>
public class CastleWindsorControllerFactory : DefaultControllerFactory
{
 WindsorContainer _container;

 public CastleWindsorControllerFactory()
 {
  // register all controllers from the calling assembly.
  // (e.g. the mvc site calling this factory)
  //
  _container =
   new WindsorContainer(
    new XmlInterpreter(
     new ConfigResource("castle")
    )
   );

  // change this to Assembly.GetAssembly() if used directly from
  // your MVC website.  The code below is for when this class
  // exists in a seperate assembly.
  //
  var controllers =
   from t in Assembly.GetCallingAssembly().GetTypes()
   where typeof(IController).IsAssignableFrom(t)
   select t;

  foreach (Type t in controllers)
   _container.AddComponentLifeStyle(
    t.FullName, t, LifestyleType.Transient); 
 }

 protected override IController GetControllerInstance(Type controllerType)
 {
  if (controllerType == null)
  {
   throw new HttpException(
    0x194
    , string.Format(
     CultureInfo.CurrentUICulture
     , "Controller Not Found"
     , new object[] {
      this.RequestContext.HttpContext.Request.Path }));
  }
  if (false == typeof(IController).IsAssignableFrom(controllerType))
  {
   throw new ArgumentException(
    string.Format(
     CultureInfo.CurrentUICulture
     , "Type does not sub-class the controller base"
     , new object[] { controllerType }), "controllerType");
  }

  return 
   (IController) _container.Resolve(controllerType);
 }
}

And within my Globals.asax.cs, this is all you need (what you have above is vast overkill! I already loop through and register them within my CastleWindsorControllerFactor above).

protected void Application_Start()
{
 RegisterRoutes(RouteTable.Routes);

 // custom controller factory that uses Windsor
 ControllerBuilder.Current.SetControllerFactory(
  new CastleWindsorControllerFactory());

 // Uncomment to debug routes
 //RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
}

Technically, this isn't exactly the code I use. I have actually abstracted the entire Castle Windsor off to a static instance in a class I call ComponentFactory. This allows me to have true Singleton patterns through my applications, amongst several strong-type additions.

I mention this, because I plan on releasing ComponentFactory() soon on my blog. But, drop me an email and I'll send the latest version to you. Email is: me -at- eduncan911.com

eduncan911
Looks like your ComponentFactory is actually a service locator, not a good idea for IoC containers. Creating the container and registering controllers within the controllerfactory violates SRP, it's not its responsibility.
Mauricio Scheffer
thanks for your answer.
kurasa
@Mauricio Scheffer: a -1 vote for violating SRP? Really? He did not state any concern for DDD or SRP (and the MVCContrib that he said worked does the same thing as I posted). What would be your solutino then for registering 100s of IControllers automatically in an ASP.NET MVC site? "Retrieving" a controller would be the responsibility of a Factory pattern, which does not violate SRP. This uses an IoC Container for handling it easier.
eduncan911
sorry, I just don't think this is good advice. We'll have to agree to disagree I guess...
Mauricio Scheffer
+1  A: 

Just use MVCContrib.

It includes everything to integrate Windsor and ASP.NET MVC, including the controller factory and extensions to register controllers.

Mauricio Scheffer
thank you. That worked perfectly.
kurasa
Doesn't MVCContrib do the same thing as my answer? lol
eduncan911