C
C#13mo ago
sir loin

❔ Migrate AppDomain (.net framework) to AssemblyLoadContext (.net core)

I need help converting this code to the .net core equivalent by using AppDomain here, ensured that the code is running in their own domains. However, by migrating the app to .net core (for MANY reasons), AppDomain becomes unusable. I've heard that using AssemblyLoadContext is the best (native) alternative. How could I migrate properly?
var setup = new AppDomainSetup
{
ApplicationName = $"{Name} {Id}",
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true,
DisallowBindingRedirects = true
};

var scriptDomain = AppDomain.CreateDomain(setup.ApplicationName, null, setup, new PermissionSet(PermissionState.Unrestricted));

ScriptProvider<TScript> scriptProvider;
try
{
var scriptProviderHandle = Activator.CreateInstanceFrom(scriptDomain,
typeof(ScriptProvider<TScript>).Assembly.ManifestModule.FullyQualifiedName,
typeof(ScriptProvider<TScript>).FullName);

scriptProvider = (ScriptProvider<TScript>)scriptProviderHandle.Unwrap();
scriptProvider.Initialize(assemblyPath, ScriptTypeName);
}
catch
{
AppDomain.Unload(scriptDomain);
throw;
}

if (appDomain != null)
{
Debug.Print($"{nameof(Scripting)}: Unloading domain {appDomain.FriendlyName}");
AppDomain.Unload(appDomain);
}
appDomain = scriptDomain;

return scriptProvider;
var setup = new AppDomainSetup
{
ApplicationName = $"{Name} {Id}",
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true,
DisallowBindingRedirects = true
};

var scriptDomain = AppDomain.CreateDomain(setup.ApplicationName, null, setup, new PermissionSet(PermissionState.Unrestricted));

ScriptProvider<TScript> scriptProvider;
try
{
var scriptProviderHandle = Activator.CreateInstanceFrom(scriptDomain,
typeof(ScriptProvider<TScript>).Assembly.ManifestModule.FullyQualifiedName,
typeof(ScriptProvider<TScript>).FullName);

scriptProvider = (ScriptProvider<TScript>)scriptProviderHandle.Unwrap();
scriptProvider.Initialize(assemblyPath, ScriptTypeName);
}
catch
{
AppDomain.Unload(scriptDomain);
throw;
}

if (appDomain != null)
{
Debug.Print($"{nameof(Scripting)}: Unloading domain {appDomain.FriendlyName}");
AppDomain.Unload(appDomain);
}
appDomain = scriptDomain;

return scriptProvider;
5 Replies
Mayor McCheese
Mayor McCheese13mo ago
Create a .NET Core application with plugins - .NET
Learn how to create a .NET Core application that supports plugins.
sir loin
sir loinOP13mo ago
the main issue here is creating an isolated instance of ScriptProvider
var assemblyPath = $"{CompiledScriptsPath}/{HashHelper.GetMd5(Name + Environment.TickCount)}.dll";
ScriptCompiler.Compile(SourcePaths, assemblyPath, ReferencedAssemblies);

var scriptLoadContext = new AssemblyLoadContext($"{Name} {Id}", true);
Debug.Print($"{nameof(Scripting)}: Loading AssemblyLoadContext {scriptLoadContext.Name}");

ScriptProvider<TScript> scriptProvider;
try
{
var type = scriptLoadContext.LoadFromAssemblyPath(typeof(ScriptProvider<TScript>).Assembly.Location).GetType(typeof(ScriptProvider<TScript>).FullName);
scriptProvider = (ScriptProvider<TScript>)Activator.CreateInstance(type);
scriptProvider?.Initialize(assemblyPath, ScriptTypeName);
}
catch
{
scriptLoadContext.Unload();
throw;
}

if (assemblyLoadContext != null)
{
Debug.Print($"{nameof(Scripting)}: Unloading AssemblyLoadContext {assemblyLoadContext.Name}");
assemblyLoadContext?.Unload();
}
assemblyLoadContext = scriptLoadContext;

return scriptProvider;
var assemblyPath = $"{CompiledScriptsPath}/{HashHelper.GetMd5(Name + Environment.TickCount)}.dll";
ScriptCompiler.Compile(SourcePaths, assemblyPath, ReferencedAssemblies);

var scriptLoadContext = new AssemblyLoadContext($"{Name} {Id}", true);
Debug.Print($"{nameof(Scripting)}: Loading AssemblyLoadContext {scriptLoadContext.Name}");

ScriptProvider<TScript> scriptProvider;
try
{
var type = scriptLoadContext.LoadFromAssemblyPath(typeof(ScriptProvider<TScript>).Assembly.Location).GetType(typeof(ScriptProvider<TScript>).FullName);
scriptProvider = (ScriptProvider<TScript>)Activator.CreateInstance(type);
scriptProvider?.Initialize(assemblyPath, ScriptTypeName);
}
catch
{
scriptLoadContext.Unload();
throw;
}

if (assemblyLoadContext != null)
{
Debug.Print($"{nameof(Scripting)}: Unloading AssemblyLoadContext {assemblyLoadContext.Name}");
assemblyLoadContext?.Unload();
}
assemblyLoadContext = scriptLoadContext;

return scriptProvider;
casting ScriptProvider causes the weird ambiguity error, and it doesn't inherit from anything
Mayor McCheese
Mayor McCheese13mo ago
Give me a bit to look on my pc having trouble reading on my phone
reflectronic
reflectronic13mo ago
when you do scriptLoadContext.LoadFromAssemblyPath you load an entirely separate verion of ScriptProvider<TScript> at runtime. because it is a different type, the cast does not work AssemblyLoadContexts are isolated. this is the feature that they provide--that different AssemblyLoadContexts can load any set of assemblies without interfering with each other hence, the ScriptProvider<TScript> which is loaded into AssemblyLoadContext.Default is different from the ScriptProvider<TScript> which is loaded into scriptLoadContext. in this case, the two types really are identical, but not in general--for example, it's possible to have loaded different versions of the same assembly (in which case they wouldn't neccessarily be identical) what you want to do is share the already loaded assembly with the new AssemblyLoadContext instead of loading it again. this is possible, and it is described in the documentation https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/understanding-assemblyloadcontext#shared-dependencies (i'm assuming ScriptProvider<TScript> is some kind of shared base class, though i am not quite sure) the sharing is very simple--you just return the existing typeof(ScriptProvider<TScript>) that you have in the override for the loading algorithm of course, the next section is about "Type-conversion issues" and ways to debug them, which sounds exactly like what you are facing
Accord
Accord13mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server