This repository demonstrates how to resolve DLL conflicts in Revit plugins by leveraging AppDomain isolation. Specifically, it showcases how to load conflicting assemblies (like Auth0.Client
and its dependencies) in an isolated AppDomain to bypass version constraints imposed by Revit’s runtime. This technique enables you to load and use custom DLL versions independently of Revit’s internal assemblies, ensuring smooth integration and preventing dependency issues.
- AppDomain Isolation: Isolates conflicting DLLs in a separate AppDomain, allowing them to load independently from Revit’s core assemblies.
- Cross-Domain Communication: Uses
MarshalByRefObject
to allow data exchange and method execution between the isolated AppDomain and the default Revit AppDomain. - Dynamic Assembly Loading: Demonstrates how to load assemblies dynamically within the isolated AppDomain, managing dependencies without affecting Revit.
- Seamless UI Integration: Offers a solution for handling UI library conflicts by loading UI components in a separate domain and returning to the Revit context after completion.
Read this article for more over view
-
Creating an Isolated AppDomain: The code sets up a custom AppDomain with a defined setup, including application base and dependency paths.
var domSetup = new AppDomainSetup { ShadowCopyFiles = "ShadowCopied", ShadowCopyDirectories = "ShadowDires", CachePath = Path.GetTempPath(), ApplicationBase = Path.GetDirectoryName(targetDll) }; AppDomain domain = AppDomain.CreateDomain("IsolatedDomain", null, domSetup); Type assemblySandboxType = typeof(T); var assemblySandbox = (T) domain.CreateInstanceAndUnwrap( assemblySandboxType.Assembly.FullName, assemblySandboxType.ToString() ); assemblySandbox.SetDomain(domain);
-
Loading Assemblies in the Isolated Domain: The sample demonstrates how to load assemblies like
Auth0.Client
inside the isolated AppDomain.private string RunWithAppDomain(string dllPath) { var authService = UtilityHelper.LoadAssemblyViaAppDomain<AuthSandbox>(dllPath); authService.LoadAssembly(dllPath); string result = ""; try { result = authService.ExecuteLogin(); authService.Dispose(); } catch (Exception) { // AppDomain is unloaded I have verified that through the unloaded message in the Debugger the exception here is because the whole // thread in the created appdomain is now aborted } return result; } ```
-
Cross-Domain Execution: Through
MarshalByRefObject
, the code enables cross-domain communication, allowing interaction between the isolated domain and the main Revit domain.public abstract class AssemblySandbox : MarshalByRefObject { public void SetDomain(AppDomain domain) { if (Domain == null && domain != null) { Domain = domain; Resolver = new AssemblyResolver(Domain); Domain.DomainUnload += Domain_DomainUnload; } } }
- Resolve DLL Version Conflicts: Bypass issues where Revit locks certain DLL versions by loading the necessary version in an isolated domain.
- Maintain Stability: Prevent Revit's internal dependencies from being overridden by external libraries, ensuring the stability of the application.
- Flexible Plugin Development: This approach allows plugins to manage their own dependencies, facilitating smoother integration of external libraries and services.
-
Clone the repository to your local machine:
https://github.com/mostafa901/SharpBIM.AppDomainSample.git
-
Open the project in your development environment (e.g., Visual Studio).
-
Review the code in SharpBIMAddinCommand.cs to see how the AppDomain is created and how assemblies are loaded dynamically.
-
Modify the
AuthSandbox.cs
class to adapt it for your specific needs, such as interacting with different libraries or performing tasks in the isolated domain. -
Build and run the solution to test how the isolated AppDomain handles DLL loading and cross-domain communication.
This project is licensed under the MIT License - see the LICENSE file for details.