I've been using the XmlProvider from FSharp.Data to generate types corresponding to a fragment of XML which I am storing in a file in the source directory of the F# project being built.
I parameterize the XmlProvider with the path of the file. This code is then compiled into a DLL.
If I then reference the compiled DLL of this assembly from another F# project which is unable to read from the source directory then, at compile time for that project I get the error FS3033 'Cannot read sample XML from 'config_schema.xml': Could not find (path)'.
Why is this? My understanding was that after compilation, the type corresponding to the XML sample was a standard fully fledged type and this is what should end up in the compiled DLL. Why does a consumer of the type (code in the second project) still need to reference the sample to compile?
This is subtle. When you compile code that uses a erasing type provider like XmlProvider
or JsonProvider
into a DLL, the compiler does not actually store the generated types. This means that when you reference the DLL from another library, the compiler will trigger the type provider again - even though the end-user code (user of your library) is not actually using the type provider.
This means that the type provider needs to be able to access the sample, even after you compiled the library and distributed it to your users.
You could use relative paths and copy the samples with your library, but that's not very elegant. We actually have exactly the same problem in F# Data Toolbox which is a library that uses JsonProvider
under the cover.
F# Data has a special option for this purpose. You can embed the sample as a resource when compiling the DLL - that way, the type provider will first look for an embedded resource (which works after you distributed your library) and if it's not there, it will look for a local file (which you need when compiling the library).
See how this is done in F# Data Toolbox here:
type Response = JsonProvider<"json/bearer_token.json",
EmbeddedResource="FSharp.Data.Toolbox.Twitter,bearer_token.json">
The embedded resource is set in the project file:
<EmbeddedResource Include="json/bearer_token.json">
<Link>json/bearer_token.json</Link>
</EmbeddedResource>
I believe this is supported for both JSON and XML providers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With