using System; using System.Linq; using System.Web.Mvc; using System.Web.Routing; namespace Umbraco.Web.Mvc { /// /// A controller factory which uses an internal list of in order to invoke /// different controller factories dependent upon their implementation of for the current /// request. Allows circumvention of MVC3's singly registered IControllerFactory. /// /// internal class MasterControllerFactory : DefaultControllerFactory { private readonly Func _factoriesAccessor; private FilteredControllerFactoryCollection _factories; /// /// Initializes a new instance of the with a factories accessor. /// /// The factories accessor. public MasterControllerFactory(Func factoriesAccessor) { // note // because the MasterControllerFactory needs to be ctored to be assigned to // ControllerBuilder.Current when setting up Mvc and WebApi, it cannot be ctored by // the IoC container - and yet we don't want that ctor to resolve the factories // as that happen before everything is configured - so, passing a factories // accessor func. _factoriesAccessor = factoriesAccessor; } private IFilteredControllerFactory FactoryForRequest(RequestContext context) { if (_factories == null) _factories = _factoriesAccessor(); return _factories.FirstOrDefault(x => x.CanHandle(context)); } /// /// Creates the specified controller by using the specified request context. /// /// The context of the HTTP request, which includes the HTTP context and route data. /// The name of the controller. /// The controller. /// The parameter is null. /// /// The parameter is null or empty. /// public override IController CreateController(RequestContext requestContext, string controllerName) { var factory = FactoryForRequest(requestContext); return factory != null ? factory.CreateController(requestContext, controllerName) : base.CreateController(requestContext, controllerName); } /// /// Retrieves the controller type for the specified name and request context. /// /// /// /// The controller type. /// /// The context of the HTTP request, which includes the HTTP context and route data. /// The name of the controller. internal Type GetControllerTypeInternal(RequestContext requestContext, string controllerName) { var factory = FactoryForRequest(requestContext); if (factory != null) { //check to see if the factory is of type UmbracoControllerFactory which exposes the GetControllerType method so we don't have to create // an instance of the controller to figure out what it is. This is a work around for not having a breaking change for: // http://issues.umbraco.org/issue/U4-1726 var umbFactory = factory as UmbracoControllerFactory; if (umbFactory != null) { return umbFactory.GetControllerType(requestContext, controllerName); } //we have no choice but to instantiate the controller var instance = factory.CreateController(requestContext, controllerName); return instance?.GetType(); } return GetControllerType(requestContext, controllerName); } /// /// Releases the specified controller. /// /// The controller to release. /// public override void ReleaseController(IController icontroller) { var released = false; var controller = icontroller as Controller; if (controller != null) { var requestContext = controller.ControllerContext.RequestContext; var factory = FactoryForRequest(requestContext); if (factory != null) { factory.ReleaseController(controller); released = true; } } if (released == false) base.ReleaseController(icontroller); } } }