Closed RestoreMonarchy closed 3 years ago
We have a class, ManagedCodeConventions
that can be used to select assets from a package. I guess our unit tests have the easiest examples of how to use this class.
The issue is for the runtimes/
assets is that you need a runtime graph. NuGet doesn't contain this itself, the .NET SDK passes us the file path via msbuild property. Therefore, you'll need to find a solution to how you want to get the runtimes.json file, but it appears that the .NET team is still publishing it as a NuGet package, despite shipping it in the .NET SDK: https://www.nuget.org/packages/Microsoft.NETCore.Platforms/
How you determine what your current runtime is, whether it's win-???
, macos-???
or linux-???
, and what to replace that ???
with is another problem you'll need to solve. Again, MSBuild passes that information to NuGet during restore, so it's not a problem that NuGet itself has.
@zivkan I got it working thanks to your hints!
I added runtime.json
file, from the latest version of Microsoft.NETCore.Platforms
package, to my project, so it appears in the root of the output directory.
This is my LoadLibAsync
method now:
private RuntimeGraph GetRuntimeGraph(string expandedPath)
{
string runtimeGraphFile = Path.Combine(expandedPath, RuntimeGraph.RuntimeGraphFileName);
if (File.Exists(runtimeGraphFile))
{
using (FileStream stream = File.OpenRead(runtimeGraphFile))
{
return JsonRuntimeFormat.ReadRuntimeGraph(stream);
}
}
return null;
}
private async Task<IEnumerable<Assembly>> LoadLibAsync(IAssemblyContext context, PackageArchiveReader reader, string path)
{
RuntimeGraph graph = GetRuntimeGraph(Directory.GetCurrentDirectory());
ManagedCodeConventions conv = new ManagedCodeConventions(graph);
ContentItemCollection collection = new ContentItemCollection();
collection.Load(await reader.GetFilesAsync(CancellationToken.None));
List<Assembly> assemblies = new List<Assembly>();
NuGetFramework framework = frameworkReducer.GetNearest(targetFramework, await reader.GetSupportedFrameworksAsync(CancellationToken.None));
ContentItemGroup natives = collection.FindBestItemGroup(
conv.Criteria.ForRuntime(RuntimeInformation.RuntimeIdentifier),
conv.Patterns.NativeLibraries);
ContentItemGroup group = collection.FindBestItemGroup(
conv.Criteria.ForFrameworkAndRuntime(framework, RuntimeInformation.RuntimeIdentifier),
conv.Patterns.RuntimeAssemblies);
if (group != null)
{
foreach (ContentItem item in group.Items)
{
if (!item.Path.EndsWith(".dll"))
continue;
ZipArchiveEntry entry = reader.GetEntry(item.Path);
using Stream libStream = entry.Open();
using MemoryStream ms = new MemoryStream();
await libStream.CopyToAsync(ms);
ms.Position = 0;
Assembly assembly = context.LoadAssembly(ms);
assemblies.Add(assembly);
logger.LogInformation($"{assembly.GetName().Name} {assembly.GetName().Version} has been loaded!");
}
}
if (natives != null)
{
foreach (ContentItem item in natives.Items)
{
if (!item.Path.EndsWith(".dll"))
continue;
string itemPath = Path.Combine(path, item.Path);
NativeLibrary.Load(itemPath);
}
}
return assemblies;
}
System.Data.SqlClient
and all other dependencies are loaded without issues now and my code runs without errors
..., but I'm not sure if I load the native libraries like sni.dll
for System.Data.SqlClient
correctly.
Right now I'm loading all dependencies into the AssemblyContext which after execution of a method from a plugin I'm unloading.
Native library I'm just simply loading with NativeLibrary.Load
and it works.
Should I load native library into the AssemblyContext, so I could unload it later along with other libraries? Can I even do this? Or should I keep it like this and it won't have any leaks?
Thanks for help again
Should I load native library into the AssemblyContext, so I could unload it later along with other libraries? Can I even do this? Or should I keep it like this and it won't have any leaks?
I don't know, I'm not an expert on AssemblyLoadContext
or AppDomain
. Closing since this is no longer about NuGet. It seems you know enough to test for yourself, but you could also try stack overflow, or asking at dotnet/runtime.
Hello,
I'm making a project that will dynamically load assemblies from NuGet package in runtime. I'm using NuGet.Client packages to download & install dependencies then to read the NuGet package.
I'm stuck in my
LoadLibAsync
method. I use it to load the assembly from the passed NuGetPackage as aPackageArchiveReader reader
parameter. It works well for most NuGet packages likeDapper
orEPPlus
, but it doesn't work forSystem.Data.SqlClient 4.8.2
orSystem.Drawing
.When I try to load
System.Data.SqlClient 4.8.2
using theLoadLibAsync
it loads the assembly from thelib
folder which contains only I think a reference binary for it. It does get loaded but every method will throw the exception:I know I should load the assembly from
runtimes
if it exists in the NuGet package likeSystem.Data.SqlClient 4.8.2
, because it's a complete assembly. I couldn't find any method in NuGet.Client libraries that does it tho. I also don't know how I can make a handling for it myself, becauseSystem.Data.SqlClient
containsunix
andwin
directories insideruntimes
, but I read that other packages may contain specific windows versions.What should I use to load assemblies like
System.Data.SqlClient
orSystem.Drawing
? Thanks for help!