A type provider is simultaneously a tool and a library. There is a component that runs at compile-time (also called "design-time") and a component that runs at runtime. F# type providers are hosted by applications using FSharp.Compiler.Service.
First, some terminology:
The Type Provider Run Time Component (TPRTC) is the component referenced by #r
or -r:
on the command line or other configration of a host tool, e.g. FSharp.Data.dll
.
The Type Provider Design Time Component (TPDTC), e.g. FSharp.Data.DesignTime.dll
is the DLL that gets loaded into host tools.
The host tool is, for example fsc.exe
or fsi.exe
, or some tool hosting FSharp.Compiler.Service.dll
such as devenv.exe
or FsAutoComplete.exe
.
This contains either a TypeProviderAssembly
attribute indicating that this component is also a TPDTC, or TypeProviderAssembly("MyDesignTime.dll")
attribute indicating that the name of the design time component.
TPRTCs are normally netstandard2.0
or above.
The Type Provider Design Time Component (TPDTC) is, for example, FSharp.Data.DesignTime.dll
.
This is the DLL that gets loaded into host tools, and may be the same physical file as the TPRTC. This component includes the ProvidedTypes.fs/fsi files from the type provider SDK.
TPDTC are generally netstandard2.0 or netstandard2.1 components.
See Loading type providers for the rules to find TPDTC components.
The following guidance extends https://fsharp.github.io/2014/09/19/fsharp-libraries.html.
A type provider for a data source or schema format XYZ can often be placed in FSharp.Data
, e.g. “FSharp.Data.XYZ”.
A type provider for interoperability can often be placed inFSharp.Interop
, e.g. “FSharp.Interop.XYZ”.
Good type provider naming examples:
FSharp.Text.RegexProvider
FSharp.Azure.StorageTypeProvider
Here are some examples of existing type providers that aren't too bad (they are clear) but could be renamed to follow the guidelines:
ExcelProvider
(better would be FSharp.Interop.ExcelProvider
)RProvider
(better would be FSharp.Interop.RProvider
)ApiaryProvider
(better would be FSharp.Data.ApiaryProvider
)SQLProvider
(better would be FSharp.Data.SQLProvider
)DynamicsNAVProvider
(better would be FSharp.Interop.DynamicsNAVProvider
)DynamicsCRMProvider
(better would be FSharp.Interop.DynamicsCRMProvider
)The nuget package layout of a type provider follows these rules:
lib
typeproviders/fsharp41
For examples:
|
Runtime dependencies are often the same as design time dependencies for simple type providers. For more complex providers these can be different
These dependencies are packaged and managed differently
The runtime dependencies are normal nuget package dependencies just like any normal .NET library. For example, if your type provider has Newtonsoft.Json as a runtime dependency then your nuget package should list this a normal nuget dependency.
The design dependencies must all be bundled alongside your design-time DLL. The design-time component is a component loaded into a tool like Ionide or Visual Studio and must be loadable without referencing any other packages.
F# type providers are hosted by applications using FSharp.Compiler.Service. These notes describe the lifetime and typical resource usage of type provider instances for applications that incorporate FSharp.Compiler.Service (the host).
Each time the host application (e.g. devenv.exe) checks a file using type providers (e.g. containing JsonProvider<"...">
), one or more new TP instantiations may be created, along with subsequent calls to ApplyStaticArguments
.
The lifetime of TAST structures is as long as they are held in the IncrementalBuilder, or you hold on to FSharpCheckFileResults, or FSharpCheckProjectResults, or FSharpAssemblyContents.
Some type providers need to build code via explicit calls to FSharp.Quotations.Expr.*
rather than via quotation
literals. Frequently, this is needed when code must instantiate generic methods or types. However, in some cases limitations
of the F# quotations API are reached.
In these cases, follow these rules
ProvidedTypeBuilder.MakeGenericType(type, typeArguments)
rather than type.MakeGenericType(typeArguments)
ProvidedTypeBuilder.MakeGenericMethod(methInfo, methTypeArguments)
rather than methInfo.MakeGenericType(methTypeArguments)
open ProviderImplementation.ProvidedTypes.UncheckedQuotations
and make quotation nodes representing calls and other operations using Expr.CallUnchecked
.If you don't do this you may get errors like
|
or
|