ASP.Net Core 在运行时注册控制器
Posted
技术标签:
【中文标题】ASP.Net Core 在运行时注册控制器【英文标题】:ASP.Net Core register Controller at runtime 【发布时间】:2018-02-19 18:01:58 【问题描述】:我在问自己是否可以在运行时加载带有Controller
s 的 DLL 并使用它。
我发现的唯一解决方案是通过ApplicationPart
在StartUp
上添加程序集:
var builder = services.AddMvc();
builder.AddApplicationPart(
AssemblyLoadContext.Default.LoadFromAssemblyPath(
@"PATH\ExternalControllers.dll"
));
有谁知道是否可以随时注册Controller
,因为该解决方案的问题是,当您想添加另一个包含Controller
s 的DLL 时,您必须重新启动WebService
.如果您可以随时添加它们并在应用程序中随时注册它们,那就太好了。
【问题讨论】:
例如,当我想编写一个基于插件的 WebAPI 时,您可以通过简单地将 DLL 添加到文件夹中来修改 WebAPI,然后抓取它并将其加载到 WebAPI 中。这样 WebAPI 是超级动态的,而原始的 WebAPI 是愚蠢的。它通过每个插件提高了他的智力。 而重启应用的问题是什么? 问题是@poke 在生产中重新启动它有点烦人。我的意思是它没有没有这个功能那么糟糕,但如果它可以在没有重新启动的情况下制作,那将是完美的。 那你就倒霉了。标准的依赖注入系统不允许您在实现服务集合后更改它。因此,您必须为此使用不同的 DI 容器,以便以后进行修改(或添加 DI 模块;我相信 Autofac 会这样做)。那时,您可能已经在复杂性方面非常深入,所以我真的不确定这是否值得。 – 您是否考虑过使用多个独立的 Web 应用程序? @ChrisPratt 如果您正在构建一个可重用的框架,那么在某些情况下,您希望使用可从调用程序集配置的通用参数动态创建控制器。 【参考方案1】:现在可以在 .net core 2.0+ 上实现这一点
请看代码ActionDescriptorCollectionProvider.cs:
public ActionDescriptorCollectionProvider(
IEnumerable<IActionDescriptorProvider> actionDescriptorProviders,
IEnumerable<IActionDescriptorChangeProvider> actionDescriptorChangeProviders)
_actionDescriptorProviders = actionDescriptorProviders
.OrderBy(p => p.Order)
.ToArray();
_actionDescriptorChangeProviders = actionDescriptorChangeProviders.ToArray();
ChangeToken.OnChange(
GetCompositeChangeToken,
UpdateCollection);
第一步:实现IActionDescriptorChangeProvider类:
public class MyActionDescriptorChangeProvider : IActionDescriptorChangeProvider
public static MyActionDescriptorChangeProvider Instance get; = new MyActionDescriptorChangeProvider();
public CancellationTokenSource TokenSource get; private set;
public bool HasChanged get; set;
public IChangeToken GetChangeToken()
TokenSource = new CancellationTokenSource();
return new CancellationChangeToken(TokenSource.Token);
第 2 步:在 Startup.ConfigureServices() 上添加单例:
public void ConfigureServices(IServiceCollection services)
services.AddMvc();
services.AddSingleton<IActionDescriptorChangeProvider>(MyActionDescriptorChangeProvider.Instance);
services.AddSingleton(MyActionDescriptorChangeProvider.Instance);
第三步:在运行时注册控制器:
public class TestController : Controller
private readonly ApplicationPartManager _partManager;
private readonly IHostingEnvironment _hostingEnvironment;
public TestController(
ApplicationPartManager partManager,
IHostingEnvironment env)
_partManager = partManager;
_hostingEnvironment = env;
public IActionResult RegisterControllerAtRuntime()
string assemblyPath = @"PATH\ExternalControllers.dll";
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
if (assembly != null)
_partManager.ApplicationParts.Add(new AssemblyPart(assembly));
// Notify change
MyActionDescriptorChangeProvider.Instance.HasChanged = true;
MyActionDescriptorChangeProvider.Instance.TokenSource.Cancel();
return Content("1");
return Content("0");
【讨论】:
您能解释一下这是如何工作的,或者为什么以及是否有文档?谢谢。 @cnxiaboy 你真的需要对单例 MyActionDescriptorChange() 的 3 个不同引用吗?是否可以删除静态 Instance 属性和 services.AddSingleton(MyActionDescriptorChangeProvider.Instance) 行,然后是 services.AddSingleton现在可以了。
请查看关于how to add dynamic controllers的更新文档:
public class GenericControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
// This is designed to run after the default ControllerTypeProvider,
// so the list of 'real' controllers has already been populated.
foreach (var entityType in EntityTypes.Types)
var typeName = entityType.Name + "Controller";
if (!feature.Controllers.Any(t => t.Name == typeName))
// There's no 'real' controller for this entity, so add the generic version.
var controllerType = typeof(GenericController<>)
.MakeGenericType(entityType.AsType()).GetTypeInfo();
feature.Controllers.Add(controllerType);
【讨论】:
我不明白你的问题? 此控制器注册在设置过程中仅进行一次,并非对控制器的每个请求都正确 是的。我只是在我的本地主机上快速运行,它只被调用了一次。提供者类型注册一次然后多次调用也是有道理的。 如果你想用它来定义包含哪些控制器,哪些不包含,那么在开头使用feature.Controllers.Clear()
,然后循环遍历你想要包含的所有控制器(使用反射)
您如何为您的控制器命名?因为路由是根据类名猜测控制器的。以上是关于ASP.Net Core 在运行时注册控制器的主要内容,如果未能解决你的问题,请参考以下文章
在 2 个控制器 ASP.NET Core 3.1 MVC 之间传递 ID
在 ASP.NET Core Web API 中注册一个新的 DelegatingHandler