// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; namespace Microsoft.AspNetCore.Mvc.Controllers { /// /// Discovers controllers from a list of instances. /// public class ControllerFeatureProvider : IApplicationFeatureProvider { private const string ControllerTypeNameSuffix = "Controller"; /// public void PopulateFeature( IEnumerable parts, ControllerFeature feature) { foreach (var part in parts.OfType()) { foreach (var type in part.Types) { if (IsController(type) && !feature.Controllers.Contains(type)) { feature.Controllers.Add(type); } } } } /// /// Determines if a given is a controller. /// /// The candidate. /// true if the type is a controller; otherwise false. protected virtual bool IsController(TypeInfo typeInfo) { if (!typeInfo.IsClass) { return false; } if (typeInfo.IsAbstract) { return false; } // We only consider public top-level classes as controllers. IsPublic returns false for nested // classes, regardless of visibility modifiers if (!typeInfo.IsPublic) { return false; } if (typeInfo.ContainsGenericParameters) { return false; } if (typeInfo.IsDefined(typeof(NonControllerAttribute))) { return false; } if (!typeInfo.Name.EndsWith(ControllerTypeNameSuffix, StringComparison.OrdinalIgnoreCase) && !typeInfo.IsDefined(typeof(ControllerAttribute))) { return false; } return true; } } }