I am working on a complex migration to .NET Core 6 application which has a set of shared assemblies which are located in a different path than the main application assemblies due to our deployment strategy.
The libs are statically linked so I can't use AssemblyLoadContext
or AppDomain
to extend the resolving process, sadly. I saw that the runtimeconfig.json
offers the possibility to add APP_PATHS
which seem to work, BUT I only managed to use absolute paths - which is nonsense as I won't know the actual paths on the target machines.
Can't I use relative paths? Whenever I try even sub-paths I get an exception that the runtime cannot be created. Is there a magical syntax to that? It can't be so complicated to have the assemblies in multiple folders.... I feel stupid.
Has somebody an idea here? I can't just change the deployment structure / process.
Thanks
Update: After carefully subscribe to AssemblyLoadContext.Default and ensuring that only that happens in the static main, not some static constructors interfering, it works. Thanks for the heads up.
An example to my comment. I have three projects: Library A
, Library B
, and Application C
.
A.csproj
and B.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
ClassA
in project A
.
using System.Runtime.CompilerServices;
namespace A
{
public static class ClassA
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static int Plink()
{
return 1;
}
}
}
ClassB
using System.Runtime.CompilerServices;
namespace B
{
public class ClassB
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static int Plonk()
{
return 2;
}
}
}
C.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\A\A.csproj" Private="false" />
<ProjectReference Include="..\B\B.csproj" Private="false" />
</ItemGroup>
</Project>
Program.cs
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using A;
using B;
namespace C
{
public static class Program
{
public static void Main(string[] args)
{
SetupAssemblies();
Foo();
}
private static void SetupAssemblies()
{
AssemblyLoadContext.Default.Resolving += Default_Resolving;
}
private static System.Reflection.Assembly? Default_Resolving(AssemblyLoadContext arg1, System.Reflection.AssemblyName arg2)
{
Console.WriteLine($"Attempting to resolve {arg2}");
string assemblyPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), $@"..\deps\{arg2.Name}.dll"));
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Foo()
{
Console.WriteLine(ClassA.Plink() + ClassB.Plonk());
}
}
}
I structured my output as follows
~\Projects\SO\C\BIN\DEBUG
│
├───deps
│ A.dll
│ B.dll
└───net8.0
C.deps.json
C.dll
C.exe
C.pdb
C.runtimeconfig.json
Program output:
Attempting to resolve A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Attempting to resolve B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
3