Skip to content

Conversation

@edwardneal
Copy link
Contributor

Description

This PR lays the groundwork to enable a single build of SqlClient to work for both Windows and non-Windows platforms. It also tests the water on the approach.

#3810 helped the shared SqlClient project to build by using the _WINDOWS and _UNIX conditional compilation symbols; this enables the merge to proceed, but we can move these checks to run-time and make the build process simpler.

I've started this process with a simple IsWindows member in ADP, and using this to throw PlatformNotSupportedExceptions in the three Windows-specific public types: SqlColumnEncryptionCngProvider, SqlColumnEncryptionCspProvider and SqlFileStream. As a result of this, the Unix-specific files are no longer necessary and we can remove them.

SqlFileStream makes a handful of pinvokes, and as a result I've removed the _WINDOWS guard on these pinvokes and their associated types to enable the project to compile. I expect that eventually, this'll happen to the entirety of the interop layer.

I've put some focus here on IL trimming, making sure that publishing for Unix will strip away the Windows interop layer. This procedure seems a little limited: I can't use my preferred approach of using a throw helper, because the trimmer can't see that the method throws, so keeps the code paths which use the Windows interop layer around.

@benrr101 @paulmedynski this intersects with the conversations around TargetOs going on in #3837.

Issues

None.

Testing

While SqlFileStream doesn't have any unit tests to verify that it throws a PNSE on Unix, SqlColumnEncryptionCngProvider and SqlColumnEncryptionCspProvider do. These pass.

I also created a sample application which instantiates a SqlFileStream, then published this using a Linux target with trimming enabled and viewed the result in ILSpy. Every code path except for the one which throws PlatformNotSupportedException was removed, and this led to the Windows interop layer also being removed.

Also clean up the netfx-only s_isWindowsNT variable - this was originally used to distinguish between Windows 9x and Windows NT!
We only throw a PlatformNotSupportedException in the constructor; if this throws, there's no way execution can reach a property or method.
This is necessary because when an application using SqlClient is being published, the IL trimmer doesn't see that the throw helper throws an exception, and thus doesn't eliminate the code paths which call Windows-specific APIs. As a result, the Windows-specific API paths aren't removed from executables published for a Linux platform.
@edwardneal edwardneal requested a review from a team as a code owner December 13, 2025 00:17
@paulmedynski paulmedynski self-assigned this Dec 15, 2025
Copy link
Contributor

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, with a couple of comments.

@paulmedynski
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants