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); + } + } +}