Comments (6)
even should be reported as a flaw in AssemblyLoadContext.LoadUnmanagedDllFromPath.
Yes, can you please open this on https://github.com/dotnet/coreclr, if it doesn't exist already?
In the meantime, I'm happy to take a workaround for this that normalizes slashes before calling LoadUnmanagedDllFromPath.
from dotnetcoreplugins.
@per-samuelsson thanks for sharing details on your investigation. I'd be happy to add a workaround to this library which normalizes the file path before calling LoadUnmanagedDllFromPath. Feel free to send a PR and I can get an update to nuget.org this week.
from dotnetcoreplugins.
even should be reported as a flaw in AssemblyLoadContext.LoadUnmanagedDllFromPath.
Yes, can you please open this on https://github.com/dotnet/coreclr, if it doesn't exist already?
https://github.com/dotnet/coreclr/issues/22094
from dotnetcoreplugins.
FYI: when investigating a possible workaround, I found this is more narrow than it first appeared to be.
For example, I debugged the unit test LoadsNativeDependenciesWhenDllImportUsesFilename()
and that actually resolve sni.dll
to full path C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder\\runtime.win-x64.runtime.native.system.data.sqlclient.sni\\4.4.0\\runtimes/win-x64/native/sni.dll
on my machine (notice the forward slashes), and that succeed when passed on to AssemblyLoadeContext.LoadUnmanagedDllFromPath(path)
.
But then when I try with the library I reported about, it resolves to C:\\Users\\Per\\.nuget\\packages\\starcounter.queryprocessor\\2.0.10\\runtimes/win-x64/native/libswipl.dll
, and that fails. However, if I normalize that path using Path.GetFullPath(path)
before I pass it on to AssemblyLoadeContext.LoadUnmanagedDllFromPath(path)
, loading succeed.
I guess the takeaway right now is that a workaround doing Path.GetFullPath(path)
just before calling AssemblyLoadeContext.LoadUnmanagedDllFromPath(path)
would pass all cases I've got. The problem is it's not trivial to set up any decent regression test for it.
from dotnetcoreplugins.
The problem is it's not trivial to set up any decent regression test for it.
OK, now I crafted me a decent repro to illustrate, and where it's easy to tweak to apply the workaround:
- Clone https://github.com/per-samuelsson/ALCHostingTests
- Under
Test2
, there's two projects:- App: a console app invoking a native function in a package.
- Loader: a console app loading "App" and calling the code that invokes the function (effectively forcing plugin library to resolve native asset).
- First
cd Test2\App
anddotnet run
. You'll see standard host resolve properly. - Now
cd Test2\Loader
anddotnet run
. You'll see plugin library fail to resolve.
If you want to apply the workaround and see plugin library succeed, just change reference in Test2\Loader\Loader.csproj
to point to sources of DotNetCorePlugins
(just adjust location of relative project path).
Then I tweaked ManagedLoadContext.cs
like below. Doing that, point [4] from above goes from red to green.
// All calls doing native loading now goes via `LoadUnmanagedDllFromResolvedPath` that
// does the normalization
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
foreach (var prefix in PlatformInformation.NativeLibraryPrefixes)
{
if (_nativeLibraries.TryGetValue(prefix + unmanagedDllName, out var library))
{
if (SearchForLibrary(library, prefix, out var path))
{
return LoadUnmanagedDllFromResolvedPath(path);
}
}
else
{
// coreclr allows code to use [DllImport("sni")] or [DllImport("sni.dll")]
// This library treats the file name without the extension as the lookup name,
// so this loop is necessary to check if the unmanaged name matches a library
// when the file extension has been trimmed.
foreach (var suffix in PlatformInformation.NativeLibraryExtensions)
{
if (!unmanagedDllName.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
{
continue;
}
// check to see if there is a library entry for the library without the file extension
var trimmedName = unmanagedDllName.Substring(0, unmanagedDllName.Length - suffix.Length);
if (_nativeLibraries.TryGetValue(prefix + trimmedName, out library))
{
if (SearchForLibrary(library, prefix, out var path))
{
return LoadUnmanagedDllFromResolvedPath(path);
}
}
else
{
// fallback to native assets which match the file name in the plugin base directory
var localFile = Path.Combine(_basePath, prefix + unmanagedDllName + suffix);
if (File.Exists(localFile))
{
return LoadUnmanagedDllFromResolvedPath(localFile);
}
var localFileWithoutSuffix = Path.Combine(_basePath, prefix + unmanagedDllName);
if (File.Exists(localFileWithoutSuffix))
{
return LoadUnmanagedDllFromResolvedPath(localFileWithoutSuffix);
}
}
}
}
}
return base.LoadUnmanagedDll(unmanagedDllName);
}
private IntPtr LoadUnmanagedDllFromResolvedPath(string unmanagedDllPath)
{
var normalized = Path.GetFullPath(unmanagedDllPath);
return LoadUnmanagedDllFromPath(normalized);
}
from dotnetcoreplugins.
Feel free to send a PR and I can get an update to nuget.org this week.
from dotnetcoreplugins.
Related Issues (20)
- Use WeakReference to check if unload is successful HOT 3
- [Question] What happened to AddDependencyContext? HOT 9
- Add hot-reload to ASP.NET Core sample HOT 2
- How do I "Unload" a plugin/dll HOT 1
- Error starting application when plugin controller decorating with [ApiController]
- How can i use Plugin DBContext ? HOT 2
- Docker file build problems HOT 3
- [Question] Diamond dependency & shared types doesn't work
- Diamond dependency & shared types doesn't work when using NuGet packages HOT 2
- Error on loading NuGet package HOT 2
- [Question] [Help Wanted] JSON Serialization problems; can assembly name or version be changed at load time? HOT 1
- [Question] Some questions about the state of the project HOT 8
- 支持卸载吗 HOT 2
- [Question] How to inject Logger or IConfiguration in Plugins ? I tried and failed HOT 1
- Using the library in MacOs project
- [Question] Capturing exceptions
- RobiniaDocs API Explorer
- [Question] System.Data.SqlClient could not be found on my plugin HOT 1
- [Question] Hot-reload managed assemblies using assembly file lock instead of through FileStream
- System.PlatformNotSupportedException on Android
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dotnetcoreplugins.