dotnet / SqlClient

Microsoft.Data.SqlClient provides database connectivity to SQL Server for .NET applications.
MIT License
857 stars 286 forks source link

How to prevent publishing SNI dll when using AppContext switch for managed networking? #2824

Closed Ririshi closed 2 months ago

Ririshi commented 2 months ago

I have a framework-dependent single-file executable project that I would like to publish without having to bundle native libraries. I found the AppContext switch to use managed networking, which eliminates the need for the native SNI dll. However, when publishing my application, the SNI dll is always placed next to the executable, even though it is not actually used at runtime.

How can I best prevent the SNI dll from being published alongside the executable? I would be happy to hardcode a workaround into my csproj file, but I have not found a way yet to do this in a good way. The only workaround that I currently know of is to add a post-publish target that deletes the SNI dll, but that is not a very elegant solution.

On another note, it would be great if there was a compile-time configuration to switch between managed networking and native SNI. That way, the dependency on the native SNI dll would be entirely eliminated if managed networking is enabled.

campersau commented 2 months ago

Maybe this is possible with https://github.com/0xced/Chisel and <ChiselPackage Include="Microsoft.Data.SqlClient.SNI.runtime" />

Ririshi commented 2 months ago

Thanks for the suggestion, that looks promising. It looks like Chisel doesn't (yet) work with class libraries, which means I'd have to set it up for all of my executable projects. I only mentioned a single project but in reality there are many projects that are all consuming the same EF Core project. I'm trying to set it up with a Directory.Build.props file now, will update here if it works out.

Ririshi commented 2 months ago

It appears I've found out how to do this. Adding the following block into my Directory.Build.props file defines Chisel as a dependency for all executable projects, omits the SNI dll from all of those projects while also enabling managed networking. Perhaps I can add another condition to only do this if the Microsoft.Data.SqlClient package is a (transient) dependency, but I don't know how to write a conditional basd on other dependencies yet.

An interesting point: apparently it is possible to set an AppContext switch by using RuntimeHostConfigurationOption in MSBuild. I haven't seen it documented anywhere officially, so proceed at your own risk, but it seems to be working for us so far.

<ItemGroup Condition="'$(OutputType)'=='Exe'">
  <PackageReference Include="Chisel" Version="1.0.0">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  </PackageReference>
  <ChiselPackage Include="Microsoft.Data.SqlClient.SNI.runtime" />
  <RuntimeHostConfigurationOption
    Include="Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows" Value="true" />
</ItemGroup>
dauinsight commented 2 months ago

@Ririshi It looks like you've been able to find a solution, but I will bring this to the team to see if an alternative option is available.

Ririshi commented 2 months ago

Thank you, much appreciated.

While my suggested solution does work, it is a bit roundabout and feels hacky, because Chisel does not support dependency removal directly on class libraries. Enabling Chisel on all executable projects works, but some don't use my EF Core class library. This causes Chisel to generate build warnings saying that those projects do not have the SNI.runtime package in their dependency graph. I've disabled this warning (CHISEL002) for now using NoWarn.

As I said before, the best alternative in my opinion would be to have an MSBuild option that switches managed networking for the project in which it is set, as well as any projects referencing it. Ideally, it would work both for projects that directly reference M.D.SqlClient as well as projects that reference it as a transitive dependency, e.g. through EF Core.

The same could be said for Azure support, which is what Chisel was made for in the first place. That part might be irrelevant / off-topic though, since I also read something about creating separate packages to support on-prem and Azure separately.

JRahnama commented 2 months ago

the SNI .targets file have a variable as $(CopySNIFiles), can you try with your msbuild command and add -p:CopySNIFiles=false to see the outcome?