3

My background: I have a DLL that is being developed in Visual Studio 2017 and will be loaded from a proprietary application -- this is my only way to export the data in their proprietary formats to a database I am building. The proprietary application provides a DLL containing their data structures and so forth, which I have been able to add as a dependency (but only for some reason with .NET Framework 4.6.x, does not work with 4.7.x). The publisher's code samples for this are all in C#, but I might prefer to program my plugin in F#, since I am addicted to Haskell and always wanted to learn an ML dialect. However I am still in very early stages of learning either C# or F#. Think "experienced Linux-based programmer who has only the most basic understanding idea about this whole Windows ecosystem."

My problem: I build this DLL, I load it from the proprietary application, and I get a pop-up reporting the following error:

Exception Type:FileNotFoundException
Details: could not load file or assembly 'FSharp.Core,
Version=4.4.1.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a' or one of its 
dependencies. The system cannot find the file specified.

This seems to be fundamentally different from Brent Tranberg's StackOverflow question where he was at least able to get the dependencies loaded; they just complained at him afterwards. Here the dependencies are not even being loaded. So the problem is (I think) that the NuGet package is not getting globally installed and it's also not getting copied into the build output, and as a consequence the proprietary application doesn't ever know about it. The only helpful thing I have found so far online has been telling me that apparently what I'm trying to do is an antipattern: F# libraries are apparently only ever supposed to be used from F# applications which can define what version of F# Core they bind to; they are never supposed to actually include the F# Core library itself.

I must be misunderstanding something here because that sounds crazy to me. On .NET, DLLs are a much bigger deal than just "a library of F# code that I can call from my F# application": they are a core interoperability construct that multiple different languages can use to talk to each other. How do I include this F# dependency in a library which is not destined for an application that knows anything about F# code at all?

Should I violate the part of the guidelines before and "assume FSharp.Core is in the GAC" -- and if so, how the heck do I start doing that? (I am warned that "VS2017 doesn’t install FSharp.Core to the GAC" by the same source.) Or, I mean, is there a nice way to statically link this code since the dynamic linking is not working? Is there a way to convert a NuGet PackageReference into a Reference so that I can add <Private>true</Private> so that it is included in the DLL folder? What other options do I have?

(I have since tried the latter and it does not actually copy the needed DLL into the build folder. I have also tried adding the Fsharp.Core DLL directly as a "Dependency" -- still no dice. It does work if I copy it over every time I build but this seems like a very flimsy approach to a deeper problem that Visual Studio could not possibly be having.)

CR Drost
  • 9,637
  • 1
  • 25
  • 36
  • .NET DLLs are not the same as Windows DLLs. .NET DLLs are indeed "just a library of code". So your F# library happens to be using some other library, and therefore that other library must also be present wherever you want to use your library. This is no different from using other libraries. – Fyodor Soikin Jan 05 '18 at 18:45
  • @FyodorSoikin Thanks for your comment, I rewrote "On Windows" to "On .NET" to clarify that yes, indeed, I am not talking about Windows DLLs but .NET DLLs. I am still stuck however on this problem of "There seems to be no way to get Visual Studio 2017 to include this file in its build output short of copying it over after the build completes," which is a very strange problem that I am very surprised to be stuck on. – CR Drost Jan 05 '18 at 19:16

1 Answers1

1

(Warning: self-answer, workaround)

Some more Googling eventually led to a very tangential thread about NuGet being confused about the version of .NET Core, which would otherwise be unhelpful except that one of the major developers (Kevin Ransom) says that the reference to FSharp.Core is being implicitly included because "there is no need for the majority of projects to explicitly reference FSharp.Core". I suppose F# libs being used from C# is not "the majority," but if this is not supported at all I am very surprised. However he has a suggestion for people who do want to explicitly reference it, and that worked for me as a workaround for this issue.

So my workaround looks like this:

  • Close Visual Studio 2017.
  • Open <ProjectName>.fsproj in a separate text editor.
  • In the leading <PropertyGroup> add Kevin Ransom's suggestion, <DisableImplicitFSharpCoreReference>true</DisableImplicitFSharpCoreReference>.
  • Track down the relative path to FSharp.Core.dll; in my case it was in ..\..\..\..\.nuget\packages\fsharp.core\4.2.3\lib\net45\FSharp.Core.dll
  • Add that to the project as an ItemGroup holding a Private Reference (this lives in parallel to the PropertyGroup). That reference therefore for me looks like this:

      <ItemGroup>
        <Reference Include="FSharp.Core">
          <HintPath>..\..\..\..\.nuget\packages\fsharp.core\4.2.3\lib\net45\FSharp.Core.dll</HintPath>
          <Private>true</Private>
        </Reference>
      </ItemGroup>
    

    I did not need to delete a <PackageReference> that NuGet Core had added.

  • Save that file, reopen the solution in Visual Studio 2017, and rebuild.
  • Then FSharp.Core.dll magically appeared in my build folder with my own .dll file.

If this is an awful workaround please let me know in comments! I am really new to all of this and at that wit's-end stage of "Dammit VS just put this stupid file in that stupid directory already!" so if the above steps are a bit desperate, that's why.

CR Drost
  • 9,637
  • 1
  • 25
  • 36
  • Generally explicitly referencing Fsharp.Core in nuget or paket will include it in the packages directory and also copies it to the build output directory. And, (I haven't tried this with dlls), you can specifiy the `--standalone` flag in the Other flags section of the Build settings in VS. That will include Fsharp.Core in the compiled assembly. – s952163 Jan 06 '18 at 00:52