I needed to load dynamically some controllers to the Stankins application .Dynamic like in – written in some text file, then loading them, The best reference was https://www.strathweb.com/2018/04/generic-and-dynamically-generated-controllers-in-asp-net-core-mvc/ . But it was not enough : what I wanted is to write the controller in some text file and compile and load them.
First problem ; What about the dll’s to be loaded ?
I ended up with this code :
var refs=new List<MetadataReference>();
var ourRefs=Assembly.GetEntryAssembly().GetReferencedAssemblies();
foreach(var item in ourRefs)
{
var ass=Assembly.Load(item);
refs.Add(MetadataReference.CreateFromFile(ass.Location));
}
refs.Add(MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location));
//MetadataReference NetStandard = MetadataReference.CreateFromFile(Assembly.Load("netstandard, Version=2.0.0.0").Location);
MetadataReference NetStandard = MetadataReference.CreateFromFile(Assembly.Load("netstandard").Location);
refs.Add(NetStandard);
refs.Add(MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location) );
Second problem: where to put the errors ? The simplest option ( not the best one) is to put as comments to the end of the file – at reloading I will find them and correct
using (var ms = new MemoryStream())
{
var res = compilation.Emit(ms);
if (!res.Success)
{
string diag=string.Join(Environment.NewLine, res.Diagnostics.Select(it=>it.ToString()));
File.AppendAllText(fileName,"/*"+diag+"*/");
return null;
}
}
( Better – to display the error inline…)
Third problem: The controlers are loaded at initial step of configuring .NET MVC Core 2.x , not later. The assembly loader /unloader will come as a feature at .NET Core 3 – so not yet. I figure up that the best solution is to re-load the application
static CancellationTokenSource cancel ;
static bool InternalRequestRestart;
public async static Task Main(string[] args)
{
do{
InternalRequestRestart=false;
cancel= new CancellationTokenSource();
await CreateWebHostBuilder(args).Build().RunAsync(cancel.Token);
await Task.Delay(10);//just waiting some time
Console.WriteLine("restarting");
}while(InternalRequestRestart);
}
public static void Shutdown()
{
InternalRequestRestart=true;
cancel.Cancel();
}
You can find the code source for loading the controllers at https://github.com/ignatandrei/stankins/blob/master/stankinsv2/solution/StankinsV2/StankinsData/GenericControllerFeatureProvider.cs
You can find the code source for restarting the application at https://github.com/ignatandrei/stankins/blob/master/stankinsv2/solution/StankinsV2/StankinsData/Program.cs
You can test the code at https://azurestankins.azurewebsites.net/receiveData ( add a new controller , hit save and then access the route – or swagger at https://azurestankins.azurewebsites.net/swagger/index.html
– or you can try with Docker with
( for linux containers)
docker run -p 5000:5000 ignatandrei/stankins_linux
( for windows containers)
docker run -p 5000:5000 ignatandrei/stankins_linux
( restart docker if any problems)
and access http://localhost:5000/receiveData
That’s all 😉