# Isolate Autodesk Add-Ins With the 'Isolator.Fody' NuGet Package

Autodesk add-ins previously allowed the use of NuGet package/assembly versions that differ from the ones bundled within the Autodesk software. However, with 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 using the 'Isolator.Fody' NuGet package to automatically isolate the add-in’s dependencies in a separate container using `AssemblyLoadContext`. All it takes is adding the `[Isolator]` attribute to the class.

A full [Inventor](https://github.com/tylerwarner33/autodesk-inventor-assembly-load-context-fody) and [Vault](https://github.com/tylerwarner33/autodesk-vault-assembly-load-context-fody) sample application can be found on GitHub.

Previous articles have explained how to do this by directly modifying the add-in architecture and not referencing an external NuGet package.

## What is [AssemblyLoadContext](https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/understanding-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?

### Update Project (.csproj) File

- Add the `Isolator.Fody` NuGet package reference.
- Add the `WeaverConfiguration` settings with the `SkipIsolator` set to `false` for an isolated AssemblyLoadContext or `true` for the default add-in behavior.

``` xml
<ItemGroup>
	<PackageReference Include="Isolator.Fody" Version="1.0.0">
	  <PrivateAssets>all</PrivateAssets>
	  <IncludeAssets>build; compile</IncludeAssets>
	</PackageReference>
</ItemGroup>

<PropertyGroup>
	<WeaverConfiguration>
		<Weavers>
			<Isolator />
		</Weavers>
	</WeaverConfiguration>
</PropertyGroup>
```

### Update Classes

- Add the `[Isolator]` attribute to classes that need to use the add-in's NuGet package versions instead of Autodesk's bundled versions.
- Do **NOT** add the `[Isolator]` attribute to classes that interact with Autodesk COM objects (ex. `Inventor.Application`, `ButtonDefinition`, ribbon UI code). COM interop requires the code to run in the default `AssemblyLoadContext`; isolating these classes will cause `System.ArgumentException` marshaling errors.
- If a class needs both COM interop and isolated dependencies, keep the COM code in a non-isolated class and delegate the isolated work to a separate `[Isolator]`-marked class.

``` csharp
// CANNOT isolate. Uses Inventor COM objects.
internal class MyButton : Button
{
    protected override void ButtonDefinition_OnExecute(NameValueMap context)
    {
        // Delegate to an isolated class for dependency-specific work.
        AssemblyInspector inspector = new();
        string result = inspector.DoIsolatedWork();
    }
}

// Safe to isolate. No COM interop.
[Isolator]
internal class AssemblyInspector
{
    public string DoIsolatedWork()
    {
        // Uses the add-in's version of Serilog, not Inventor's.
        Serilog.Log.Information("This runs in the isolated context");
        return typeof(Serilog.Log).Assembly.GetName().Version?.ToString() ?? "unknown";
    }
}
```

## Notes

- `<Isolator SkipIsolator='true' />` can replace `<Isolator />` in the project file to temporarily disable isolation for debugging. Since `false` is the default, `<Isolator />` and `<Isolator SkipIsolator='false' />` are equivalent. 
- Any `typeof()` calls for assemblies to be isolated must be placed **inside** the `[Isolator]`-marked class. If a `Type` is passed from a non-isolated class, it will resolve to the default context's version.
- When debugging, Visual Studio may prompt to find source files like `ILTemplate.cs` from a non-existent path (ex. `D:\a\Isolator.Fody\...`). This is the build server path embedded in the library's debug symbols and can be safely dismissed.
- This add-in format is compatible with Inventor versions using .NET Framework 4.8 or .NET 8.  In .NET Framework, `AppDomain` is used instead of `AssemblyLoadContext`.
- This add-in format is compatible and works as an `AppBundle` with the [Automation API](https://aps.autodesk.com/en/docs/design-automation/v3/developers_guide/overview/).

## References

- NuGet Package: [Isolator.Fody](https://www.nuget.org/packages/Isolator.Fody)
- GitHub Repo: [Isolator.Fody](https://github.com/ricaun-io/Isolator.Fody)
- Microsoft Learn - [System.Runtime.Loader.AssemblyLoadContext](https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/understanding-assemblyloadcontext)
- GitHub - dotnet - [AssemblyLoadContext.md](https://github.com/dotnet/coreclr/blob/v2.1.0/Documentation/design-docs/assemblyloadcontext.md)
