Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression with published application: PlatformNotSupportedException #445

Closed
davedx opened this issue Feb 26, 2020 · 5 comments
Closed

Regression with published application: PlatformNotSupportedException #445

davedx opened this issue Feb 26, 2020 · 5 comments

Comments

@davedx
Copy link

davedx commented Feb 26, 2020

Describe the bug

We have a .NET core application that is built and published inside a dockerfile. When we upgraded EF core to 3.1 and deployed our app, it started crashing at runtime in the SqlClient constructor with a PlatformNotSupportedException. After some investigation we determined the issue is related to how SqlClient is deployed with dotnet publish; also upgrading only SqlClient in isolation would result in the same crash. Running a shell inside the docker image it appears the correct SqlClient DLL for the platform (Linux) is not copied to the root of the application.

One workaround is to remove the --runtime linux-x64 flag from dotnet publish. Then it works. But this produces a different type of build (not self contained).

Exception message:
System.PlatformNotSupportedException: Microsoft.Data.SqlClient is not supported on this platform.

Stack trace:   
at Microsoft.Data.SqlClient.SqlConnection..ctor(String connectionString)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.CreateDbConnection()
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.get_DbConnection()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.CreateCommand(RelationalCommandParameterObject parameterObject, Guid commandId, DbCommandMethod commandMethod)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at System.Linq.Queryable.First[TSource](IQueryable`1 source)
   at EFGetStarted.Program.Main(String[] args) in /src/Program.cs:line 14

To reproduce

Clone this repo: https://github.com/davedx/sqlclient-repro

Then run:

docker build -t efgs -f ./Dockerfile.custom.dotnet.3.1 .

docker run efgs

Expected behavior

Previous to upgrading SqlClient, this dockerfile and deploy process worked and app would run without crashing.

Further technical details

Microsoft.Data.SqlClient version: 1.0.19269.1
.NET target: (Core 3.1)
SQL Server version: (SQL Server 2019)
Operating system: (Docker container)

Additional context

There seems to be a related issue here: dotnet/runtime#29522

But we are on a newer version of dotnet core than the version in the above issue that fixed the issue. I'm happy to also open an issue no that repo if you think it's an issue with a different component but thought I had to start somewhere. :)

@davedx
Copy link
Author

davedx commented Feb 26, 2020

I figured this out, after almost a solid week of debugging...

There was a change in dotnet build in 3.0+ that meant dotnet build now pulls nuget packages in whereas before it did not. So if you don't specify --runtime to the build command and it runs before publish, it will pull in the default dlls, then publish will see the dlls are there and not update them with the correct ones for the platform/runtime.

It still seems strange to me though, because in my dockerfile I am on Linux so I would expect dotnet build without --runtime to pull in the "unix" dll of SqlClient. But I guess it doesn't.

https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#build-copies-dependencies

@cheenamalhotra
Copy link
Member

cheenamalhotra commented Feb 26, 2020

Cool! I've been wrapping my head around this one, and saw same problem, it is due to "lib" folder dlls getting copied which is not expected in Linux or even Dotnet Core. Runtime libraries should override. According to Nuget documentation here:

Please note, NuGet always picks these compile or runtime assets from one folder so if there are some compatible assets from /ref then /lib will be ignored to add compile-time assemblies. Similarly, if there are some compatible assets from /runtimes then also /lib will be ignored for runtime.

Which makes sense but doesn't seem to be true in this case?
The same issue is reproducible by building with msbuild on Windows btw, so it's not Unix specific.

I was able to make it work by adding this target to csproj:

  <Target Name="PreventCopyOfLibDlls" AfterTargets="ResolveReferences">
    <ItemGroup>
      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.RuntimeIdentifier)' == ''" />
    </ItemGroup>
  </Target>

If there is no runtime identifier (applies to lib*.dll), we don't want those to be included.

Related argument could be that runtimes\unix\... DLLs should be used when setting linux, ubuntu, osx values for --runtime option, but doesn't look like linux-x64 in this case is inclusive and is able to consume runtimes\unix\... DLL.

Also that seems to be applicable to dotnet CLI only, not msbuild. So this is clearly a bug in .NET Core SDK.

@cheenamalhotra
Copy link
Member

Hi @davedx

Also to add:

One workaround is to remove the --runtime linux-x64 flag from dotnet publish. Then it works. But this produces a different type of build (not self contained).

This is true since we ship runtimes for "unix", which is expected to be a fallback folder for any related runtime.

Previous to upgrading SqlClient, this dockerfile and deploy process worked and app would run without crashing.

Can you elaborate to which version of SqlClient worked well for you before?

@cheenamalhotra
Copy link
Member

Hi @davedx

As per comment https://github.com/dotnet/runtime/issues/33046#issuecomment-593714200 this behavior is by design. Let me know for any more questions you have.

@davedx
Copy link
Author

davedx commented Mar 3, 2020

Hi @cheenamalhotra,

Thanks a lot for following up on this issue, it's appreciated. I confirm this is caused by the sdk's behaviour and it's not sqlclient's fault :) Maybe it would be nice to add a line about this to the FAQ entry for PlatformNotSupported Exception to help future travellers. Have a good week.

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

No branches or pull requests

2 participants