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