Referencing external assembly fails - f#

I can't get referencing a private assembly working. I've followed the documentation, but it still fails with the error message:
2016-09-29T19:43:08.615 startup(2,1): error FS82: Could not resolve this reference. Could not locate the assembly "Backend.dll". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. (Code=MSB3245)
Here is the run.fsx file:
#r "Backend.dll"
open System
open System.IO
open System.Net
open System.Net.Http.Headers
open System.Collections.Generic
open CoP
let createResponse json =
let responseJson = Request.handleJson json
let response = new HttpResponseMessage()
response.Content <- new StringContent(responseJson)
response.StatusCode <- HttpStatusCode.OK
response.Content.Headers.ContentType <- MediaTypeHeaderValue("application/json")
response
let Run (req: HttpRequestMessage) =
async {
let! json = req.Content.ReadAsStringAsync()
return createResponse json
} |> Async.StartAsTask
I've also placed the Backend.dll in a bin folder inside the same folder as the function.
What am I missing?

Looks like you ran into a bug with private assembly resolution in the Azure Functions F# implementation.
I've opened this issue for tracking and will have a fix included in the next release:
https://github.com/Azure/azure-webjobs-sdk-script/issues/733
In the meantime, you should be able to reference your private assembly by using:
#r "bin/Backend.dll"
Hope this helps!

If that was a question about .fsx scripts alone, I'd say you're missing the part where you tell FSI where to look for the dll to reference:
#I "bin"
#r "BackEnd.dll"
Is there anything Azure does to put the .\bin folder within the context reachable by #r directive?

Related

Can I create a conditional literal?

In order to create a Json provider I need to pass a literal with the path. There are several people working on the project from different locations, and the paths are different in each case. (Actually only the beginning of each path). I tried to create a literal with pattern matching but the compiler does not accept it. Is there another way to do this?
My failed attempt is below:
open FSharp.Data
[<Literal>]
let bitbucketRoot = // Error message: This is not a valid constant expression
let computerName = Environment.MachineName
match computerName with
| "DESKTOP-G3OF32U" -> "C:\\Users\\Fernando"
| "HPW8" -> #"H:\Dropbox\"
| _ -> failwith "Unknown computer"
[<Literal>] // Error message: This is not a valid constant expression
let projDataPath = bitbucketRoot + #"Bitbucket\VSProjects\Fractal10\Fractal10\data\"
[<Literal>] // Error message: This is not a valid constant expression
let jsonPath = projDataPath + "fractal.json"
type PathInfo = JsonProvider<Sample=jsonPath>
I would advise that you store it in source control and make it a path relative to your project root, assuming you are working out of a common source control repository.
Either that, or host the sample on a public URL. (I wouldn't actually recommend this because including it in your source repository allows versioning and doesn't publicly expose your data)
You cannot create a conditional literal as the other comments point it out. However this is a fairly frequent use case and the way to deal with it is as follows:
#r #"..\packages\FSharp.Data\lib\net40\FSharp.Data.dll"
open FSharp.Data
open System
open System.IO
[<Literal>]
let JsonSource = __SOURCE_DIRECTORY__ + #"\test.json"
type JSonType = JsonProvider<JsonSource>
let json1 = JSonType.GetSamples()
let anotherPath = #"C:\tmp"
let anotherJson = anotherPath + #"\test.json"
let json2 = JSonType.Load(anotherJson)
The __SOURCE_DIRECTORY__ directive will point to the project root (just display it in the REPL) and then you can add the filename to it and make that a literal. If you check in this file into a git repo, then everyone who checks it out can have it in a relative path, and you can refer it when generating the type. When actually using the type or referring to the full file you can just use the .Load() method to load any file, and this doesn't have to be a literal.
There is actually a second way, which could work for you depending on the circumstances, compile a sample, and distribute it as a .dll. You can refer to this and use it directly without having access to the actual file. Please see the Using the JSON Provider in a Library section at the end of the documentation.
I have not tried referring to the json in a config file, it might also be possible.

Using ConfigurationManger in F# project

I am simply trying to use the ConfigurationManager within an F# project but I am getting the error:
This value is not a function and cannot be applied
here is the code:
open System.Configuration
let connectionString = ConfigurationManager.ConnectionStrings["ManagementDb"].ConnectionString
I have also referenced the System.Configuration library.
I haven't verified this in Visual Studio, but usually there is a dot ('.') when using an F# index.
i.e.
let connectionString = ConfigurationManager.ConnectionStrings.["ManagementDb"].ConnectionString

