/* **************************************************************************** * * Copyright (c) Microsoft Corporation. All rights reserved. * * This software is subject to the Microsoft Public License (Ms-PL). * A copy of the license can be found in the license.htm file included * in this distribution. * * You must not remove this notice, or any other, from this software. * * ***************************************************************************/ namespace System.Web.Mvc { using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; internal sealed class ControllerTypeCache { private Dictionary> _cache; private object _lockObj = new object(); internal int Count { get { int count = 0; foreach (var lookup in _cache.Values) { foreach (var grouping in lookup) { count += grouping.Count(); } } return count; } } public void EnsureInitialized(IBuildManager buildManager) { if (_cache == null) { lock (_lockObj) { if (_cache == null) { List controllerTypes = GetAllControllerTypes(buildManager); var groupedByName = controllerTypes.GroupBy( t => t.Name.Substring(0, t.Name.Length - "Controller".Length), StringComparer.OrdinalIgnoreCase); _cache = groupedByName.ToDictionary( g => g.Key, g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); } } } } private static List GetAllControllerTypes(IBuildManager buildManager) { // Go through all assemblies referenced by the application and search for // controllers and controller factories. List controllerTypes = new List(); ICollection assemblies = buildManager.GetReferencedAssemblies(); foreach (Assembly assembly in assemblies) { Type[] typesInAsm; try { typesInAsm = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { typesInAsm = ex.Types; } controllerTypes.AddRange(typesInAsm.Where(IsControllerType)); } return controllerTypes; } public IList GetControllerTypes(string controllerName, HashSet namespaces) { List matchingTypes = new List(); ILookup nsLookup; if (_cache.TryGetValue(controllerName, out nsLookup)) { // this friendly name was located in the cache, now cycle through namespaces if (namespaces != null) { foreach (string ns in namespaces) { matchingTypes.AddRange(nsLookup[ns]); } } else { // if the namespaces parameter is null, search *every* namespace foreach (var nsGroup in nsLookup) { matchingTypes.AddRange(nsGroup); } } } return matchingTypes; } internal static bool IsControllerType(Type t) { return t != null && t.IsPublic && t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) && !t.IsAbstract && typeof(IController).IsAssignableFrom(t); } } }