How to Use AssemblyLoadContext for Isolating Vault Addin Dependencies
Solve version conflicts once and for all.

Autodesk Vault previously allowed add-ins to use NuGet package/assembly versions that differ from the ones bundled with Vault. However, with Autodesk Vault 2026 and the framework upgrade to .NET 8, this no longer worked out of the box and caused version conflicts.
This article will demonstrate one way to resolve the version conflict by isolating the add-in’s dependencies in a separate container using AssemblyLoadContext.
A full sample application can be found on GitHub.
What is AssemblyLoadContext?
- It's the runtime's provider for locating and loading dependencies. Whenever a dependency is loaded, an AssemblyLoadContext instance is invoked to locate it.
- AssemblyLoadContext provides a service of locating, loading, and caching managed assemblies and other dependencies.
- To support dynamic code loading and unloading, it creates an isolated context for loading code and its dependencies in their own AssemblyLoadContext instance.
How to update the add-in?
Add IsolatedIExplorerExtension.cs
This is used as the new entry point into the add-in. It is a wrapper around the IExplorerExtension. It adds additional functionality behind the scenes but still exposes all methods called automatically by Vault.
OnStartup(IApplication application)=>Startup()OnLogOn(IApplication application)=>LogOn()OnLogOff(IApplication application)=>LogOff()OnShutdown(IApplication application)=>Shutdown()CommandSites()=>OnCommandSites()CustomEntityHandlers()=>OnCustomEntityHandlers()DetailTabs()=>OnDetailTabs()DockPanels()=>OnDockPanels()(For Vault 2026+)HiddenCommands()=>OnHiddenCommands()
using Autodesk.Connectivity.Explorer.Extensibility;
using System.ComponentModel;
namespace IsolatedVaultAddin.Isolation;
/// <summary>
/// <see cref="IExplorerExtension" /> is the entry point of the Vault addin.
/// This class is extended to have fully isolated addin dependency container.
/// Inherit this class and add custom logic to overrides of <see cref="Startup" />, <see cref="LogOn" />, <see cref="LogOff" />, <see cref="Shutdown" />, <see cref="OnCommandSites" />, <see cref="OnCustomEntityHandlers" />, <see cref="OnDetailTabs" />, <see cref="OnDockPanels" />, or <see cref="OnHiddenCommands" />.
/// </summary>
public abstract class IsolatedIExplorerExtension : IExplorerExtension
{
#if NETCOREAPP
private object? _isolatedInstance;
#endif
/// <summary>
/// Reference to the parameter in <see cref="IExplorerExtension.OnStartup" />, <see cref="IExplorerExtension.OnLogOn" />, <see cref="IExplorerExtension.OnLogOff" />, <see cref="IExplorerExtension.OnShutdown" />.
/// </summary>
public IApplication Application { get; private set; } = default!;
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnStartup(IApplication application)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnStartup), application);
return;
}
#endif
Application = application;
#if NETCOREAPP
Startup();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
Startup();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnLogOn(IApplication application)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnLogOn), application);
return;
}
#endif
Application = application;
#if NETCOREAPP
LogOn();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
LogOn();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnLogOff(IApplication application)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnLogOff), application);
return;
}
#endif
Application = application;
#if NETCOREAPP
LogOff();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
LogOff();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnShutdown(IApplication application)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnShutdown), application);
return;
}
#endif
Application = application;
#if NETCOREAPP
Shutdown();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
Shutdown();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<CommandSite>? CommandSites()
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
return AddinLoadContext.Invoke<CommandSite>(_isolatedInstance, nameof(CommandSites));
}
#endif
#if NETCOREAPP
return OnCommandSites();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
return OnCommandSites();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<CustomEntityHandler>? CustomEntityHandlers()
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
return AddinLoadContext.Invoke<CustomEntityHandler>(_isolatedInstance, nameof(CustomEntityHandlers));
}
#endif
#if NETCOREAPP
return OnCustomEntityHandlers();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
return OnCustomEntityHandlers();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<DetailPaneTab>? DetailTabs()
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
return AddinLoadContext.Invoke<DetailPaneTab>(_isolatedInstance, nameof(DetailTabs));
}
#endif
#if NETCOREAPP
return OnDetailTabs();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
return OnDetailTabs();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
#if VAULT_HAS_DOCK_PANELS
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<DockPanel>? DockPanels()
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
return AddinLoadContext.Invoke<DockPanel>(_isolatedInstance, nameof(DockPanels));
}
#endif
#if NETCOREAPP
return OnDockPanels();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
return OnDockPanels();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<string>? HiddenCommands()
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
return AddinLoadContext.Invoke<string>(_isolatedInstance, nameof(HiddenCommands));
}
#endif
#if NETCOREAPP
return OnHiddenCommands();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
return OnHiddenCommands();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
/// <summary>
/// Overload this method to execute custom logic when the Vault addin is loaded and <see cref="IExplorerExtension.OnStartup" /> method is executed.
/// </summary>
public abstract void Startup();
/// <summary>
/// Overload this method to execute custom logic when the Vault is logged into and <see cref="IExplorerExtension.OnLogOn" /> method is executed.
/// </summary>
public abstract void LogOn();
/// <summary>
/// Overload this method to execute custom logic when the Vault is logged out of and <see cref="IExplorerExtension.OnLogOff" /> method is executed.
/// </summary>
public abstract void LogOff();
/// <summary>
/// Overload this method to execute custom logic when the Vault addin is unloaded and <see cref="IExplorerExtension.OnShutdown" /> method is executed.
/// </summary>
public abstract void Shutdown();
/// <summary>
/// Overload this method to execute custom logic when the Vault addin ... and <see cref="IExplorerExtension.CommandSites" /> method is executed.
/// </summary>
public abstract IEnumerable<CommandSite>? OnCommandSites();
/// <summary>
/// Overload this method to execute custom logic when the Vault addin ... and <see cref="IExplorerExtension.CustomEntityHandlers" /> method is executed.
/// </summary>
public abstract IEnumerable<CustomEntityHandler>? OnCustomEntityHandlers();
/// <summary>
/// Overload this method to execute custom logic when the Vault addin ... and <see cref="IExplorerExtension.DetailTabs" /> method is executed.
/// </summary>
public abstract IEnumerable<DetailPaneTab>? OnDetailTabs();
#if VAULT_HAS_DOCK_PANELS
/// <summary>
/// Overload this method to execute custom logic when the Vault addin ... and <see cref="IExplorerExtension.DockPanels" /> method is executed.
/// </summary>
public abstract IEnumerable<DockPanel>? OnDockPanels();
#endif
/// <summary>
/// Overload this method to execute custom logic when the Vault addin ... and <see cref="IExplorerExtension.HiddenCommands" /> method is executed.
/// </summary>
public abstract IEnumerable<string>? OnHiddenCommands();
}
Add IsolatedIWebServiceExtension .cs
This is used as the new entry point into the add-in. It is a wrapper around the IWebServiceExtension. It adds additional functionality behind the scenes but still exposes all methods called automatically by Vault.
OnLoad()=>Load()
using Autodesk.Connectivity.WebServices;
using System.ComponentModel;
namespace IsolatedVaultAddin.Isolation;
/// <summary>
/// <see cref="IWebServiceExtension" /> is the entry point of the Vault addin.
/// This class is extended to have fully isolated addin dependency container.
/// Inherit this class and add custom logic to overrides of <see cref="Load" />.
/// </summary>
public abstract class IsolatedIWebServiceExtension : IWebServiceExtension
{
#if NETCOREAPP
private object? _isolatedInstance;
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnLoad()
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnLoad));
return;
}
#endif
#if NETCOREAPP
Load();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
Load();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
/// <summary>
/// Overload this method to execute custom logic when the Vault addin is loaded and <see cref="IWebServiceExtension.OnLoad" /> method is executed.
/// </summary>
public abstract void Load();
}
Add IsolatedIJobHandler.cs
This is used as the new entry point into the add-in. It is a wrapper around the IJobHandler. It adds additional functionality behind the scenes but still exposes all methods called automatically by Vault.
Execute(IJobProcessorServices context, IJob job)=>OnExecute()CanProcess(string jobType)=>OnCanProcess()OnJobProcessorStartup(IJobProcessorServices context)=>JobProcessorStartup()OnJobProcessorShutdown(IJobProcessorServices context)=>JobProcessorShutdown()OnJobProcessorWake(IJobProcessorServices context)=>JobProcessorWake()OnJobProcessorSleep(IJobProcessorServices context)=>JobProcessorSleep()
using Autodesk.Connectivity.Explorer.Extensibility;
using Autodesk.Connectivity.JobProcessor.Extensibility;
using System.ComponentModel;
namespace IsolatedVaultAddin.Isolation;
/// <summary>
/// <see cref="IJobHandler" /> is the entry point of the Vault job processor addin.
/// This class is extended to have fully isolated addin dependency container.
/// Inherit this class and add custom logic to overrides of <see cref="OnExecute" />, <see cref="OnCanProcess" />, <see cref="JobProcessorStartup" />, <see cref="JobProcessorShutdown" />, <see cref="JobProcessorWake" />, or <see cref="JobProcessorSleep" />.
/// </summary>
public abstract class IsolatedIJobHandler : IJobHandler
{
#if NETCOREAPP
private object? _isolatedInstance;
#endif
/// <summary>
/// Reference to the parameter in <see cref="IExplorerExtension.Execute" />, <see cref="IExplorerExtension.OnJobProcessorStartup" />, <see cref="IExplorerExtension.OnJobProcessorShutdown" />, <see cref="IExplorerExtension.OnJobProcessorWake" />, <see cref="IExplorerExtension.OnJobProcessorSleep" />.
/// </summary>
public IJobProcessorServices Context { get; private set; } = default!;
/// <summary>
/// Reference to the parameter in <see cref="IExplorerExtension.Execute" />.
/// </summary>
public IJob Job { get; private set; } = default!;
/// <summary>
/// Reference to the parameter in <see cref="IExplorerExtension.CanProcess" />.
/// </summary>
public string JobType { get; private set; } = default!;
[EditorBrowsable(EditorBrowsableState.Never)]
public JobOutcome Execute(IJobProcessorServices context, IJob job)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
return AddinLoadContext.Invoke(_isolatedInstance, nameof(Execute), context, job);
}
#endif
Context = context;
Job = job;
#if NETCOREAPP
return OnExecute();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
return OnExecute();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool CanProcess(string jobType)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
return AddinLoadContext.Invoke(_isolatedInstance, nameof(CanProcess), jobType);
}
#endif
JobType = jobType;
#if NETCOREAPP
return OnCanProcess();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
return OnCanProcess();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnJobProcessorStartup(IJobProcessorServices context)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnJobProcessorStartup), context);
return;
}
#endif
Context = context;
#if NETCOREAPP
JobProcessorStartup();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
JobProcessorStartup();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnJobProcessorShutdown(IJobProcessorServices context)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnJobProcessorShutdown), context);
return;
}
#endif
Context = context;
#if NETCOREAPP
JobProcessorShutdown();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
JobProcessorShutdown();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnJobProcessorWake(IJobProcessorServices context)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnJobProcessorWake), context);
return;
}
#endif
Context = context;
#if NETCOREAPP
JobProcessorWake();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
JobProcessorWake();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void OnJobProcessorSleep(IJobProcessorServices context)
{
Type currentType = GetType();
#if NETCOREAPP
if (AddinLoadContext.CheckIfCustomContext(currentType) is false)
{
AddinLoadContext dependenciesProvider = AddinLoadContext.GetDependenciesProvider(currentType);
_isolatedInstance = dependenciesProvider.CreateAssemblyInstance(currentType);
AddinLoadContext.Invoke(_isolatedInstance, nameof(OnJobProcessorSleep), context);
return;
}
#endif
Context = context;
#if NETCOREAPP
JobProcessorSleep();
#else
try
{
ResolveHelper.BeginAssemblyResolve(currentType);
JobProcessorSleep();
}
finally
{
ResolveHelper.EndAssemblyResolve();
}
#endif
}
/// <summary>
/// Overload this method to execute custom logic when the Vault job processor is ... and <see cref="IJobHandler.ExecuteAsync" /> method is executed.
/// </summary>
public abstract JobOutcome OnExecute();
/// <summary>
/// Overload this method to execute custom logic when the Vault job processor is ... and <see cref="IJobHandler.CanProcess" /> method is executed.
/// </summary>
public abstract bool OnCanProcess();
/// <summary>
/// Overload this method to execute custom logic when the Vault job processor is ... and <see cref="IJobHandler.OnJobProcessorStartup" /> method is executed.
/// </summary>
public abstract void JobProcessorStartup();
/// <summary>
/// Overload this method to execute custom logic when the Vault job processor is ... and <see cref="IJobHandler.OnJobProcessorShutdown" /> method is executed.
/// </summary>
public abstract void JobProcessorShutdown();
/// <summary>
/// Overload this method to execute custom logic when the Vault job processor is ... and <see cref="IJobHandler.OnJobProcessorWake" /> method is executed.
/// </summary>
public abstract void JobProcessorWake();
/// <summary>
/// Overload this method to execute custom logic when the Vault job processor is ... and <see cref="IJobHandler.OnJobProcessorSleep" /> method is executed.
/// </summary>
public abstract void JobProcessorSleep();
}
Add AddinLoadContext.cs
This is a custom implementation of the AssemblyLoadContext specifically for the format of a Vault add-in.
#if NETCOREAPP
using Autodesk.Connectivity.Explorer.Extensibility;
using Autodesk.Connectivity.JobProcessor.Extensibility;
using Autodesk.Connectivity.WebServices;
using System.Reflection;
using System.Runtime.Loader;
namespace IsolatedVaultAddin.Isolation;
/// <summary>
/// Isolated addin dependency container.
/// </summary>
/// <remarks>
/// References:
/// <a href="https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support">
/// Microsoft/Tutorials/Plugins
/// </a>
/// <a href="https://github.com/dotnet/coreclr/blob/v2.1.0/Documentation/design-docs/assemblyloadcontext.md">
/// GitHub/DotNet/CoreCLR
/// </a>
/// </remarks>
internal sealed class AddinLoadContext : AssemblyLoadContext
{
/// <summary>
/// Add-ins contexts storage.
/// </summary>
private static readonly Dictionary<string, AddinLoadContext> _dependenciesProviders = new(1);
private readonly AssemblyDependencyResolver _resolver;
private const BindingFlags MethodSearchFlags = BindingFlags.Public | BindingFlags.Instance;
private AddinLoadContext(Type type, string addinName) : base(addinName)
{
string addinLocation = type.Assembly.Location;
_resolver = new AssemblyDependencyResolver(addinLocation);
}
/// <summary>
/// Resolve and load dependency any time one is loaded if it exists in the isolated addin dependency container.
/// </summary>
protected override Assembly? Load(AssemblyName assemblyName)
{
string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
return assemblyPath is not null
? LoadFromAssemblyPath(assemblyPath)
: null;
}
/// <summary>
/// Resolve and load unmanaged native dependency any time one is loaded if it exists in the isolated addin dependency container.
/// </summary>
protected override nint LoadUnmanagedDll(string assemblyName)
{
string? assemblyPath = _resolver.ResolveUnmanagedDllToPath(assemblyName);
return assemblyPath is not null
? LoadUnmanagedDllFromPath(assemblyPath)
: nint.Zero;
}
/// <summary>
/// Determine if the <see cref="AssemblyLoadContext" /> is custom or still the default context.
/// </summary>
public static bool CheckIfCustomContext(Type type)
{
AssemblyLoadContext? currentContext = GetLoadContext(type.Assembly);
return currentContext != Default;
}
/// <summary>
/// Get or create a new isolated context for the type.
/// </summary>
public static AddinLoadContext GetDependenciesProvider(Type type)
{
// Assembly location used as context name and the unique provider key.
string addinRoot = System.IO.Path.GetDirectoryName(type.Assembly.Location)!;
if (_dependenciesProviders.TryGetValue(addinRoot, out var provider))
{
return provider;
}
string addinName = System.IO.Path.GetFileName(addinRoot);
provider = new AddinLoadContext(type, addinName);
_dependenciesProviders.Add(addinRoot, provider);
return provider;
}
/// <summary>
/// Create new instance in the separated context.
/// </summary>
public object CreateAssemblyInstance(Type type)
{
string assemblyLocation = type.Assembly.Location;
Assembly assembly = LoadFromAssemblyPath(assemblyLocation);
return assembly.CreateInstance(type.FullName!)!;
}
/// <summary>
/// Execute <see cref="IExplorerExtension.OnStartup" />, <see cref="IExplorerExtension.OnLogOn" />, <see cref="IExplorerExtension.OnLogOff" />, <see cref="IExplorerExtension.OnShutdown" /> methods in the isolated context.
/// </summary>
/// <remarks>
/// Matches parameter format of <see cref="IExplorerExtension.OnStartup" />, <see cref="IExplorerExtension.OnLogOn" />, <see cref="IExplorerExtension.OnLogOff" />, <see cref="IExplorerExtension.OnShutdown" /> methods.
/// </remarks>
public static void Invoke(object instance, string methodName, IApplication application)
{
Type instanceType = instance.GetType();
Type[] methodParameterTypes =
[
typeof(IApplication)
];
object[] methodParameters =
[
application
];
MethodInfo method = instanceType.GetMethod(methodName, MethodSearchFlags, null, methodParameterTypes, null)!;
_ = method.Invoke(instance, methodParameters)!;
}
/// <summary>
/// Execute <see cref="IJobHandler.OnJobProcessorStartup" />, <see cref="IJobHandler.OnJobProcessorShutdown" />, <see cref="IJobHandler.OnJobProcessorWake" />, <see cref="IJobHandler.OnJobProcessorSleep" /> methods in the isolated context.
/// </summary>
/// <remarks>
/// Matches parameter format of <see cref="IJobHandler.OnJobProcessorStartup" />, <see cref="IJobHandler.OnJobProcessorShutdown" />, <see cref="IJobHandler.OnJobProcessorWake" />, <see cref="IJobHandler.OnJobProcessorSleep" /> methods.
/// </remarks>
public static void Invoke(object instance, string methodName, IJobProcessorServices context)
{
Type instanceType = instance.GetType();
Type[] methodParameterTypes =
[
typeof(IJobProcessorServices)
];
object[] methodParameters =
[
context!
];
MethodInfo method = instanceType.GetMethod(methodName, MethodSearchFlags, null, methodParameterTypes, null)!;
_ = method.Invoke(instance, methodParameters)!;
}
/// <summary>
/// Execute <see cref="IJobHandler.Execute" /> method in the isolated context.
/// </summary>
/// <remarks>
/// Matches parameter format of <see cref="IJobHandler.Execute" /> method.
/// </remarks>
public static JobOutcome Invoke(object instance, string methodName, IJobProcessorServices context, IJob job)
{
Type instanceType = instance.GetType();
Type[] methodParameterTypes =
[
typeof(IJobProcessorServices),
typeof(IJob)
];
object[] methodParameters =
[
context!,
job!
];
MethodInfo method = instanceType.GetMethod(methodName, MethodSearchFlags, null, methodParameterTypes, null)!;
return (JobOutcome)method.Invoke(instance, methodParameters)!;
}
/// <summary>
/// Execute <see cref="IJobHandler.CanProcess" /> method in the isolated context.
/// </summary>
/// <remarks>
/// Matches parameter format of <see cref="IJobHandler.CanProcess" /> method.
/// </remarks>
public static bool Invoke(object instance, string methodName, string jobType)
{
Type instanceType = instance.GetType();
Type[] methodParameterTypes =
[
typeof(string)
];
object[] methodParameters =
[
jobType
];
MethodInfo method = instanceType.GetMethod(methodName, MethodSearchFlags, null, methodParameterTypes, null)!;
return (bool)method.Invoke(instance, methodParameters)!;
}
/// <summary>
/// Execute <see cref="IWebServiceExtension.OnLoad" /> method in the isolated context.
/// </summary>
/// <remarks>
/// Matches parameter format of <see cref="IWebServiceExtension.OnLoad" /> method.
/// </remarks>
public static void Invoke(object instance, string methodName)
{
Type instanceType = instance.GetType();
MethodInfo method = instanceType.GetMethod(methodName, MethodSearchFlags, null, [], null)!;
_ = method.Invoke(instance, [])!;
}
/// <summary>
/// Execute <see cref="IExplorerExtension.CommandSites" /> method in the isolated context.
/// </summary>
/// <remarks>
/// Matches parameter format of <see cref="IExplorerExtension.CommandSites" /> method.
/// </remarks>
public static IEnumerable<T>? Invoke<T>(object instance, string methodName)
{
Type instanceType = instance.GetType();
MethodInfo method = instanceType.GetMethod(methodName, MethodSearchFlags, null, [], null)!;
return (IEnumerable<T>?)method.Invoke(instance, [])!;
}
}
#endif
Add ResolveHelper.cs
This is a helper class used to resolve conflicting versions of a dependency.
using System.Reflection;
#if NETCOREAPP
using System.Runtime.Loader;
#endif
namespace IsolatedVaultAddin.Isolation;
/// <summary>
/// Used to resolve conflicting versions of a dependency.
/// </summary>
public static class ResolveHelper
{
private static string? _moduleDirectory;
private static object? _domainResolvers;
/// <summary>
/// Subscribes the current domain to resolve dependencies for the type.
/// </summary>
/// <typeparam name="T">
/// Type, to search for dependencies in the directory where this type is defined.
/// </typeparam>
/// <remarks>
/// Dependencies are searched in a directory of the specified type.
/// At the time of dependency resolution, all other dependency resolution methods for the domain are disabled,
/// this requires calling <see cref="EndAssemblyResolve" /> immediately after executing user code where dependency failures occur.
/// </remarks>
public static void BeginAssemblyResolve<T>()
{
BeginAssemblyResolve(typeof(T));
}
/// <summary>
/// Subscribes the current domain to resolve dependencies for the type.
/// </summary>
/// <param name="type">
/// Type, to search for dependencies in the directory where this type is defined.
/// </param>
/// <remarks>
/// Dependencies are searched in a directory of the specified type.
/// At the time of dependency resolution, all other dependency resolution methods for the domain are disabled,
/// this requires calling <see cref="EndAssemblyResolve" /> immediately after executing user code where dependency failures occur.
/// </remarks>
public static void BeginAssemblyResolve(Type type)
{
if (_domainResolvers is not null)
return;
if (type.Module.FullyQualifiedName == "<Unknown>")
return;
#if NETCOREAPP
var loadContextType = typeof(AssemblyLoadContext);
var resolversField = loadContextType.GetField("AssemblyResolve", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)!;
var resolvers = resolversField.GetValue(null);
resolversField.SetValue(null, null);
#else
var domainType = AppDomain.CurrentDomain.GetType();
var resolversField = domainType.GetField("_AssemblyResolve", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)!;
var resolvers = resolversField.GetValue(AppDomain.CurrentDomain);
resolversField.SetValue(AppDomain.CurrentDomain, null);
#endif
_domainResolvers = resolvers;
_moduleDirectory = System.IO.Path.GetDirectoryName(type.Module.FullyQualifiedName);
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
}
/// <summary>
/// Unsubscribes the current domain to resolve dependencies for the type.
/// </summary>
public static void EndAssemblyResolve()
{
if (_domainResolvers is null)
return;
#if NETCOREAPP
var loadContextType = typeof(AssemblyLoadContext);
var resolversField = loadContextType.GetField("AssemblyResolve", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)!;
resolversField.SetValue(null, _domainResolvers);
#else
var domainType = AppDomain.CurrentDomain.GetType();
var resolversField = domainType.GetField("_AssemblyResolve", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)!;
resolversField.SetValue(AppDomain.CurrentDomain, _domainResolvers);
#endif
_domainResolvers = null;
_moduleDirectory = null;
AppDomain.CurrentDomain.AssemblyResolve -= OnAssemblyResolve;
}
private static Assembly? OnAssemblyResolve(object? sender, ResolveEventArgs args)
{
string? assemblyName = new AssemblyName(args.Name).Name;
string assemblyPath = System.IO.Path.Combine(_moduleDirectory!, $"{assemblyName}.dll");
if (System.IO.File.Exists(assemblyPath) is false)
return null;
return Assembly.LoadFrom(assemblyPath);
}
}
Update Project (.csproj) File
- Must set
PrivatetoFalseon Vault-related assembly file reference. - Replace
VaultVersionvalue of2026with the version of Vault being referenced.
<!-- Custom Variable -->
<PropertyGroup>
<VaultVersion>2026</VaultVersion>
</PropertyGroup>
<PropertyGroup Condition="$(VaultVersion) >= 2026">
<DefineConstants>$(DefineConstants);VAULT_HAS_DOCK_PANELS</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="Autodesk.Connectivity.Explorer.Extensibility">
<HintPath>$(ProgramFiles)\Autodesk\Vault Client $(VaultVersion)\Explorer\Autodesk.Connectivity.Explorer.Extensibility.dll</HintPath>
<!-- Required For Isolated Addin -->
<Private>False</Private>
</Reference>
<Reference Include="Autodesk.Connectivity.Extensibility.Framework">
<HintPath>$(ProgramFiles)\Autodesk\Vault Client $(VaultVersion)\Explorer\Autodesk.Connectivity.Extensibility.Framework.dll</HintPath>
<!-- Required For Isolated Addin -->
<Private>False</Private>
</Reference>
<Reference Include="Autodesk.Connectivity.JobProcessor.Extensibility">
<HintPath>$(ProgramFiles)\Autodesk\Vault Client $(VaultVersion)\Explorer\Autodesk.Connectivity.JobProcessor.Extensibility.dll</HintPath>
<!-- Required For Isolated Addin -->
<Private>False</Private>
</Reference>
<Reference Include="Autodesk.Connectivity.WebServices">
<HintPath>$(ProgramFiles)\Autodesk\Vault Client $(VaultVersion)\Explorer\Autodesk.Connectivity.WebServices.dll</HintPath>
<!-- Required For Isolated Addin -->
<Private>False</Private>
</Reference>
<Reference Include="Autodesk.DataManagement.Client.Framework">
<HintPath>$(ProgramFiles)\Autodesk\Vault Client $(VaultVersion)\Explorer\Autodesk.DataManagement.Client.Framework.dll</HintPath>
<!-- Required For Isolated Addin -->
<Private>False</Private>
</Reference>
<Reference Include="Autodesk.DataManagement.Client.Framework.Vault">
<HintPath>$(ProgramFiles)\Autodesk\Vault Client $(VaultVersion)\Explorer\Autodesk.DataManagement.Client.Framework.Vault.dll</HintPath>
<!-- Required For Isolated Addin -->
<Private>False</Private>
</Reference>
</ItemGroup>
Notes
- This add-in format is compatible with Vault versions using .NET Framework 4.8 or .NET 8.
References
- Microsoft Learn - System.Runtime.Loader.AssemblyLoadContext
- GitHub - dotnet - AssemblyLoadContext.md



