Comments (3)
@sgryt thanks for the report.
From what I understand, it is more likely to be a dotnet/sdk issue or (maybe) dotnet/fsharp one, there is nothing in the FSharp.Data.SqlClient
nuget package that is related to deciding which FSharp.Core your console application should use, and the binding redirect handling is specific to msbuild, AFAIU.
I have had my own issues over the years of using dotnet framework, related to assembly bindings, and generally resort to using paket to handle the the consistency of those, but your mileage may vary.
I'll keep the ticket open to track the progress on resolving it, but encourage you to gather a minimum reproduce project, and opening an issue on dotnet/sdk.
Hope you'll be able to understand why this is occurring, and confirmation it reproduces (please provide a self contained zipped sample where it is minimum steps from command line to build, to make sure the sdk team can look into it).
from fsharp.data.sqlclient.
@smoothdeveloper: I'm not deeply familiar with type provider internals, but I
believe to have identified the underlying cause of the exception. Please correct
me if my reasoning is off.
The exception appears to be caused by a general limitation across type providers
when the F# compiler is referencing a different version of FSharp.Core than the
application being compiled.
Code like
type Datawarehouse = SqlProgrammabilityProvider<"name=DataWarehouse">
let checkReady = new Datawarehouse.read_json.check_if_ready_for_load(connectionString)
async {
// Exception raised here. isReady is of type option<bool> which is important later.
let! isReady = checkReady.AsyncExecute()
...
}
results in
System.IO.FileLoadException: 'Could not load file or assembly 'FSharp.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)'
with a stack trace of
[Managed to Native Transition]
mscorlib.dll!System.RuntimeTypeHandle.GetTypeByName(string name, bool throwOnError, bool ignoreCase, bool reflectionOnly, ref System.Threading.StackCrawlMark stackMark, System.IntPtr pPrivHostBinder, bool loadTypeFromPartialName) Unknown
mscorlib.dll!System.Type.GetType(string typeName, bool throwOnError) Unknown
FSharp.Data.SqlClient.dll!FSharp.Data.SqlClient.Internals.ISqlCommand Implementation.ISqlCommand Implementation(FSharp.Data.SqlClient.Internals.DesignTimeConfig cfg, Microsoft.FSharp.Core.FSharpChoice<string, System.Data.SqlClient.SqlConnection, System.Data.SqlClient.SqlTransaction> connection, int commandTimeout) Unknown
The offending type provider code is at
https://github.com/fsprojects/FSharp.Data.SqlClient/blob/master/src/SqlClient/ISqlCommand.fs#L111:
let itemType = Type.GetType( itemTypeName, throwOnError = true)
Here itemTypeName
is a "type string", baked into the application by the
SqlClient.DesignTime
.
De-sugaring the async computation expression above and reverse compiling the
design-time generated code to C#, DesignTimeConfig
(from the stack trace) is
instantiated as
ISqlCommand\u0020Implementation checkReady = (ISqlCommand\u0020Implementation)new ISqlCommand\u0020Implementation(new DesignTimeConfig("SELECT read_json.check_if_ready_for_load()", false, Array.Empty<SqlParameter>(), ResultType.Records, ResultRank.ScalarValue, Mapper.GetMapperWithNullsToOptions(Dsl.Consumption.checkReady@170.@_instance, Dsl.Consumption.checkReady@170-1.@_instance), "Microsoft.FSharp.Core.FSharpOption`1[[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], FSharp.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", new Tuple<string, string>[]
{
new Tuple<string, string>("", "System.Boolean")
}), FSharpChoice<string, SqlConnection, SqlTransaction>.NewChoice1Of3(item), commandTimeout);
Notice how part of the instantiation consists of FSharp.Core, Version=8.0.0.0
:
"Microsoft.FSharp.Core.FSharpOption`1[[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], FSharp.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
which is the return type from calling the type provider and the underlying
source of the exception.
Digging through SqlClient.DesignTime
, I came upon
https://github.com/fsprojects/FSharp.Data.SqlClient/blob/master/src/SqlClient.DesignTime/DesignTime.fs#L31:
| Some x -> Expr.Value( x.ErasedTo.AssemblyQualifiedName)
where I believe x.ErasedTo
is the System.Type
returned by the type provider,
i.e., option<bool>
in this case.
The underlying issue can be illustrated by creating a .NET console application
and in its project file pin FSharp.Core
to a version different from the latest
version installed on the machine (.NET 4.8 and .NET 8 in this case):
<PackageReference Update="FSharp.Core" version="7.0.0" />
Then include the following code:
open Microsoft.FSharp.Quotations
[<EntryPoint>]
let main _ =
let t: System.Type = typeof<option<bool>>
let e: Expr = Expr.Value(t.AssemblyQualifiedName)
printfn "%A" e
// Value ("Microsoft.FSharp.Core.FSharpOption`1[
// [System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],
// FSharp.Core, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
0
Not pinning FSharp.Core
makes e
become Version=8.0.0.0
.
As during compilation FSharp.Data.SqlClient.DesignTime.dll
is loaded into the
F# compiler process, code in the design-time executes in the context of the
compiler, i.e., not subject to any assembly redirect in the program being
compiled. The compiler itself doesn't have an assembly redirect downgrading its
version of FSharp.Core
to 7.0.0.0.
When the equivalent of
let t: System.Type = typeof<option<bool>>
let e: Expr = Expr.Value(t.AssemblyQualifiedName)
evaluates inside the compiler, the result is a "type string" containing
FSharp.Core, Version=8.0.0.0
.
Now, the compiler is aware of the FSharp.Core
version it's compiling the
application against. MSBuild resolves and passes this information on the
command-line when invoking the compiler:
C:\Program Files\Microsoft Visual Studio\2022\Community/Common7/IDE/CommonExtensions/Microsoft/FSharp/Tools/fscAnyCpu.exe -o:obj\Debug\net48\Test.exe
...
-r:C:\Users\tester\.nuget\packages\fsharp.core\7.0.0\lib\netstandard2.0\FSharp.Core.dll
...
Dsl.fs
Program.fs
But this information may be lost/hard to get at inside the design-time of a type
provider -- at least with current type provider infrastructure.
So either (1) upgrade the application to the latest version of F# installed, (2)
include an assembly redirect downgrading FSharp.Core
, or (3) add a
global.json
pinning the .NET version.
from fsharp.data.sqlclient.
I believe to have identified the underlying cause of the exception. Please correct me if my reasoning is off.
I'm unlikely to "correct", but share my understanding (which can be misguided, as this is either a fsharp or TP SDK issue, not an dotnet/sdk one), and your analysis seems thorough (based on looking up IL types emitted by the compiler, and investigating the quotations in the type provider implementation).
I believed the binding redirects were not needed anymore but in .NET framework, but it sounds I was too hopeful.
The analysis you make about the TP in the compiler is correct, I'm not sure if the newer versions of the Type Provider SDK (we are on one of the early that supported .net core, sdk v2 era) help solving the issue, nor if the type provider implementation should define things for the TP SDK to do the relinking, I only know any time I tried to upgrade the TP SDK, it was a bit though, or I couldn't make it work (but also due to sdk v2 in the master branch and not enough know how).
Let's keep the issue open (others will find useful information, and learn about binding redirect when they have same error), and when I'm able to update Type Provider SDK while keeping everything green on CI, we should give it another look, in case there is some form of detection between runtime references versus what the compiler binds against.
Thanks @ronnieholm for giving a shot at reproducing @sgryt issue, and all the analysis.
For now, I effectively can't solve those use cases, and only encourage people to closely care for their binding redirects, msbuild or paket can be used to deal with it in ways which aren't 100% manual.
from fsharp.data.sqlclient.
Related Issues (20)
- Dacpac support info HOT 3
- "F# Formatting" link is broken
- Can't build/run from the commandline, but can from Visual Studio 2019 HOT 2
- Question: Creating a provider without an access to DB HOT 3
- SqlEnumProvider breaks VS 2019 HOT 2
- Not platform detection Fable HOT 1
- Build is broken without full VS installation
- Fixed length binary columns in user defined table types fail when constructed HOT 8
- Cannot use User Defined Table Types with the SqlCommandProvider HOT 5
- .NET 6 support HOT 6
- One line summary of the bug HOT 2
- TVP Column Ordering is incorrect as of version 2.1.0
- Cannot use parameter name more than once in a script HOT 3
- System.Data.SqlClient is not supported on this platform. HOT 5
- Conversion failed when using User Defined Table Types HOT 1
- Any 2023 tricks for running on Windows? HOT 3
- NullReferenceException in SqlConnection.UseLocally HOT 1
- Support for 'Active Directory Interactive' authentication HOT 3
- SQL LIKE operation doesn't recognize variable HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fsharp.data.sqlclient.