TeklaHelper.AssemblyResolver
1.1.0
dotnet add package TeklaHelper.AssemblyResolver --version 1.1.0
NuGet\Install-Package TeklaHelper.AssemblyResolver -Version 1.1.0
<PackageReference Include="TeklaHelper.AssemblyResolver" Version="1.1.0" />
<PackageVersion Include="TeklaHelper.AssemblyResolver" Version="1.1.0" />
<PackageReference Include="TeklaHelper.AssemblyResolver" />
paket add TeklaHelper.AssemblyResolver --version 1.1.0
#r "nuget: TeklaHelper.AssemblyResolver, 1.1.0"
#:package TeklaHelper.AssemblyResolver@1.1.0
#addin nuget:?package=TeklaHelper.AssemblyResolver&version=1.1.0
#tool nuget:?package=TeklaHelper.AssemblyResolver&version=1.1.0
TeklaHelper.AssemblyResolver
Remove Tekla assemblies from the GAC:
In some environments, the .NET runtime automatically loads older Tekla assemblies from the Global Assembly Cache (GAC) before TeklaHelper.AssemblyResolver can intercept the resolution. For example, an application targeting Tekla Structures 2026 may inadvertently load Tekla 2020 DLLs from the GAC, resulting in version mismatches and connection failures.
Run the following PowerShell command (as Administrator) to remove any Tekla assemblies from the GAC so that TeklaHelper.AssemblyResolver will operate correctly:
Get-ChildItem "C:\Windows\Microsoft.NET\assembly\*\Tekla*" -Directory | Remove-Item -Recurse -Force
Tekla Structures 2026+ supports only 64-bit (x64) extensions: With the continuous improvement of the Tekla Open API and the efforts to enable .NET for Tekla Structures that started with TeklaStructures 2024, starting with TeklaStructures 2026 only x64 extensions that use Tekla Open API are supported.
See the Tekla Discussion Forum announcement for details.
Finds Tekla Structures installations in the Windows Registry and, at runtime, loads every DLL your application is missing from the folders of the Tekla Structures version it works with.
This lets a standalone application (console, WPF, WinForms, …) reference the Tekla Open API without copying any Tekla DLLs next to the executable. When the runtime cannot find a DLL — a Tekla Open API assembly such as Tekla.Structures.Model, or one of its dependencies such as Trimble.Remoting or System.Memory — the resolver loads it from the matching Tekla Structures installation.
Features
- Discovers every installed Tekla Structures version from
HKLM(both 64-bit and 32-bit registry views,Trimble\Tekla Structuresand legacyTekla\Structureskeys). Keys that cannot be read are skipped instead of failing. - Loads Tekla assemblies only from the installation with the same major version as requested (e.g.
2026.0.0.0→ Tekla 2026). It never silently loads a DLL from a different Tekla version unless you opt in. - Loads any other missing DLL (e.g.
Trimble.Remoting,System.Memory,Google.Protobuf) only from the Tekla installation in use, so DLLs of different Tekla versions are never mixed. - Verifies the assembly name, version and
PublicKeyTokenof the file before loading it. - Supports both the new layout (
bin,bin\Net48Runtimeon Tekla 2026+) and the old layout (nt\bin,nt\bin\pluginson Tekla 2020 and earlier), the direct sub-folders ofbin/nt\bin(e.g.nt\bin\dialogs), plus extra sub-folders you declare inAdditionalSearchDirectories. - Targets
netstandard2.0. The Tekla Open API itself requires .NET Framework 4.8 — see Requirements.
Installation
dotnet add package TeklaHelper.AssemblyResolver
or with the Package Manager Console:
Install-Package TeklaHelper.AssemblyResolver
Quick start
In a project targeting
net48, reference the Tekla Open API DLLs (or theTekla.Structures.*NuGet packages) as usual, but do not copy them to the output folder — otherwise the runtime finds the local copy and the resolver is never asked:<Reference Include="Tekla.Structures.Model"> <HintPath>C:\TeklaStructures\2026.0\bin\Tekla.Structures.Model.dll</HintPath> <Private>false</Private> </Reference>For a
PackageReference, use<ExcludeAssets>runtime</ExcludeAssets>.Register the resolver at the very start of
Main, before calling any method that uses Tekla types. The JIT loads referenced assemblies as soon as such a method is compiled, so keep the Tekla code in a separate method:using System.Runtime.CompilerServices; using TeklaHelper.AssemblyResolver; internal static class Program { private static void Main() { TeklaAssemblyResolver.Register(); RunTeklaCode(); } [MethodImpl(MethodImplOptions.NoInlining)] private static void RunTeklaCode() { var model = new Tekla.Structures.Model.Model(); System.Console.WriteLine(model.GetConnectionStatus()); } }TeklaAssemblyResolver.Register()creates one shared resolver from the registry; calling it again returns the same resolver. To control the lifetime or the installations yourself, create an instance instead:using (var resolver = TeklaAssemblyResolver.CreateFromRegistry()) { resolver.Register(); RunTeklaCode(); }
Listing installed Tekla Structures versions
foreach (TeklaInstallation installation in TeklaInstallationFinder.FindAll())
{
Console.WriteLine(installation.Version); // 2026.0
Console.WriteLine(installation.InstallDirectory); // C:\TeklaStructures\2026.0
Console.WriteLine(string.Join(", ", installation.GetBinDirectories()));
}
TeklaInstallation also exposes ProductVersion, EnvironmentDirectory, ModelDirectory, MajorVersion, GetExtensionsDirectory() / EnsureExtensionsDirectory() and FindAssemblyPath(...).
How assemblies are resolved
| Requested assembly | Installations searched | Version check |
|---|---|---|
Tekla assembly with a Tekla version (e.g. Tekla.Structures.Model, Version=2026.0.0.0) |
Only installations with the same major version | File major version must match |
Any other missing DLL (e.g. Trimble.Remoting, Google.Protobuf) |
Only ActiveInstallation; all installations, newest first, while it is not known yet |
File version must be ≥ requested version |
Directories are searched in this order inside each installation:
bin\Net48Runtime(Tekla 2026+, searched first when running on .NET Framework)bin(Tekla 2021+)nt\bin\plugins(Tekla 2020 and earlier)nt\bin(Tekla 2020 and earlier)AdditionalSearchDirectories, in the order they were added- The direct sub-folders of
binandnt\binnot listed above, in alphabetical order (e.g.nt\bin\dialogs, which containsTekla.Structures.Dialogon Tekla 2020)
The sub-folders come last because some of them keep other versions of DLLs that are also in the main folders (for example nt\bin\symed\dxkit.dll on Tekla 2020).
A request counts as a Tekla assembly with a Tekla version when its name starts with Tekla. or it is signed with the Tekla public key (PublicKeyToken=2f04dbe497b71114), and its major version is a year (2000–2099) or the major version of an installed Tekla (old numbering such as 21.1). Third-party DLLs with similar version numbers (e.g. DevExpress.Data.v21.1) and Tekla libraries with their own versioning (e.g. Tekla.Common.Geometry 4.7) are treated as dependencies.
ActiveInstallation is the installation the first Tekla assembly was loaded from. If a Tekla assembly was already loaded by other means (for example inside a Tekla Structures plugin), the resolver detects its installation from the file location.
If no matching installation is found the resolver returns null, so the runtime throws the usual FileNotFoundException.
Additional search directories
Only the direct sub-folders of bin and nt\bin are searched by default; deeper folders (bin\plugins\Tekla\…, bin\applications\…) are not. Add the ones your application needs, relative to the installation directory:
TeklaAssemblyResolver resolver = TeklaAssemblyResolver.Register();
resolver.AdditionalSearchDirectories.Add(@"bin\plugins\Tekla\Drawings\AdvancedGridLabels"); // Tekla 2021+
resolver.AdditionalSearchDirectories.Add(@"nt\bin\plugins\Tekla"); // Tekla 2020 and earlier
Each relative path is resolved inside every installation, so the DLL still comes from the Tekla version in use; folders that do not exist in an installation are skipped. Absolute paths are used as-is. Folders deeper than one level are not searched recursively on purpose: they can contain copies from other Tekla versions (for example bin\applications\Tekla\Model\StatusSharing\Tekla.Structures.dll is version 2024 in Tekla 2026).
Version fallback
TeklaAssemblyResolver.Register(allowVersionFallback: true);
// or, on your own instance
resolver.AllowVersionFallback = true;
Allows loading DLLs from another Tekla version when the requested version is not installed, and loading dependencies from other installations when the installation in use does not have them. This is disabled by default because API differences between versions can cause MissingMethodException or TypeLoadException at runtime.
Logging
Set Logger to see what the resolver does: registration, each resolve request, the file that was loaded, files that were skipped and why, and requests that could not be resolved. Logging is off by default.
TeklaAssemblyResolver.Register(logger: Console.WriteLine);
// or write to a file
TeklaAssemblyResolver resolver = TeklaAssemblyResolver.Register();
resolver.Logger = message => File.AppendAllText(@"C:\Temp\resolver.log", $"{DateTime.Now:HH:mm:ss.fff} {message}{Environment.NewLine}");
Example output with Tekla Structures 2026:
[TeklaAssemblyResolver] Registered. Tekla Structures installations: 2026.0 (C:\TeklaStructures\2026.0), 2020.0 (C:\TeklaStructures\2020.0)
[TeklaAssemblyResolver] Resolving Tekla.Structures.Model, Version=2026.0.0.0, Culture=neutral, PublicKeyToken=2f04dbe497b71114
[TeklaAssemblyResolver] Tekla.Structures.Model: loaded C:\TeklaStructures\2026.0\bin\Tekla.Structures.Model.dll
[TeklaAssemblyResolver] Active installation: Tekla Structures 2026.0 (C:\TeklaStructures\2026.0)
[TeklaAssemblyResolver] Resolving Trimble.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=a70cba4ef557ee03
[TeklaAssemblyResolver] Trimble.Remoting: loaded C:\TeklaStructures\2026.0\bin\Trimble.Remoting.dll
The logger can be called from several threads at once. Exceptions thrown by it are ignored, and it is never called recursively, so a logger that itself needs a missing DLL cannot break or loop the resolver.
API overview
| Type | Member | Description |
|---|---|---|
TeklaInstallationFinder |
FindAll() |
Returns all installations, newest first. Empty on non-Windows platforms. |
TeklaAssemblyResolver |
static Register(allowVersionFallback = false, logger = null) |
Creates (once) and registers a shared resolver from the registry, and returns it. |
CreateFromRegistry() |
Creates a resolver for all installations found in the registry. | |
Register() / Unregister() / Dispose() |
Subscribes to / unsubscribes from AppDomain.CurrentDomain.AssemblyResolve. |
|
FindAssemblyPath(AssemblyName) |
Returns the path of the matching DLL without loading it. | |
LoadAssembly(AssemblyName) |
Loads the matching DLL (or returns the already loaded one). | |
AdditionalSearchDirectories |
Extra folders, relative to each installation, searched after the standard bin folders. | |
Logger |
Action<string> that receives diagnostic messages; null disables logging. |
|
Installations, ActiveInstallation, AllowVersionFallback |
Resolver state and options. |
Requirements
- Windows with at least one Tekla Structures version installed.
- An application that uses the Tekla Open API must target .NET Framework 4.8 (
net48). - Starting with Tekla Structures 2026, applications and extensions using the Tekla Open API must target x64 (64-bit).
The resolver itself targets netstandard2.0 and also loads DLLs correctly on .NET 6/8+. However, the Tekla Open API communicates with Tekla Structures through .NET Remoting, which does not exist on .NET Core / .NET 5+. On .NET 8, new Model() fails inside Tekla's own code with TypeLoadException: Could not load type 'System.Runtime.Remoting.Lifetime.ClientSponsor', and GetConnectionStatus() returns false. This is a Tekla Open API limitation and cannot be fixed by the resolver. On .NET 6/8+ you can still use TeklaInstallationFinder to list installations.
Building from source
git clone https://github.com/nguyenthanguth/TeklaHelper.AssemblyResolver.git
cd TeklaHelper.AssemblyResolver
dotnet build TeklaHelper.AssemblyResolver.slnx -c Release
Packing
dotnet pack TeklaHelper.AssemblyResolver.csproj -c Release -o artifacts
License
Tekla and Tekla Structures are trademarks of Trimble Inc. This project is not affiliated with or endorsed by Trimble.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Win32.Registry (>= 5.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.