Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"System.IO.Ports is currently only supported on Windows" when dynamically loading assembly on a Windows machine

A console application dynamically loads an assembly containing a class that refers System.IO.Ports.

Both the application and the class library target net8.0-windows.

I get the exception System.IO.Ports is currently only supported on Windows., even though the command OperatingSystem.IsWindows() returns true.

If I add a reference to the class library from console application the error disappears.

I guess that during dynamic loading the information about the target runtime is lost.

Adding

<RuntimeIdentifiers>win-x64</RuntimeIdentifiers> 

to projects does not help.

A minimal reproducible example is available on GitHub.

Console application project file:

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
</PropertyGroup>

Class library project file:

<PropertyGroup>
    <TargetFramework>net8.0-windows</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

<ItemGroup>
    <PackageReference Include="System.IO.Ports" Version="8.0.0" />
</ItemGroup>

Program.cs:

using System.Reflection;

try
{
    var serialPortPath = "..\\..\\..\\..\\SerialPort\\bin\\Debug\\net8.0-windows\\SerialPort.dll";
    var serialAssembly = Assembly.LoadFrom(serialPortPath);
    var serialPort = Activator.CreateInstance(serialAssembly.GetType("SerialPort.SerialPort"));
}
catch    
{
    // Do nothing
}

SerialPort.cs:

namespace SerialPort
{
    public class SerialPort
    {
        public SerialPort()
        {
            var serial = new System.IO.Ports.SerialPort();
        }
    }
}

The exception throws at

var serial = new System.IO.Ports.SerialPort();

EDIT: I'm aware of LoadContext, but I don't understand the root of the problem yet: if I directly refer the assembly it correctly finds the Windows dll, why the information about target platform is lost when loading via Assembly.LoadFrom?

like image 370
grandangelo Avatar asked Oct 29 '25 20:10

grandangelo


1 Answers

Because SerialPort.dll depends on System.IO.Ports.dll, when you load SerialPort.dll, the runtime automatically loads System.IO.Ports.dll from the same folder, but unfortunately this is a wrong assembly file, the right assembly file to load is located in runtimes\win\lib\net8.0\ folder. To resolve the dependency path, you need to create a custom AssemblyLoadContext and an AssemblyDependencyResolver, also ensure that SerialPort.deps.json is generated along with SerialPort.dll:

var customALC = new CustomALC();
....
var serialAssembly = customALC.Load(serialPortPath);
....

class CustomALC : AssemblyLoadContext
{
    private AssemblyDependencyResolver? _resolver;

    protected override Assembly? Load(AssemblyName assemblyName)
    {
        var path = _resolver?.ResolveAssemblyToPath(assemblyName);
        return path != null ? LoadFromAssemblyPath(path) : null;
    }

    public Assembly Load(string path)
    {
        path = Path.GetFullPath(path);
        _resolver = new AssemblyDependencyResolver(path);
        return LoadFromAssemblyPath(path);
    }
}
like image 70
shingo Avatar answered Oct 31 '25 13:10

shingo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!