F# TypeProvider 无法加载类型

F# TypeProvider cannot load type

我正在尝试使用 F# 类型提供程序编写一个简单的 SOAP 客户端。完整程序为:

open System
open System.Runtime.Serialization
open System.ServiceModel
open Microsoft.FSharp.Data.TypeProviders

type EntrezService = WsdlService<"http://eutils.ncbi.nlm.nih.gov/soap/v2.0/eutils.wsdl">

[<EntryPoint>]
let main argv =
    let client = EntrezService.GeteUtilsServiceSoap()
    try
        let req = EntrezService.ServiceTypes.eSearchRequest()
        let res = client.run_eSearch req
        printfn "%A" res
    with
        | ex ->
            let rec inner (ex : Exception) =
                if ex.InnerException <> null then
                    inner ex.InnerException
                printfn "%s" ex.Message
            inner ex
    0

不幸的是,应用程序似乎在进行 SOAP 调用之前就崩溃了,并出现以下 TypeLoadException:

Could not load type 'UrlTypeLNG' from assembly 'EntrezGeneAdaptor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null '.

此类型在 WSDL 中定义。我不明白为什么 .NET 会尝试从我的程序集中加载它。

堆栈跟踪表明异常是从 System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping.

抛出的

这是怎么回事,是否有简单的解决方法?等效程序在 C# 中运行良好,那么这是 F# 类型提供程序的问题吗?

在两种情况下,我遇到了类型提供程序 运行 编译的问题,但在 FSI 中没有(反之亦然)。您可能已经找到了第三种类型的提供者仍然有点前沿...

  1. 应用程序中缺少使用类型提供程序的程序集绑定重定向。在此处检查一些 assembly redirect instructions 是否有 FSharp.Core。
  2. GAC 或 Visual Studios 执行目录中的库。我曾经有一个 nuget 包将其自身解压缩到 Visual Studio 的 Common7 目录结构中的某个地方,从那时起 FSI(和类型提供者)always 使用那里的版本因为 Visual Studio 在启动时加载它们。我花了几个月的时间才弄清楚发生了什么。

不知道这些是否是您的问题,但可能值得检查一下。

看来问题是由 WSDL 引起的。该服务定义了一个名为 "UrlType" 的复杂类型,其中包含一个名为 "LNG" 的属性。不知何故,这被错误地组合成 "UrlTypeLNG"。我手动编辑 WSDL 以使用纯字符串而不是复杂类型,它现在似乎可以正常工作了。

如果您正在使用无法编辑其 WSDL 的第 3 方服务,您仍然可以绕过此问题。诀窍是在定义 WSDL 服务类型时使用 LocalSchemaFileForceUpdate。在 LocalSchemaFile 中指定 .wsdlschema 文件名会创建所述文件并定期将缓存的 WSDL 存储在其中。为防止定期重新生成此文件,还包括 ForceUpdate = false。这允许您更改您的类型提供程序使用的临时 WSDL。确保每次都重建以使更改生效。另请注意,如果更改了第 3 方服务的 WSDL,您可能需要手动重做此过程。

类型定义可能如下所示:

type SomeService = WsdlService<"http://3rdparty.net/wsdl/srv.wsdl",
                               LocalSchemaFile = "srv_local.wsdlschema",
                               ForceUpdate = false>