FSharp.Data
FSharp.Data copied to clipboard
Error opening a library that uses JsonProvider with an embedded resource
I've encountered some strange behaviour when trying to open a library that uses a JsonProvider with an embedded resource.
Given then following module defined in a separate library:
module MyLib
open FSharp.Data
type MyJsonConfig = JsonProvider<"sample.json", EmbeddedResource="MyLib, sample.json">
type MyFoo = { Foo : string }
let loadMyConfig (path : string) =
let config = MyJsonConfig.Load(path)
{ Foo = config.Foo }
And the following program that references and consumes MyLib
:
open System
open MyLib
[<EntryPoint>]
let main argv =
let config = loadMyConfig("config.json")
printfn "Loaded config: %A" config
printfn ""
printfn "Press any key to exit"
Console.ReadKey() |> ignore
0
I get the following compilation error:
Error FS3033 The type provider 'ProviderImplementation.JsonProvider' reported an error: An index satisfying the predicate was not found in the collection.
For this simple example, there is a workaround to avoid this error: Instead of opening MyLib
, use the fully-qualified name when referencing loadMyConfig
(i.e. MyLib.loadMyConfig
).
There is also an Intellisense issue regardless of whether the workaround is used: If you attempt to dot into MyLib
(i.e. type MyLib.
), Intellisense will show the same error reported above.
I have put together a repro here: https://github.com/ScottShingler/JsonProviderEmbeddedRepro
I should also mention that I'm experiencing the same compilation error in another project, but the workaround of not opening the library module is not solving it. Unfortunately I am unable to share that code since it's proprietary, but I expect the root cause of this issue should be related.
@ScottShingler just had the same issue too, but with XmlProvider
. As I understand the problem is in the format of embedded resource names used in .NET Standard/.NET Core. Try to specify the resource name as follows: EmbeddedResource = "MyLib, MyLib.sample.json"
. Hope it works for you as it worked for me. :)
P.S. This SO answer helped me.
I'm experiencing the same issue with the JsonProvider and the workaround doesn't seem to work for me.
Lib
namespace TrelloConnectFSharp
open FSharp.Data
module Trello =
type Boards = JsonProvider<"boards.json", EmbeddedResource = "TrelloConnectFSharp, TrelloConnectFSharp.boards.json">
let LoadBoardsType (path:string) = Boards.Load(path)
Console App
...
let BoardsType = TrelloConnectFSharp.Trello.LoadBoardsType("TrelloConnectFSharp.boards.json")
Build Error
typecheck error FS3033: error : An index satisfying the predicate was not found in the collection.
The boards.json file is in the root and lib compiles successfully.
@fischgeek have you added "boards.json" to the project as an embedded resource?
Isn't that what this is doing JsonProvider<"boards.json", EmbeddedResource = "TrelloConnectFSharp, TrelloConnectFSharp.boards.json">
?
Should I be manually loading this as a resource file in the Lib?
@fischgeek as I understand this provider parameter only tells the provider to look for the sample JSON-file among the project resources. So if the provider can't find the resource (because it wasn't included in the assembly), it will throw the error. I suspect the phrase An index satisfying the predicate was not found in the collection
is straightly about that (i.e. there is no resource which corresponds to the given parameter).
Right, I understand that, however the Library will compile successfully which lead me to believe it was working as is. I'm still not clear as to if I need to embed the json file in the library project AND declare the type from the file path or if I need to embed the resource json file in the calling project.
@fischgeek not in the calling project. You should embed it only in the library where the type for provider is declared. And also you should specify the provider parameter as you've done initially. After that you should be able to use the library with the types, generated by type provider, without any issues (and without any worries about the sample file).
@ArtemyB Thank you! I'll give that a try! Might be out of context here, but is there anyway to alias the result of .Parse
instead of using Root
as the type and make my own type derived from it?
@fischgeek by "my own type derived from it" you mean inheritance or what? I don't understand completely what are you trying to achieve.
P.S.: I'll try to guess something about aliasing and Root
: you can set custom name instead of "Root" by passing to the provider parameter RootName
your desired name string literal.
Okay. I apologize for nudging this one again. I gave up after a while and now I'm back at it trying to figure it out. Here's what I have done so far but still get the error.
The Library Project
- Added a sample json file to my library project:
Samples\board.json
- Marked the sample json file as an EmbeddedResource in the file's Properties screen under Build Action
- Declared the type using the JsonProvider
type Board = JsonProvider<"Samples/board.json", EmbeddedResource = "TrelloConnectFSharp, TrelloConnectFSharp.Samples.board.json", RootName = "Board">
- Declared a load method (not sure if this is needed or if I can just pipe to
.Parse
but I was following the example of the OP.
let LoadBoardType (path:string) = Board.Load(path) // also tried .Parse(path)
- Built the library project -> Successful, no errors.
The Console Project
- Added the library DLL as a reference (note, I did not add as "Existing project", I only located the DLL and referenced that).
- Opened the library with
open TrelloConnectFSharp
- This simple
let
throws the error as discussed
let myparsedBoard = TrelloConnectFSharp.Trello.LoadBoardType "boardId"
Error: The type provider 'ProviderImplementation.JsonProvider' reported an error: An index satisfying the predicate was not found in the collection.
What am I doing wrong?
@fischgeek , as I've understood your sample JSON is located in the directory "Samples". In that case JsonProvider
's static parameter EmbeddedResource
should be specified as "TrelloConnectFSharp, TrelloConnectFSharp.Samples.board.json"
(whereas your parameter value you specified corresponds to the case when "board.json" is located in the project root directory).
@ArtemyB , thanks for pointing that out. However, I'm afraid the console app still doesn't compile. I also updated my comment with the change you suggested.
@fischgeek and when you reference the project, not just the DLL, does all work?
@ArtemyB actually, no. It doesn't. Interesting.
@fischgeek what are you trying to do when you're calling TrelloConnectFSharp.Trello.LoadBoardType "boardId"
? Load
function expects path to some JSON-file or a plain JSON string which has the same data scheme as your initial JSON in "boards.json".
@ArtemyB The parameter example data "boardId" was a bad example. It would in-fact be the string representation of the json in board.json. I just didn't want to shove all that into a comment as it is rather large. But, it does match. When I normally do this in the same project I use .Parse(jsonStr)
and not .Load(jsonStr)
(not sure of the difference).
FWIW - I found that if I keep my json samples in a directory outside both projects, and provide the full path in the library project it seems to work. This is good enough for me for now. Thanks @ArtemyB
@fischgeek ok, it's already good that you've made it work at least in such way. But I still don't know why it doesn't works in the initial way, because in my case with XML provider (for XML Schema, not sample) all works as intended, even when I reference the library as NuGet-package. And your last version seems to me the same as mine (relying on your description of course).