I want to create a dotnet library that supports both linux and windows. The library detects on which OS it is running and executes the respective implementation. For the windows implementation, I need windows apis, which I could get by setting my TargetFramework to (for example) net8.0-windows10.0.19041.0 .
However, I really don't want/cannot change my TargetFramework. It has to stay on net8.0 and net8.0 only. Multiple TargetFrameworks are also not an option for me.
Question: How can I access Windows Runtime Apis while staying on net8.0?
The only available information online always tells me to change my Target Framework Monikor to net8.0-windows.X but, as stated above this is no option for me.
There also is the Microsoft.Windows.SDK.NET.Ref nuget package which I tried to include. However, when building I get the error NU1213:
error NU1213: The package Microsoft.Windows.SDK.NET.Ref 10.0.26100.57 has a package type DotnetPlatform that is incompatible with this project.
My conclusion reading into the error leads me to believe that the nuget has a custom package type which cannot be installed by nuget. My knowledge and the information online is, however, quite limited so maybe there is a different reason.
What works so far
After a lot of testing, I managed to get something working, but it feels very hacky.
The main idea is, to load the windows assembly dynamically at runtime. I can test for the executing OS and then only load and instantiate the assembly if we are on windows.
My overall structure looks like this (omitting .csproj files):
├── BaseProject - TargetFramework: net8.0
│ └── IMyInterface.cs
├── ConsoleProject - TargetFramework: net8.0
│ ├── Microsoft.Windows.SDK.NET.dll
│ └── Programm.cs
└── WindowsProject - TargetFramework: net8.0-windows10.0.19041.0
└── MyClass.cs (implements IMyInterface)
In my BaseProject, I have defined an Interface that is implemented by class MyClass of the WindowsProject.
The ConsoleProject Program.cs looks like similar to this:
var assembly = Assembly.LoadFile("windowsAssembly");
var windowsClassType = assembly.GetType("MyClass");
IMyInterface windowsClass = Activator.CreateInstance(windowsClassType) as IMyInterface;
await windowsClass.SomeMethodAsync().ConfigureAwait(false);
In my small test, the SomeMethodAsync methods accesses the Windows Apis by getting the default Bluetooth adapter.
This setup does not yet fully work, because when SomeMethodAsync is called, I get a runtime error:
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Could not load file or assembly 'Microsoft.Windows.SDK.NET, Version=10.0.19041.38, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.
When I build/publish WindowsProject, the Microsoft.Windows.SDK.NET assembly does not seem to be included in the WindowsProject.dll?!
To get it to run, I extracted the .dlls from the Microsoft.Windows.SDK.NET.Ref nuget and manually added them in the ConsoleProject .csproj.
Now it works (but at what cost 😶).
Microsoft.Windows.SDK.NET.Refpackage. You can just unzip it and access the .nuspec file, remove thepackageTypeand repackage it into your own nuget, or work with the .dlls directly. This is sketchy but it works.