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

Error opening a library that uses JsonProvider with an embedded resource #1191

Open
ScottShingler opened this issue Aug 20, 2018 · 18 comments
Open

Comments

@ScottShingler
Copy link

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.

@ArtemyB
Copy link

ArtemyB commented Dec 19, 2018

@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.

@fischgeek
Copy link

fischgeek commented Apr 6, 2020

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.

@ArtemyB
Copy link

ArtemyB commented Apr 6, 2020

@fischgeek have you added "boards.json" to the project as an embedded resource?

@fischgeek
Copy link

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?

@ArtemyB
Copy link

ArtemyB commented Apr 6, 2020

@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).

@fischgeek
Copy link

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.

@ArtemyB
Copy link

ArtemyB commented Apr 6, 2020

@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).

@fischgeek
Copy link

@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?

@ArtemyB
Copy link

ArtemyB commented Apr 6, 2020

@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.

@fischgeek
Copy link

fischgeek commented Jun 20, 2020

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

  1. Added a sample json file to my library project: Samples\board.json
  2. Marked the sample json file as an EmbeddedResource in the file's Properties screen under Build Action
  3. Declared the type using the JsonProvider
type Board = JsonProvider<"Samples/board.json", EmbeddedResource = "TrelloConnectFSharp, TrelloConnectFSharp.Samples.board.json", RootName = "Board">
  1. 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)
  1. Built the library project -> Successful, no errors.

The Console Project

  1. Added the library DLL as a reference (note, I did not add as "Existing project", I only located the DLL and referenced that).
  2. Opened the library with open TrelloConnectFSharp
  3. 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?

@ArtemyB
Copy link

ArtemyB commented Jun 21, 2020

@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).

@fischgeek
Copy link

fischgeek commented Jun 22, 2020

@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.

@ArtemyB
Copy link

ArtemyB commented Jun 22, 2020

@fischgeek and when you reference the project, not just the DLL, does all work?

@fischgeek
Copy link

@ArtemyB actually, no. It doesn't. Interesting.

@ArtemyB
Copy link

ArtemyB commented Jun 22, 2020

@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".

@fischgeek
Copy link

fischgeek commented Jun 22, 2020

@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).

@fischgeek
Copy link

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

@ArtemyB
Copy link

ArtemyB commented Jun 23, 2020

@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).

psfinaki added a commit to psfinaki/FSharp.Data that referenced this issue Nov 20, 2020
I was struggling with that and things were not working until I found [this comment](fsprojects#1191 (comment)) noting that point about project file. I think it would be useful for others as well.
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

3 participants