ASP.NET Core : Add controllers at runtime and detecting changes done by others

Part 1 Adding controllers at runtime

Adding controllers at runtime in ASP.NET Core involves the ApplicationPartManager and IActionDescriptorChangeProvider. Let’s say that we hardcode the creation of the controller


private Assembly CreateController(string name)
             string code = new StringBuilder()
                 .AppendLine("using System;")
                 .AppendLine("using Microsoft.AspNetCore.Mvc;")
                 .AppendLine("namespace TestBlocklyHtml.Controllers")
                 .AppendLine(string.Format("public class {0} : ControllerBase", name))
                 .AppendLine(" {")
                 .AppendLine("  public string Get()")
                 .AppendLine("  {")
                 .AppendLine(string.Format("return \"test - {0}\";", name))
                 .AppendLine("  }")
                 .AppendLine(" }")

            var codeString = SourceText.From(code);
             var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3);

            var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(codeString, options);

            var references = new MetadataReference[]

            var codeRun = CSharpCompilation.Create("Hello.dll",
                 new[] { parsedSyntaxTree },
                 references: references,
                 options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
                     optimizationLevel: OptimizationLevel.Release,
                     assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default));
             using (var peStream = new MemoryStream())
                 if (!codeRun.Emit(peStream).Success)
                     return null;
                 return Assembly.Load(peStream.ToArray());



Then we will load into ApplicationParts

        public string AddRuntimeController([FromServices] ApplicationPartManager partManager, [FromServices]MyActionDescriptorChangeProvider provider)
            string name = "andrei" + DateTime.Now.ToString("yyyyMMddHHmmss");
            var ass = CreateController(name);
            if (ass != null)
                partManager.ApplicationParts.Add(new AssemblyPart(ass));
                // Notify change
                provider.HasChanged = true;
                return "api/"+ name;
            throw new Exception("controller not generated");

and the code for is

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);

and it is added to the DI services by


Usually , you do not need Part 2 – if you do not construct something like Blockly for .NET Core (, that needs to see controllers added  by the application

Part 2  Detecting controller added at runtime by others

You usually do not need this – Part 1 is enough.  I need because I do construct something like Blockly for .NET Core (, that needs to see controllers added  by the application.

So we need ActionDescriptorCollectionProvider –  read the remarks at . We can obtain by DI from IActionDescriptorCollectionProvider and convert to ActionDescriptorCollectionProvider

The code is

//in the class , obtained by DI from IActionDescriptorCollectionProvider 
private readonly ActionDescriptorCollectionProvider cp;

internal void registerCallback()
            cp.GetChangeToken().RegisterChangeCallback(a =>
                 //a is your class because of this parameter below

                //do your work
            }, this);


( All code is taken from