Setting up Inversion of Control (IoC) in ASP.NET MVC with Castle Windsor
I'm going over Sanderson's Pro ASP.NET MVC Framework and in Chapter 4 he discusses Creating a Custom Controller Factory and it seems that the original method, AddComponentLifeStyle
or AddComponentWithLifeStyle
, used to register controllers is deprecated now:
public class WindsorControllerFactory : DefaultControllerFactory
{
IWindsorContainer container;
public WindsorControllerFactory()
{
container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
// register all the controller types as transient
var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
//[Obsolete("Use Register(Component.For<I>().ImplementedBy<T>().Named(key).Lifestyle.Is(lifestyle)) instead.")]
//IWindsorContainer AddComponentLifeStyle<I, T>(string key, LifestyleType lifestyle) where T : class;
foreach (Type t in controllerTypes)
{
container.Register(Component.For<IController>().ImplementedBy<???>().Named(t.FullName).LifeStyle.Is(LifestyleType.Transient));
}
}
// Constructs the controller instance needed to service each request
protected override IController GetControllerInstance(Type controllerType)
{
return (IController)container.Resolve(controller开发者_如何学GoType);
}
}
The new suggestion is to use Register(Component.For<I>().ImplementedBy<T>().Named(key).Lifestyle.Is(lifestyle))
, but I can't figure out how to present the implementing controller type in the ImplementedBy<???>()
method. I tried ImplementedBy<t>()
and ImplementedBy<typeof(t)>()
, but I can't find the appropriate way to pass in the implementing type. Any ideas?
I'm doing this using the ControllerBuilder.SetControllerFactory
and the code you can find in the open source project MvcContrib:
Global.asax.cs
protected void Application_Start()
{
...
IWindsorContainer windsorContainer = new WindsorContainer();
windsorContainer.RegisterControllers(Assembly.GetExecutingAssembly());
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(windsorContainer));
...
}
WindsorControllerFactory
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IWindsorContainer _container;
public WindsorControllerFactory(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException();
}
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException();
}
if (!typeof(IController).IsAssignableFrom(controllerType))
{
throw new ArgumentException();
}
try
{
return (IController)_container.Resolve(controllerType);
}
catch (Exception ex)
{
throw new InvalidOperationException();
}
}
public override void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
_container.Release(controller);
}
}
WindsorExtensions (see MvcContrib)
public static class WindsorExtensions
{
public static IWindsorContainer RegisterController<T>(this IWindsorContainer container) where T : IController
{
container.RegisterControllers(typeof(T));
return container;
}
public static IWindsorContainer RegisterControllers(this IWindsorContainer container, params Type[] controllerTypes)
{
foreach (Type type in controllerTypes)
{
if (ControllerExtensions.IsController(type))
{
container.Register(Component.For(type).Named(type.FullName).LifeStyle.Is(LifestyleType.Transient));
}
}
return container;
}
public static IWindsorContainer RegisterControllers(this IWindsorContainer container, params Assembly[] assemblies)
{
foreach (Assembly assembly in assemblies)
{
container.RegisterControllers(assembly.GetExportedTypes());
}
return container;
}
}
ControllerExtensions (see MvcContrib)
public static class ControllerExtensions
{
public static bool IsController(Type type)
{
return type != null
&& type.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)
&& !type.IsAbstract
&& typeof(IController).IsAssignableFrom(type);
}
}
You may also want to consider using the new installer option in the latest Windsor build. There is more documentation on Windsor's tutorial: http://stw.castleproject.org/Windsor.Windsor-tutorial-part-three-writing-your-first-installer.ashx
There's a tutorial (in the works but 9 parts are already out) that discusses usage of Windsor in ASP.NET MVC here. That's the most up to date and covering most of the usual usage resource on the topic as far as I'm aware.
@Lirik, as an addition: drop your own custom IControllerFactory
out if you use MVC3. Just register controllers with Windsor and implement IDependencyResolver
with Windsor container inside.
Set your IDependencyResolver
as MVC DependencyResolver and DefaultControllerFactory
will automatically wire up controllers registered in container (via DependencyResolver
).
something like:
public void Register(IWindsorContainer container)
{
Assembly.GetAssembly(typeof(ControllersRegistrarMarker)).GetExportedTypes()
.Where(IsController)
.Each(type => container.AddComponentLifeStyle(
type.Name.ToLower(),
type,
LifestyleType.Transient));
}
ControllersRegistrarMarker is just an empty class in your Controllers assembly
精彩评论