1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc {
\r
15 using System.Collections;
\r
16 using System.Collections.Generic;
\r
17 using System.Globalization;
\r
20 using System.Web.Mvc.Resources;
\r
21 using System.Web.Routing;
\r
23 public class DefaultControllerFactory : IControllerFactory {
\r
25 private IBuildManager _buildManager;
\r
26 private ControllerBuilder _controllerBuilder;
\r
27 private ControllerTypeCache _instanceControllerTypeCache;
\r
28 private static ControllerTypeCache _staticControllerTypeCache = new ControllerTypeCache();
\r
30 internal IBuildManager BuildManager {
\r
32 if (_buildManager == null) {
\r
33 _buildManager = new BuildManagerWrapper();
\r
35 return _buildManager;
\r
38 _buildManager = value;
\r
42 internal ControllerBuilder ControllerBuilder {
\r
44 return _controllerBuilder ?? ControllerBuilder.Current;
\r
47 _controllerBuilder = value;
\r
51 internal ControllerTypeCache ControllerTypeCache {
\r
53 return _instanceControllerTypeCache ?? _staticControllerTypeCache;
\r
56 _instanceControllerTypeCache = value;
\r
60 public RequestContext RequestContext {
\r
65 public virtual IController CreateController(RequestContext requestContext, string controllerName) {
\r
66 if (requestContext == null) {
\r
67 throw new ArgumentNullException("requestContext");
\r
69 if (String.IsNullOrEmpty(controllerName)) {
\r
70 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
\r
72 RequestContext = requestContext;
\r
73 Type controllerType = GetControllerType(controllerName);
\r
74 IController controller = GetControllerInstance(controllerType);
\r
78 protected internal virtual IController GetControllerInstance(Type controllerType) {
\r
79 if (controllerType == null) {
\r
80 throw new HttpException(404,
\r
82 CultureInfo.CurrentUICulture,
\r
83 MvcResources.DefaultControllerFactory_NoControllerFound,
\r
84 RequestContext.HttpContext.Request.Path));
\r
86 if (!typeof(IController).IsAssignableFrom(controllerType)) {
\r
87 throw new ArgumentException(
\r
89 CultureInfo.CurrentUICulture,
\r
90 MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase,
\r
95 return (IController)Activator.CreateInstance(controllerType);
\r
97 catch (Exception ex) {
\r
98 throw new InvalidOperationException(
\r
100 CultureInfo.CurrentUICulture,
\r
101 MvcResources.DefaultControllerFactory_ErrorCreatingController,
\r
107 protected internal virtual Type GetControllerType(string controllerName) {
\r
108 if (String.IsNullOrEmpty(controllerName)) {
\r
109 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
\r
112 // first search in the current route's namespace collection
\r
113 object routeNamespacesObj;
\r
115 if (RequestContext != null && RequestContext.RouteData.DataTokens.TryGetValue("Namespaces", out routeNamespacesObj)) {
\r
116 IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;
\r
117 if (routeNamespaces != null) {
\r
118 HashSet<string> nsHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);
\r
119 match = GetControllerTypeWithinNamespaces(controllerName, nsHash);
\r
120 if (match != null) {
\r
126 // then search in the application's default namespace collection
\r
127 HashSet<string> nsDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
\r
128 match = GetControllerTypeWithinNamespaces(controllerName, nsDefaults);
\r
129 if (match != null) {
\r
133 // if all else fails, search every namespace
\r
134 return GetControllerTypeWithinNamespaces(controllerName, null /* namespaces */);
\r
137 private Type GetControllerTypeWithinNamespaces(string controllerName, HashSet<string> namespaces) {
\r
138 // Once the master list of controllers has been created we can quickly index into it
\r
139 ControllerTypeCache.EnsureInitialized(BuildManager);
\r
141 IList<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
\r
142 switch (matchingTypes.Count) {
\r
144 // no matching types
\r
148 // single matching type
\r
149 return matchingTypes[0];
\r
152 // multiple matching types
\r
153 // we need to generate an exception containing all the controller types
\r
154 StringBuilder sb = new StringBuilder();
\r
155 foreach (Type matchedType in matchingTypes) {
\r
157 sb.Append(matchedType.FullName);
\r
159 throw new InvalidOperationException(
\r
161 CultureInfo.CurrentUICulture,
\r
162 MvcResources.DefaultControllerFactory_ControllerNameAmbiguous,
\r
163 controllerName, sb));
\r
167 public virtual void ReleaseController(IController controller) {
\r
168 IDisposable disposable = controller as IDisposable;
\r
169 if (disposable != null) {
\r
170 disposable.Dispose();
\r