//Source: https://gist.github.com/damianh/5d69be0e3004024f03b6cc876d7b0bd3 using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.Extensions.DependencyInjection; using IMvcCoreBuilder = Microsoft.Extensions.DependencyInjection.IMvcCoreBuilder; namespace HopFrame.Api.Extensions; public static class MvcExtensions { /// /// Finds the appropriate controllers /// /// The manager for the parts /// The controller types that are allowed. public static void UseSpecificControllers(this ApplicationPartManager partManager, params Type[] controllerTypes) { partManager.FeatureProviders.Add(new InternalControllerFeatureProvider()); //partManager.ApplicationParts.Clear(); partManager.ApplicationParts.Add(new SelectedControllersApplicationParts(controllerTypes)); } /// /// Only allow selected controllers /// /// The builder that configures mvc core /// The controller types that are allowed. public static IMvcCoreBuilder UseSpecificControllers(this IMvcCoreBuilder mvcCoreBuilder, params Type[] controllerTypes) => mvcCoreBuilder.ConfigureApplicationPartManager(partManager => partManager.UseSpecificControllers(controllerTypes)); /// /// Only instantiates selected controllers, not all of them. Prevents application scanning for controllers. /// private class SelectedControllersApplicationParts : ApplicationPart, IApplicationPartTypeProvider { public SelectedControllersApplicationParts() { Name = "Only allow selected controllers"; } public SelectedControllersApplicationParts(Type[] types) { Types = types.Select(x => x.GetTypeInfo()).ToArray(); } public override string Name { get; } public IEnumerable Types { get; } } /// /// Ensure that internal controllers are also allowed. The default ControllerFeatureProvider hides internal controllers, but this one allows it. /// private class InternalControllerFeatureProvider : ControllerFeatureProvider { private const string ControllerTypeNameSuffix = "Controller"; /// /// Determines if a given is a controller. The default ControllerFeatureProvider hides internal controllers, but this one allows it. /// /// The candidate. /// true if the type is a controller; otherwise false. protected override bool IsController(TypeInfo typeInfo) { if (!typeInfo.IsClass) { return false; } if (typeInfo.IsAbstract) { return false; } if (typeInfo.ContainsGenericParameters) { return false; } if (typeInfo.IsDefined(typeof(Microsoft.AspNetCore.Mvc.NonControllerAttribute))) { return false; } if (!typeInfo.Name.EndsWith(ControllerTypeNameSuffix, StringComparison.OrdinalIgnoreCase) && !typeInfo.IsDefined(typeof(Microsoft.AspNetCore.Mvc.ControllerAttribute))) { return false; } return true; } } }