C# 运行时ASP.Net核心注册控制器

C# 运行时ASP.Net核心注册控制器,c#,.net,asp.net-core,asp.net-core-mvc,.net-assembly,C#,.net,Asp.net Core,Asp.net Core Mvc,.net Assembly,我在问自己,是否可以在运行时加载一个包含控制器的DLL并使用它 我找到的唯一解决方案是通过启动上的ApplicationPart添加程序集: var builder = services.AddMvc(); builder.AddApplicationPart( AssemblyLoadContext.Default.LoadFromAssemblyPath( @"PATH\ExternalControllers.dll" )); 有人知道是否可以随时注册控制器,因为该

我在问自己,是否可以在运行时加载一个包含
控制器
的DLL并使用它

我找到的唯一解决方案是通过
启动
上的
ApplicationPart
添加程序集:

var builder = services.AddMvc();
builder.AddApplicationPart(
    AssemblyLoadContext.Default.LoadFromAssemblyPath(
        @"PATH\ExternalControllers.dll"
));
有人知道是否可以随时注册
控制器
,因为该解决方案的问题是,当您要添加另一个包含
控制器
的DLL时,必须重新启动
Web服务
。如果您可以随时添加它们并在应用程序中随时注册它们,那就太好了。

现在这是可能的

请参阅有关以下内容的更新文档:

公共类GenericControllerFeatureProvider:IAApplicationFeatureProvider
{
public void PopulateFeature(IEnumerable parts,ControllerFeature功能)
{
//这是为了在默认ControllerTypeProvider之后运行,
//因此,已经填充了“真实”控制器列表。
foreach(EntityTypes.Types中的var entityType)
{
var typeName=entityType.Name+“控制器”;
如果(!feature.Controllers.Any(t=>t.Name==typeName))
{
//此实体没有“真实”控制器,因此请添加通用版本。
变量控制器类型=类型(GenericController)
.MakeGenericType(entityType.AsType()).GetTypeInfo();
feature.Controllers.Add(controllerType);
}
}
}
}

现在,这在.net core 2.0上是可能的+

请参阅代码:

步骤2:在启动时添加Singleton.ConfigureServices():


例如,当我想编程一个基于插件的WebAPI时,你可以通过简单地向文件夹添加一个DLL来修改WebAPI,然后抓取它并将其加载到WebAPI中。这样一来,WebAPI是超级动态的,而原始WebAPI是愚蠢的。每一个插件都能提高他的智能。重启应用程序的问题是什么?问题是@poke在生产中重启它有点烦人。我的意思是,它没有没有没有这个功能那么糟糕,但是如果它不需要重新启动就可以实现,那就太完美了。那你就太倒霉了。标准依赖项注入系统不允许您在服务集合物化后更改它。因此,您必须为此使用不同的DI容器,以便以后进行修改(或添加DI模块;我相信Autofac可以做到这一点)。在这一点上,你可能已经相当复杂了,所以我真的不确定这是否值得您是否考虑过使用多个独立的web应用程序?@ChrisPratt如果您正在构建一个可重用的框架,那么在某些情况下,您希望使用调用程序集可配置的通用参数动态创建控制器。我不理解您的问题?此控制器注册仅在设置并非所有对控制器的请求都正确是。我只是在本地主机上快速运行了一次,只调用了一次。提供程序类型只注册一次,然后多次调用也是有意义的。如果要使用它来定义包含哪些控制器和不包含哪些控制器,请在开始时使用
feature.controllers.Clear()
,然后循环所有要包含的控制器(使用反射)您如何为控制器命名?因为路由根据类名猜测控制器。你能解释一下这是如何工作的,或者为什么,以及上面是否有文档吗?谢谢。@cnxiaboy您真的需要对singleton MyActionDescriptorChange()进行3种不同的引用吗?是否可以删除静态实例属性和services.AddSingleton(MyActionDescriptorChangeProvider.Instance)行,后面是services.AddSingleton(新的MyActionDescriptorChangeProvider())?
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);
            }
        }
    }
}
    public ActionDescriptorCollectionProvider(
        IEnumerable<IActionDescriptorProvider> actionDescriptorProviders,
        IEnumerable<IActionDescriptorChangeProvider> actionDescriptorChangeProviders)
    {
        _actionDescriptorProviders = actionDescriptorProviders
            .OrderBy(p => p.Order)
            .ToArray();

        _actionDescriptorChangeProviders = actionDescriptorChangeProviders.ToArray();

        ChangeToken.OnChange(
            GetCompositeChangeToken,
            UpdateCollection);
    }
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);
    }
}
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");
    }
}