2
votes

I am trying to write a simple SOAP client using an F# type provider. The complete program is:

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

Unfortunately, it looks like the app crashes before it can even make the SOAP call, with the following TypeLoadException:

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

This type is defined in the WSDL. I don't why .NET would try to load it from my assembly.

Stack trace indicates that the exception is thrown from System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping.

What's going on here, and is there an easy fix? The equivalent program works fine in C#, so is this a problem with the F# type provider?

3
What is the target .NET framework version do you use for your app? .NET framework load types from you assembly, because WsdlService generated type provider and it compile all types in real type in your assembly. BTW, everything works in my FSI screencast.com/t/H6ax57QAM1 - Sergey Tihon
I'm using .NET 4.5. That's interesting that it worked for you. I'll try running my program from another box. Maybe I have a configuration problem of some sort. - brianberns
I tried it from another box and got the same error. FWIW, I'm compiling rather than running from FSI. - brianberns
FWIW, I was able to get this working in FSI as well. Any idea why it doesn't work when compiled? - brianberns
True magic ;) The behavior depend on the service. Could you try another wsdl service from your machine? - Sergey Tihon

3 Answers

1
votes

I've had issues with type providers running compiled but not in FSI (and vice versa) in two cases. You might have found a 3rd one - type providers are still a little bit cutting edge...

  1. Missing assembly binding redirects in the app using the type provider. Check some assembly redirect instructions for FSharp.Core here.
  2. Libraries in the GAC or in Visual Studios execution directory. I once had a nuget package unzip itself into the Common7 directory structure of Visual Studio somewhere, and from then on FSI (and type providers) always used the version there because Visual Studio was loading them on start up. It took me months to work out what was going on.

Don't know if either of these are your problem, but might be worth a check.

1
votes

It looks like the problem was caused by the WSDL. The service defines a complex type called "UrlType", which contains an attribute called "LNG". Somehow, this was getting combined incorrectly into "UrlTypeLNG". I manually edited the WSDL to use a plain string instead of the complex type, and it seems to be working now.

0
votes

You can still bypass this issue if you're working with 3rd party service whose WSDL you cannot edit. The trick is to make use of LocalSchemaFile and ForceUpdate when defining the WSDL service type. Specifying a .wsdlschema file name in LocalSchemaFile creates the said file and regularly stores the cached WSDL in it. To prevent regular regeneration of this file, also include ForceUpdate = false. This allows you to make changes to the ad hoc WSDL your type provider uses. Make sure to rebuild every time for the changes to take effect. Also note that if the 3rd party service's WSDL is changed, you might have to manually redo this process.

The type definition could look something like this:

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