Setting up Inversion of Control (IoC) in ASP.NET MVC with Castle Windsor

末鹿安然 提交于 2019-12-01 03:43:31

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!