1

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 😶).

4
  • 5
    "Multiple TargetFrameworks are also not an option for me" why not? This would be the usual solution, to cross-compile for both systems. Commented Jul 7 at 16:17
  • @Charlieface Doesn't matter, that's why I specifically asked for a different way. Short version is, that I have customers which can only include packages with targetframework 'net8.0' and not 'net8.0-windows.x'. If I make my lib multitarget, all my customers would need to be multitarget as well, or choose a target based on their current OS. For my very specific case, this is not possible. (Sadly,) It is not up to me to decide what my customers do. Else, I wouldn't have this headache 😅 Commented Jul 7 at 18:00
  • 1
    Well if you want to use Windows-specific APIs you need to compile for Windows. There isn't really any way around that, especially if using Nuget. Cross-compilation and targetting frameworks are there for a reason. Your only remaining option is to recompile the wanted library with some kind of conditional handling for every PInvoke, and be very very careful you never call (or even allow the JITter to compile) for the wrong API. Commented Jul 9 at 9:47
  • To my knowledge, there currently is no possible way. The only workaround I get running, was to use the Microsoft.Windows.SDK.NET.Ref package. You can just unzip it and access the .nuspec file, remove the packageType and repackage it into your own nuget, or work with the .dlls directly. This is sketchy but it works. Commented Jul 9 at 10:00

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.