I try to implement Generic Controller. So for that I try to use;
IPostConfigureOptions<ApplicationPartManager>
IApplicationFeatureProvider<ControllerFeature>
I use PostConfigureOptions because of I want to discover after built. I cannot use
services.AddMvc().AddRazorRuntimeCompilation().ConfigureApplicationPartManager(m => m.FeatureProviders.Add(new GenericControllerFeatureProvider()));
because it is in Startup, however I register my controller inside my module service builder.
My dependency injection code:
//working
Services.ConfigureOptions(typeof(GenericPageConfigureOptions<,>).MakeGenericType(builder.UserType, t));
//not working
Services.ConfigureOptions(typeof(GenericControllerConfigureOptions<,>).MakeGenericType(builder.UserType, t));
// My IPostOptions implementations
// This is working as expected.
public class GenericPageConfigureOptions<TEntity, TKey> : IPostConfigureOptions<RazorPagesOptions> where TEntity : class where TKey : IEquatable<TKey>
{
public void PostConfigure(string name, RazorPagesOptions options)
{
name = name ?? throw new ArgumentNullException(nameof(name));
options = options ?? throw new ArgumentNullException(nameof(options));
var convention = new GenericPageModelConvention<TEntity, TKey>();
options.Conventions.AddAreaFolderApplicationModelConvention("Identity", "/", pam => convention.Apply(pam));
}
}
//not working
public class GenericControllerConfigureOptions<TEntity, TKey> : IPostConfigureOptions<ApplicationPartManager> where TEntity : class where TKey : IEquatable<TKey>
{
public void PostConfigure(string name, ApplicationPartManager options)
{
name = name ?? throw new ArgumentNullException(nameof(name));
options = options ?? throw new ArgumentNullException(nameof(options));
var provider = new GenericControllerFeatureProvider<TEntity, TKey>();
options.FeatureProviders.Add(provider);
}
}
Finally my feature provider class is looking like that:
public class GenericControllerFeatureProvider<TEntity, TKey> : IApplicationFeatureProvider<ControllerFeature> where TEntity : class where TKey : IEquatable<TKey>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
var candidates = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(x => x.GetCustomAttributes<GeneratedControllerAttribute>().Any());
foreach (var candidate in candidates) {
var typeName = candidate.Name.Remove(candidate.Name.IndexOf("Controller"));
if (!feature.Controllers.Any(t => t.Name == typeName)) {
var defaultUIAttribute = candidate.GetTypeInfo().GetCustomAttribute<GeneratedControllerAttribute>();
var controllerType = defaultUIAttribute.Template.MakeGenericType(typeof(TEntity), typeof(TKey)).GetTypeInfo();
feature.Controllers.Add(controllerType);
}
}
}
}
An example controller:
[GeneratedController(typeof(IdentityController<,>))]
public class IdentityController<TUser, TKey> : Controller
{
private IUserManager<TUser, TKey> _userManager;
public IdentityController(IUserManager<TUser, TKey> userManager)
{
_userManager = userManager;
}
}