F# interactive window folder and type provider default folder

I already changed the folder to my project folder. F# interactive:how to display/change current working directory
However, it got the following error when I sent let xml = XmlProvider<"./DbToken.xml">.GetSample() to interactive window.
DbShared.fs(66,11): error FS3033: The type provider 'ProviderImplementation.XmlProvider' reported an error: Cannot read sample XML from './DbToken.xml': Could not find file 'C:\Users\a\AppData\Local\Temp\DbToken.xml'.
You can set Environment.CurrentDirectory as in the comment but you can also specify the path to the xml file:
[<Literal>]
let xmlpath = __SOURCE_DIRECTORY__ + "/test.xml"
And then say: let xml = XmlProvider<xmlpath>.GetSample()

Fsx execution path

I have a c# .net library I am looking to use within FSI/FSX. As part of the initialization of the .net lib, by default it expects and references a custom config file (MyAppConfig.xml) which loads various things before it can be used. When using it in c# it gets copied to the bin folder and the app by default expects it to be there and references it there unless there is a specific entry in the app.config to tell it otherwise. (I should add that it does it all by convention rather than injecting a path + filename, as per NLog, say)
I have an f# source file in a console app which will execute this initialization find, but I can't quite work out how to achieve this with FSI/FSX.
So my program.fs looks simply like
open System
open myApp
module Program =
[<EntryPoint>]
let Main(args) =
myApp.Initialization.Load() // references MyAppConfig.xml
Console.WriteLine("do my stuff!")
Console.ReadLine() |> ignore
0
If I try and do the same in FSI or using FSX, I have
#r #"E:\...path to MyApp...\MyApp.dll"
#I #"E:\...path to MyAppConfig.xml ..."
Environment.CurrentDirectory <- #"E:\...path to MyAppConfig.xml ..."
myApp.Initialization.Load() |> ignore // fails ... can't find MyAppConfig.xml
//do my stuff
I suspect that I've not got the paths quite right.
I'd be grateful of a steer
EDIT:
So I've managed to attach a debugger to the c# lib and see where it is looking for the config file - turns out it is "c:\Program Files\Microsoft F#\v4.0\" ( System.AppDomain.CurrentDomain.BaseDirectory) which again shows I've not quite understood how to tell FSI/FSX to use a particular path. If I copy the config file (MyAppConfig.xml) to that location it works fine.
Many thx
S
I'm not sure of the implications, but one possiblity might be temporarily changing the app base:
let origAppBase = AppDomain.CurrentDomain.BaseDirectory
AppDomain.CurrentDomain.SetData("APPBASE", "path_to_MyAppConfig.xml")
myApp.Initialization.Load() |> ignore
AppDomain.CurrentDomain.SetData("APPBASE", origAppBase) //restore original app base

F# Module/Namespace Error

My first program with F#.
I have one file like so:
namespace LanguageMapper.Data
#if INTERACTIVE
#r "System.Data"
#r "System.Data.Linq"
#r "FSharp.Data.TypeProviders"
#endif
open System.Data
open System.Data.Linq
open Microsoft.FSharp.Data.TypeProviders
module Data =
// You can use Server Explorer to build your ConnectionString.
type SqlConnection = Microsoft.FSharp.Data.TypeProviders.SqlDataConnection<ConnectionString = #"connstring">
let db = SqlConnection.GetDataContext()
Then i have another file like so
namespace LanguageMapper.Program
open Data
module Program =
[<EntryPoint>]
let main argv =
let getLocale x =
match x with
| [|"live"|] -> "live"
| [|"dev"|] -> "dev"
| _ -> "local"
Over top of the open Data i get a red squiggly in VS telling me:
"Error 1 This declaration opens the namespace or module
'Microsoft.FSharp.Data' through a partially qualified path. Adjust
this code to use the full path of the namespace. This change will make
your code more robust as new constructs are added to the F# and CLI
libraries."
What am i doing wrong? I just want to reference one file from the other.
You need to open the module using its fully qualified name, that is including its namespace. So in LanguageMapper.Program you need to open LanguageMapper.Data.Data (only the last bit is the module name).
The Compiler is complaining on your open definition because it only specifies to open a namespace or module named Data - and it finds one in Microsoft.FSharp.Data, probably because there are some 'automatic' opens for the Microsoft.FSharp namespaces.

Resources