diff --git a/.editorconfig b/.editorconfig
index e7ef5f29..8705144d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -161,6 +161,7 @@ dotnet_diagnostic.CA1835.severity = none
dotnet_diagnostic.IDE0290.severity = none # Use primary constructor
dotnet_diagnostic.IDE0065.severity = none # Using directives must be placed outside of namespace
+dotnet_diagnostic.IDE0350.severity = none # Lambda expression can be simplified
# Collection initialization can be simplified.
# This relies on implicit conversions in ways that are sometimes undesirable.
diff --git a/src/NodeApi.DotNetHost/ManagedHost.cs b/src/NodeApi.DotNetHost/ManagedHost.cs
index 65860e50..402befe6 100644
--- a/src/NodeApi.DotNetHost/ManagedHost.cs
+++ b/src/NodeApi.DotNetHost/ManagedHost.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
@@ -49,13 +50,13 @@ public sealed class ManagedHost : JSEventEmitter, IDisposable
///
/// Mapping from assembly file paths to loaded assemblies.
///
- private readonly Dictionary _loadedAssembliesByPath = new();
+ private readonly ConcurrentDictionary _loadedAssembliesByPath = new();
///
/// Mapping from assembly names (not including version or other parts) to
/// loaded assemblies.
///
- private readonly Dictionary _loadedAssembliesByName = new();
+ private readonly ConcurrentDictionary _loadedAssembliesByName = new();
///
/// Tracks names of assemblies that have been exported to JS.
@@ -467,7 +468,7 @@ public JSValue LoadAssembly(JSCallbackArgs args)
assembly = LoadAssembly(assemblyNameOrFilePath, allowNativeLibrary: true);
}
- if (!_exportedAssembliesByName.Contains(assembly.GetName().Name!))
+ if (assembly != null && !_exportedAssembliesByName.Contains(assembly.GetName().Name!))
{
_typeExporter.ExportAssemblyTypes(assembly);
_exportedAssembliesByName.Add(assembly.GetName().Name!);
@@ -487,7 +488,7 @@ private JSValue ResolveAssembly(JSCallbackArgs args)
return default;
}
- private Assembly LoadAssembly(string assemblyNameOrFilePath, bool allowNativeLibrary)
+ private Assembly? LoadAssembly(string assemblyNameOrFilePath, bool allowNativeLibrary)
{
Trace($"> ManagedHost.LoadAssembly({assemblyNameOrFilePath})");
@@ -525,41 +526,44 @@ private Assembly LoadAssembly(string assemblyNameOrFilePath, bool allowNativeLib
"or the name of a system assembly (without path or DLL extension).");
}
- Assembly assembly;
- try
+ Assembly? assembly = _loadedAssembliesByPath.GetOrAdd(assemblyFilePath, _ =>
{
+ try
+ {
#if NETFRAMEWORK || NETSTANDARD
- // TODO: Load assemblies in a separate appdomain.
- assembly = Assembly.LoadFrom(assemblyFilePath);
+ // TODO: Load assemblies in a separate appdomain.
+ return Assembly.LoadFrom(assemblyFilePath);
#else
- assembly = _loadContext.LoadFromAssemblyPath(assemblyFilePath);
+ return _loadContext.LoadFromAssemblyPath(assemblyFilePath);
#endif
- }
- catch (BadImageFormatException)
- {
- if (!allowNativeLibrary)
- {
- throw;
}
+ catch (BadImageFormatException)
+ {
+ if (!allowNativeLibrary)
+ {
+ throw;
+ }
- // This might be a native DLL, not a managed assembly.
- // Load the native library, which enables it to be auto-resolved by
- // any later DllImport operations for the same library name.
- NativeLibrary.Load(assemblyFilePath);
+ // This might be a native DLL, not a managed assembly.
+ // Load the native library, which enables it to be auto-resolved by
+ // any later DllImport operations for the same library name.
+ NativeLibrary.Load(assemblyFilePath);
+ return null;
+ }
+ catch (FileNotFoundException fnfex)
+ {
+ throw new FileNotFoundException(
+ $"Assembly file not found: {assemblyNameOrFilePath}", fnfex);
+ }
+ });
- Trace($"< ManagedHost.LoadAssembly() => {assemblyFilePath} (native library)");
- return null!;
- }
- catch (FileNotFoundException fnfex)
+ if (assembly != null)
{
- throw new FileNotFoundException(
- $"Assembly file not found: {assemblyNameOrFilePath}", fnfex);
+ _loadedAssembliesByName.GetOrAdd(assembly.GetName().Name!, assembly);
}
- _loadedAssembliesByPath.Add(assemblyFilePath, assembly);
- _loadedAssembliesByName.Add(assembly.GetName().Name!, assembly);
-
- Trace($"< ManagedHost.LoadAssembly() => {assemblyFilePath}, {assembly.GetName().Version}");
+ string version = assembly?.GetName().Version?.ToString() ?? "(native library)";
+ Trace($"< ManagedHost.LoadAssembly() => {assemblyFilePath} {version}");
return assembly;
}