onnxruntime
df8f4a7d - Add OrtEnv.DisableDllImportResolver to prevent fatal error on resolver conflict (#27535)

Commit
10 hours ago
Add OrtEnv.DisableDllImportResolver to prevent fatal error on resolver conflict (#27535) ## Description `NativeLibrary.SetDllImportResolver()` can only be called once per assembly. If a host application registers its own `DllImportResolver` for the ONNX Runtime assembly before any ORT API is used, ORT's internal call to `SetDllImportResolver` in the `NativeMethods` static constructor throws an `InvalidOperationException`, which surfaces as a fatal `TypeInitializationException` — making ONNX Runtime completely unusable. This PR adds two complementary safeguards: 1. **`try/catch(InvalidOperationException)`** around the `SetDllImportResolver` call in `NativeMethods..cctor`, so that if a resolver is already registered, ORT logs a diagnostic trace and continues normally. 2. **`OrtEnv.DisableDllImportResolver`** — a public static `bool` property that allows callers to explicitly opt out of ORT's resolver registration before any ORT type is accessed. This is useful when the host application needs full control over native library resolution. ### Usage ```csharp // Option 1: Opt out before any ORT usage OrtEnv.DisableDllImportResolver = true; NativeLibrary.SetDllImportResolver(typeof(OrtEnv).Assembly, MyCustomResolver); var env = OrtEnv.Instance(); // Option 2: Do nothing — if a resolver is already registered, // ORT catches the conflict and continues using the existing resolver. ``` ## Motivation and Context When a library client has already called `SetDllImportResolver()` for the ORT assembly (e.g., to handle platform-specific library loading), ORT's attempt to register its own resolver causes a fatal, unrecoverable error. This change makes ORT resilient to this scenario and gives clients explicit control. ## Changes ### `csharp/src/Microsoft.ML.OnnxRuntime/OrtEnv.shared.cs` - Added `public static bool DisableDllImportResolver` property with XML documentation and usage example. ### `csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs` - Wrapped `NativeLibrary.SetDllImportResolver` in `if (!OrtEnv.DisableDllImportResolver)` guard. - Added `try/catch(InvalidOperationException)` with a `Trace.WriteLine` diagnostic message. ### `csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs` - Added `OrtEnvExternalDllImportResolverTest` test class with two tests using `AssemblyLoadContext` for process-level isolation of static constructor behavior: - **`TestExternalResolverRegisteredFirst`** — Registers an external resolver FIRST, then initializes ORT. Verifies the `try/catch` prevents a fatal error and ORT remains fully functional (`GetVersionString()` succeeds). - **`TestDisableDllImportResolverWorks`** — Sets `DisableDllImportResolver = true`, initializes ORT, then registers an external resolver. Verifies no `InvalidOperationException` is thrown, proving ORT correctly skipped its own registration.
Author
Parents
Loading