Skip to content

Instantly share code, notes, and snippets.

@davidfowl
Last active October 9, 2023 12:30
Show Gist options
  • Save davidfowl/46f470e79e23fe393e48aa4e34704357 to your computer and use it in GitHub Desktop.
Save davidfowl/46f470e79e23fe393e48aa4e34704357 to your computer and use it in GitHub Desktop.
Dynamically loading a controller
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives;
namespace WebApplication26
{
// An application part that can dynamically add types. It also implements IActionDescriptorChangeProvider in order to
// allow triggering when MVC should observe these changes
public class DynamicApplicationPart : ApplicationPart, IApplicationPartTypeProvider, IActionDescriptorChangeProvider
{
private readonly List<TypeInfo> _types = new();
private CancellationTokenSource _cts = new();
public void AddType(Type type)
{
_types.Add(type.GetTypeInfo());
}
public void Commit()
{
var old = _cts;
_cts = new CancellationTokenSource();
if (old != null)
{
// Tell MVC we changed things
old.Cancel();
}
}
public IChangeToken GetChangeToken()
{
return new CancellationChangeToken(_cts.Token);
}
public IEnumerable<TypeInfo> Types => _types;
public override string Name => "Name";
}
public class Startup
{
private readonly DynamicApplicationPart Part = new DynamicApplicationPart();
public void ConfigureServices(IServiceCollection services)
{
var builder = services.AddControllers();
builder.PartManager.ApplicationParts.Clear();
builder.PartManager.ApplicationParts.Add(Part);
services.AddSingleton<IActionDescriptorChangeProvider>(Part);
async Task MakeControllerAvailable()
{
// The route will be visible in 5 seconds
await Task.Delay(5000);
Part.AddType(typeof(HomeController));
Part.Commit();
}
_ = MakeControllerAvailable();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
public class HomeController
{
[HttpGet("/")]
public string Hello() => "Hello MVC";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment