Using F# JsonProvider within a portable class libr

2019-05-09 20:36发布

问题:

I'm trying to use the JsonProvider and I'm getting the following error when I call a function on it:

System.TypeInitializationException was unhandled
Message: An unhandled exception of type 'System.TypeInitializationException' occurred in PortableLibrary1.dll
Additional information: The type initializer for '<StartupCode$PortableLibrary1>.$PortableLibrary1' threw an exception.

I have a basic console application as follows:

module Pinit =
   open FSharp.Data

   type JsonT = JsonProvider<"""..\myFile.json""">
   let doc = JsonT.Load("""..\nyFile.json""")
   let result = doc.GeneratedAt

[<EntryPoint>]
let main argv = 
    printfn "%A" Pinit.doc.GeneratedAt
    0 

When run within the ConsoleApplication it all works as expected. If I create an F# Portable Class library as follows:

module Pinit =
   open FSharp.Data

   type JsonT = JsonProvider<"""..\myFile.json""">
   let doc = JsonT.Load("""..\nyFile.json""")
   let result = doc.GeneratedAt

Create another Console Application and reference that Portable Class Library and call the code as follows:

open PortableLibrary1

[<EntryPoint>]
let main argv = 
    printfn "%A" Pinit.result
    0 

When I run the program then it generates the exception defined above:

I'm suspecting it's because of the versions of FSharp.Core but was wondering whether I was doing something wrong or whether there was a way to get this to work?

Versions:

-- ConsoleApplication --
FSharp.Core = 4.3.1.0

-- PortableClassLibrary --
FSharp.Core = 3.3.1.0
FSharp.Data = NuGet Version: 2.0.0

回答1:

let bindings are compiled into static members, and in .NET when you have an exception in a static initializer the real exception is masqueraded.

If you turn that into a function call by changing to let result() = doc.GeneratedAt and printfn "%A" (Pinit.result()) you'll get the real exception:

Only web locations are supported

Portable profiles don't support accessing the file system. So inside the PCL you can either have web urls or load manually from an embedded resource. See here for an example: https://github.com/ovatsus/Apps/blob/master/Trains/Stations.fs#L65. Or you can load the file with File.ReadAllText in the console project and pass it to the PCL.

This was with a Portable Profile (Legacy) project, which is Profile 47 (and FSharp.Core 2.3.6.0). I then also tested with a Portable Profile project, which is Profile 7 (and FSharp.Core 3.3), and noticed it's not working correctly, it's giving this exception instead

Method not found: 'FSharp.Data.Runtime.JsonValueOptionAndPath FSharp.Data.Runtime.JsonRuntime.TryGetPropertyUnpackedWithPath(FSharp.Data.Runtime.IJsonDocument, System.String)'.

I created a github issue to track that: https://github.com/fsharp/FSharp.Data/issues/521