diff --git a/DotNetCorePlugins.sln b/DotNetCorePlugins.sln
index 20a6626..1ac5231 100644
--- a/DotNetCorePlugins.sln
+++ b/DotNetCorePlugins.sln
@@ -124,6 +124,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithOurPluginsPluginA", "te
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithOurPluginsPluginB", "test\TestProjects\WithOurPluginsPluginB\WithOurPluginsPluginB.csproj", "{D5B3DA06-E60D-4C85-8835-6A26003365AA}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeDependency", "test\TestProjects\NativeDependency\NativeDependency.csproj", "{2837A894-11D6-4DBF-B140-84C97C385A15}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -638,6 +640,18 @@ Global
{D5B3DA06-E60D-4C85-8835-6A26003365AA}.Release|x64.Build.0 = Release|Any CPU
{D5B3DA06-E60D-4C85-8835-6A26003365AA}.Release|x86.ActiveCfg = Release|Any CPU
{D5B3DA06-E60D-4C85-8835-6A26003365AA}.Release|x86.Build.0 = Release|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Debug|x64.Build.0 = Debug|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Debug|x86.Build.0 = Debug|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Release|x64.ActiveCfg = Release|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Release|x64.Build.0 = Release|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Release|x86.ActiveCfg = Release|Any CPU
+ {2837A894-11D6-4DBF-B140-84C97C385A15}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -691,6 +705,7 @@ Global
{7C7B19F2-5822-4DA2-80D2-E077CE705039} = {98E964A2-55DA-4740-9F2E-B64FDF6715DB}
{3A7712FC-9A91-4322-AF7E-4FEC6EB0D845} = {98E964A2-55DA-4740-9F2E-B64FDF6715DB}
{D5B3DA06-E60D-4C85-8835-6A26003365AA} = {98E964A2-55DA-4740-9F2E-B64FDF6715DB}
+ {2837A894-11D6-4DBF-B140-84C97C385A15} = {98E964A2-55DA-4740-9F2E-B64FDF6715DB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B1AF41DC-A03E-47B1-BBDB-3DC27ABD9F74}
diff --git a/src/Plugins/Loader/ManagedLoadContext.cs b/src/Plugins/Loader/ManagedLoadContext.cs
index 03e6212..f606047 100644
--- a/src/Plugins/Loader/ManagedLoadContext.cs
+++ b/src/Plugins/Loader/ManagedLoadContext.cs
@@ -343,7 +343,10 @@ private string CreateShadowCopy(string dllPath)
var dllFileName = Path.GetFileName(dllPath);
var shadowCopyPath = Path.Combine(_unmanagedDllShadowCopyDirectoryPath, dllFileName);
- File.Copy(dllPath, shadowCopyPath);
+ if (!File.Exists(shadowCopyPath))
+ {
+ File.Copy(dllPath, shadowCopyPath);
+ }
return shadowCopyPath;
}
diff --git a/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj b/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj
index 8d842a0..9d3c649 100644
--- a/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj
+++ b/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj
@@ -29,6 +29,7 @@
+
diff --git a/test/Plugins.Tests/ShadowCopyTests.cs b/test/Plugins.Tests/ShadowCopyTests.cs
new file mode 100644
index 0000000..422b4b0
--- /dev/null
+++ b/test/Plugins.Tests/ShadowCopyTests.cs
@@ -0,0 +1,28 @@
+#if NETCOREAPP3_1
+
+using Xunit;
+
+namespace McMaster.NETCore.Plugins.Tests
+{
+ public class ShadowCopyTests
+ {
+ [Fact]
+ public void DoesNotThrowWhenLoadingSameNativeDependecyMoreThanOnce()
+ {
+ var samplePath = TestResources.GetTestProjectAssembly("NativeDependency");
+
+ using var loader = PluginLoader
+ .CreateFromAssemblyFile(samplePath, config => config.EnableHotReload = true);
+
+ var nativeDependecyLoadMethod = loader.LoadDefaultAssembly()
+ .GetType("NativeDependency.NativeDependencyLoader")
+ .GetMethod("Load");
+
+ var exception = Record.Exception(() => nativeDependecyLoadMethod.Invoke(null, null));
+
+ Assert.Null(exception);
+ }
+ }
+}
+
+#endif
diff --git a/test/TestProjects/NativeDependency/NativeDependency.csproj b/test/TestProjects/NativeDependency/NativeDependency.csproj
new file mode 100644
index 0000000..1f98e47
--- /dev/null
+++ b/test/TestProjects/NativeDependency/NativeDependency.csproj
@@ -0,0 +1,11 @@
+
+
+
+ netcoreapp3.1
+
+
+
+
+
+
+
diff --git a/test/TestProjects/NativeDependency/NativeDependencyLoader.cs b/test/TestProjects/NativeDependency/NativeDependencyLoader.cs
new file mode 100644
index 0000000..31c1260
--- /dev/null
+++ b/test/TestProjects/NativeDependency/NativeDependencyLoader.cs
@@ -0,0 +1,37 @@
+using System;
+using System.IO;
+using System.Data.SQLite;
+
+namespace NativeDependency
+{
+ public static class NativeDependencyLoader
+ {
+ public static void Load()
+ {
+ using var tempFile = new TempFile("db.sqlite");
+ using var dbConnection = new SQLiteConnection($"Data Source={tempFile.FilePath}");
+
+ dbConnection.Open();
+ }
+ }
+
+ public class TempFile : IDisposable
+ {
+ public TempFile(string fileName)
+ {
+ FilePath = Path.Combine(Path.GetTempPath(), fileName);
+ }
+
+ public string FilePath { get; }
+
+ public void Dispose()
+ {
+ if (!File.Exists(FilePath))
+ {
+ return;
+ }
+
+ File.Delete(FilePath);
+ }
+ }
+}