| File: Controllers\ControllerFeatureProvider.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.Core\src\Microsoft.AspNetCore.Mvc.Core.csproj (Microsoft.AspNetCore.Mvc.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; namespace Microsoft.AspNetCore.Mvc.Controllers; /// <summary> /// Discovers controllers from a list of <see cref="ApplicationPart"/> instances. /// </summary> public class ControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature> { private const string ControllerTypeNameSuffix = "Controller"; /// <inheritdoc /> public void PopulateFeature( IEnumerable<ApplicationPart> parts, ControllerFeature feature) { foreach (var part in parts.OfType<IApplicationPartTypeProvider>()) { foreach (var type in part.Types) { if (IsController(type) && !feature.Controllers.Contains(type)) { feature.Controllers.Add(type); } } } } /// <summary> /// Determines if a given <paramref name="typeInfo"/> is a controller. /// </summary> /// <param name="typeInfo">The <see cref="TypeInfo"/> candidate.</param> /// <returns><see langword="true" /> if the type is a controller; otherwise <see langword="false" />.</returns> 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; } }