4

I am trying to resolve a MissingMethodException in a pre-compiled F# Azure Function. The exception is thrown when I call an extension method from FSharp.Data.CssSelectorExtensions.

The function is defined in a .Net Framework 4.6.2 class library. I am using the current versions of FSharp.Core (4.2.3) and FSharp.Data (2.3.3). (I have tried older versions of both but the problem persists.) I have added a binding redirect for FSharp.Core per the standard guidance for this kind of problem. The code compiles cleanly but fails when it is executed. It also fails if I attempt to invoke the extension method directly as a simple static method.

Any guidance on how I can get rid of this exception would be much appreciated!

Function Code

module httpfunc

open System.Net
open System.Net.Http
open Microsoft.Azure.WebJobs.Host
open FSharp.Data
open FSharp.Data.CssSelectorExtensions

let Run(req: HttpRequestMessage, log: TraceWriter) =
    async {
        let doc = HtmlDocument.Load("https://google.com")
        let node = doc.CssSelect("div.ctr-p") // <-- method is missing
        return req.CreateResponse(HttpStatusCode.OK)
    } |> Async.RunSynchronously

Exception Message

 mscorlib: Exception while executing function: Functions.httpfunc. 
 mscorlib: Exception has been thrown by the target of an invocation. 
 fsfuncs: Method not found: 'Microsoft.FSharp.Collections.FSharpList`1<FSharp.Data.HtmlNode> CssSelectorExtensions.CssSelect(FSharp.Data.HtmlDocument, System.String)'.

app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.4.1.0" newVersion="4.4.1.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="FSharp.Core" version="4.2.3" targetFramework="net462" />
  <package id="FSharp.Data" version="2.3.3" targetFramework="net462" />
  ...
</packages>

.fsproj

<Project ToolsVersion="15.0" ... />
  <PropertyGroup>
    <RootNamespace>fsfuncs</RootNamespace>
    <AssemblyName>fsfuncs</AssemblyName>
    <TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
    <TargetFSharpCoreVersion>4.4.1.0</TargetFSharpCoreVersion>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <Name>fsfuncs</Name>
  </PropertyGroup>
  ...
</Project>

Edit

On Fyodor Soikin's advice I've determined that multiple versions of FSharp.Core.dll are being loaded: one from the GAC and one from the NuGet packages folder.

Two versions of FSharp.Core.dll are loaded.

7
  • I would run it under debugger and see which modules get loaded, and whether you get two differently versioned copies of FSharp.Core. Commented Aug 25, 2017 at 17:21
  • I'm not sure how to do that, unfortunately -- to the best of my knowledge Visual Studio doesn't yet have debugger support for F# Azure Functions. Also, can you help me understand how I would get two different versions of FSharp.Core when there's just a single class library involved? That is, where would the second version come from? Commented Aug 25, 2017 at 17:26
  • 2
    There is a way to run Azure Functions locally, check it out. Different versions may come from very unexpected places. One obvious option that comes to mind is the GAC. Commented Aug 25, 2017 at 17:28
  • Cool, thanks for that pointer! It does look like two versions of the FSharp.Core.dll are being loaded (see my edit just now.) Is the solution to remove FSharp.Core.dll from the GAC, or can I otherwise prevent it from being loaded from there? Commented Aug 25, 2017 at 17:47
  • This means that your bindingRedirect didn't take. I would verify the usual suspects now: is the config in the right place? are the versions correct? etc. Commented Aug 25, 2017 at 17:50

1 Answer 1

2

The execution engine behind Azure Functions already loads FSharp.Core.dll (because it depends on F# compiler services to run your F# scripts) and I think you will always get the version of FSharp.Core.dll that is specified by the execution engine's app.config, which is 4.4.0.0.

I might be missing something, but I think your best chance is to make your function use version 4.4.0.0. Could you try removing the explicit FSharp.Core reference? That way, the runtime should load just the (already pre-loaded) version of FSharp.Core.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Tomas, this is helpful. I was doing my best to use the packaged FSharp.Core, but per Fyodor Soikin's comments it seems that the binding redirect I had in place does not work for class libraries and thus isn't a good fit for the compiled functions. I appreciate the pointer to the execution engine app.config; that'll make it easier to keep my FSharp.Core GAC reference in sync with the platform version.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.