Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/aspnetwebstack.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/System.Web.Mvc/DefaultControllerFactory.cs')
-rw-r--r--src/System.Web.Mvc/DefaultControllerFactory.cs294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/System.Web.Mvc/DefaultControllerFactory.cs b/src/System.Web.Mvc/DefaultControllerFactory.cs
new file mode 100644
index 00000000..8f67ca52
--- /dev/null
+++ b/src/System.Web.Mvc/DefaultControllerFactory.cs
@@ -0,0 +1,294 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Web.Mvc.Properties;
+using System.Web.Routing;
+using System.Web.SessionState;
+
+namespace System.Web.Mvc
+{
+ public class DefaultControllerFactory : IControllerFactory
+ {
+ private static readonly ConcurrentDictionary<Type, SessionStateBehavior> _sessionStateCache = new ConcurrentDictionary<Type, SessionStateBehavior>();
+ private static ControllerTypeCache _staticControllerTypeCache = new ControllerTypeCache();
+ private IBuildManager _buildManager;
+ private IResolver<IControllerActivator> _activatorResolver;
+ private IControllerActivator _controllerActivator;
+ private ControllerBuilder _controllerBuilder;
+ private ControllerTypeCache _instanceControllerTypeCache;
+
+ public DefaultControllerFactory()
+ : this(null, null, null)
+ {
+ }
+
+ public DefaultControllerFactory(IControllerActivator controllerActivator)
+ : this(controllerActivator, null, null)
+ {
+ }
+
+ internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)
+ {
+ if (controllerActivator != null)
+ {
+ _controllerActivator = controllerActivator;
+ }
+ else
+ {
+ _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
+ () => null,
+ new DefaultControllerActivator(dependencyResolver),
+ "DefaultControllerFactory constructor");
+ }
+ }
+
+ private IControllerActivator ControllerActivator
+ {
+ get
+ {
+ if (_controllerActivator != null)
+ {
+ return _controllerActivator;
+ }
+ _controllerActivator = _activatorResolver.Current;
+ return _controllerActivator;
+ }
+ }
+
+ internal IBuildManager BuildManager
+ {
+ get
+ {
+ if (_buildManager == null)
+ {
+ _buildManager = new BuildManagerWrapper();
+ }
+ return _buildManager;
+ }
+ set { _buildManager = value; }
+ }
+
+ internal ControllerBuilder ControllerBuilder
+ {
+ get { return _controllerBuilder ?? ControllerBuilder.Current; }
+ set { _controllerBuilder = value; }
+ }
+
+ internal ControllerTypeCache ControllerTypeCache
+ {
+ get { return _instanceControllerTypeCache ?? _staticControllerTypeCache; }
+ set { _instanceControllerTypeCache = value; }
+ }
+
+ internal static InvalidOperationException CreateAmbiguousControllerException(RouteBase route, string controllerName, ICollection<Type> matchingTypes)
+ {
+ // we need to generate an exception containing all the controller types
+ StringBuilder typeList = new StringBuilder();
+ foreach (Type matchedType in matchingTypes)
+ {
+ typeList.AppendLine();
+ typeList.Append(matchedType.FullName);
+ }
+
+ string errorText;
+ Route castRoute = route as Route;
+ if (castRoute != null)
+ {
+ errorText = String.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_ControllerNameAmbiguous_WithRouteUrl,
+ controllerName, castRoute.Url, typeList);
+ }
+ else
+ {
+ errorText = String.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_ControllerNameAmbiguous_WithoutRouteUrl,
+ controllerName, typeList);
+ }
+
+ return new InvalidOperationException(errorText);
+ }
+
+ public virtual IController CreateController(RequestContext requestContext, string controllerName)
+ {
+ if (requestContext == null)
+ {
+ throw new ArgumentNullException("requestContext");
+ }
+ if (String.IsNullOrEmpty(controllerName))
+ {
+ throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
+ }
+ Type controllerType = GetControllerType(requestContext, controllerName);
+ IController controller = GetControllerInstance(requestContext, controllerType);
+ return controller;
+ }
+
+ protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
+ {
+ if (controllerType == null)
+ {
+ throw new HttpException(404,
+ String.Format(
+ CultureInfo.CurrentCulture,
+ MvcResources.DefaultControllerFactory_NoControllerFound,
+ requestContext.HttpContext.Request.Path));
+ }
+ if (!typeof(IController).IsAssignableFrom(controllerType))
+ {
+ throw new ArgumentException(
+ String.Format(
+ CultureInfo.CurrentCulture,
+ MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase,
+ controllerType),
+ "controllerType");
+ }
+ return ControllerActivator.Create(requestContext, controllerType);
+ }
+
+ protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
+ {
+ if (controllerType == null)
+ {
+ return SessionStateBehavior.Default;
+ }
+
+ return _sessionStateCache.GetOrAdd(
+ controllerType,
+ type =>
+ {
+ var attr = type.GetCustomAttributes(typeof(SessionStateAttribute), inherit: true)
+ .OfType<SessionStateAttribute>()
+ .FirstOrDefault();
+
+ return (attr != null) ? attr.Behavior : SessionStateBehavior.Default;
+ });
+ }
+
+ protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)
+ {
+ if (String.IsNullOrEmpty(controllerName))
+ {
+ throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
+ }
+
+ // first search in the current route's namespace collection
+ object routeNamespacesObj;
+ Type match;
+ if (requestContext != null && requestContext.RouteData.DataTokens.TryGetValue("Namespaces", out routeNamespacesObj))
+ {
+ IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;
+ if (routeNamespaces != null && routeNamespaces.Any())
+ {
+ HashSet<string> namespaceHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);
+ match = GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, namespaceHash);
+
+ // the UseNamespaceFallback key might not exist, in which case its value is implicitly "true"
+ if (match != null || false.Equals(requestContext.RouteData.DataTokens["UseNamespaceFallback"]))
+ {
+ // got a match or the route requested we stop looking
+ return match;
+ }
+ }
+ }
+
+ // then search in the application's default namespace collection
+ if (ControllerBuilder.DefaultNamespaces.Count > 0)
+ {
+ HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
+ match = GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, namespaceDefaults);
+ if (match != null)
+ {
+ return match;
+ }
+ }
+
+ // if all else fails, search every namespace
+ return GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, null /* namespaces */);
+ }
+
+ private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
+ {
+ // Once the master list of controllers has been created we can quickly index into it
+ ControllerTypeCache.EnsureInitialized(BuildManager);
+
+ ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
+ switch (matchingTypes.Count)
+ {
+ case 0:
+ // no matching types
+ return null;
+
+ case 1:
+ // single matching type
+ return matchingTypes.First();
+
+ default:
+ // multiple matching types
+ throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);
+ }
+ }
+
+ public virtual void ReleaseController(IController controller)
+ {
+ IDisposable disposable = controller as IDisposable;
+ if (disposable != null)
+ {
+ disposable.Dispose();
+ }
+ }
+
+ SessionStateBehavior IControllerFactory.GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
+ {
+ if (requestContext == null)
+ {
+ throw new ArgumentNullException("requestContext");
+ }
+ if (String.IsNullOrEmpty(controllerName))
+ {
+ throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
+ }
+
+ Type controllerType = GetControllerType(requestContext, controllerName);
+ return GetControllerSessionBehavior(requestContext, controllerType);
+ }
+
+ private class DefaultControllerActivator : IControllerActivator
+ {
+ private Func<IDependencyResolver> _resolverThunk;
+
+ public DefaultControllerActivator()
+ : this(null)
+ {
+ }
+
+ public DefaultControllerActivator(IDependencyResolver resolver)
+ {
+ if (resolver == null)
+ {
+ _resolverThunk = () => DependencyResolver.Current;
+ }
+ else
+ {
+ _resolverThunk = () => resolver;
+ }
+ }
+
+ public IController Create(RequestContext requestContext, Type controllerType)
+ {
+ try
+ {
+ return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException(
+ String.Format(
+ CultureInfo.CurrentCulture,
+ MvcResources.DefaultControllerFactory_ErrorCreatingController,
+ controllerType),
+ ex);
+ }
+ }
+ }
+ }
+}