ASP.Net核心寄存器控制器在运行时

Jon*_*KAS 7 .net c# .net-assembly asp.net-core-mvc asp.net-core

我问自己是否有可能Controller在运行时加载带有s 的DLL 并使用它.

我发现的唯一的解决办法是通过添加组件ApplicationPartStartUp:

var builder = services.AddMvc();
builder.AddApplicationPart(
    AssemblyLoadContext.Default.LoadFromAssemblyPath(
        @"PATH\ExternalControllers.dll"
));
Run Code Online (Sandbox Code Playgroud)

有人知道是否可以随时注册Controller,因为该解决方案的问题是,WebService当你想要添加另一个带有Controllers的DLL时,你必须重新启动它.如果您可以随时添加它们并在应用程序中随时注册它们会很好.

小智 13

现在可以在.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);
    }
Run Code Online (Sandbox Code Playgroud)

第1步:实现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);
    }
}
Run Code Online (Sandbox Code Playgroud)

第2步:在Startup.ConfigureServices()上添加AddSingleton:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IActionDescriptorChangeProvider>(MyActionDescriptorChangeProvider.Instance);
    services.AddSingleton(MyActionDescriptorChangeProvider.Instance);
}
Run Code Online (Sandbox Code Playgroud)

第3步:在运行时注册控制器:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您能解释一下这是如何工作的或为什么以及是否有相关文档吗?谢谢。 (2认同)

Jon*_*ved 10

这是可能的.

请参阅有关如何添加动态控制器的更新文档:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)