Parameter count mismatch Exception when mocking HttpClient in F# - f#

I'm trying to mock the .NET HttpClient with Moq in F#. I currently have the following code:
open System.Net.Http
open Foq
[<Fact>]
let ``Some test`` () =
Mock<HttpClient>.With
(fun client ->
<# client.GetStringAsync("foo")
--> task { return "bar" } #>)
|> ignore
Upon running the test I get the following error.
System.Reflection.TargetParameterCountException : Parameter count mismatch.
How can I fix this?
I know there are many similar questions, but they are all for C#. They mention that either there are arguments missing somewhere or something with a callback should be added. But I can't figure out what arguments are missing, or how to add the callback to my example.

I looked into this a bit and it seems to be caused by an underlying problem with F# quotations, rather something that can be addressed within Foq. For example, the following code throws the same unhandled exception:
<# task { return "bar" } #>
|> FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation
|> printfn "%A"
I reported this as an issue in the F# core repository.

Related

Does the >>= operator not take a function?

I'm working on a side project and I'm using Hopac for the first time. I ran into an odd (to me) compilation issue that I haven't been able to grok. I suspect that I'm the problem here, and not Hopac.
The program is supposed to be a simple console app that consumes notifications from various services. Here's the problematic module:
module Provider
open System
open System.IO
open Hopac
open BitThicket.NotificationHelper.Core
open BitThicket.NotificationHelper.Providers
let defaultProviderTypes =
[| typeof<GitHub.GitHubNotificationProvider> |]
type Provider = {
getCh : Ch<Providers.INotification seq>
}
let giveLatest ch latest =
Ch.give
let start config logger (providerType:Type) = Job.delay <| fun () ->
let providerImpl = Activator.CreateInstance(providerType) :?> Providers.INotificationProvider
let p = { getCh = Ch() }
let rec server =
let latest = providerImpl.GetLatestNotificationsAsync(None) |> Job.fromAsync
latest >>= Ch.give p.getCh // error here
}
Job.start server
In this case, the compiler complains: Expecting a type supporting the operator '>>=' but given a function type. You may be missing an argument to a function.
Similarly, if I use a slightly different syntax:
// ...
let rec server =
let latest = providerImpl.GetLatestNotificationsAsync(None) |> Job.fromAsync
latest >>= fun l -> Ch.give p.getCh l // error here
// ...
In this case, the error is: This function takes too many arguments, or is used in a context where a function is not expected.
I asked haf about his in slack, and his suggestion was to check for alternative definitions of >>=. The tooling doesn't really do much to help me figure that one out, but the only namespace/module I have opened that defines >>= is Hopac (the BitThicket ones are just trivially simple namespaces with some type definitions in them).
What am I doing wrong here?
I'm looking at the source code, and I see that the bind operator is actually defined in Hopac.Infixes, not in Hopac.

What is the syntax for resolving Thenable<'t> in F# using fable?

I'm working on a vscode extension written in F# using Fable to compile to javascript. Many of the api's return a promise. What is the syntax for for resolving a promise that have return types such as Thenable<string[]> for F#?
Here is an example of many of the api's for vscode: vscode api
Take a look at how Ionide does it:
https://github.com/ionide/ionide-vscode-helpers/blob/fable/Helpers.fs
https://github.com/ionide/ionide-vscode-helpers/blob/fable/Fable.Import.VSCode.fs
Basically, it looks like Ionide almost ignored the existence of Thenable<T> and converted every API call to a Promise<T> in their Fable bindings. They do have a pair of toPromise and toThenable functions in Helpers.fs, but I don't see those being used anywhere in the entire https://github.com/ionide/ionide-vscode-fsharp repository.
I don't have any personal experience with Fable, so if this isn't enough to answer your question, hopefully someone else will chime in with more information.
After some playing with the syntax, I was able to figure it out with the clue that rmunn gave with converting the Thenable to Promise.
module PromiseUtils =
let success (a : 'T -> 'R) (pr : Promise<'T>) : Promise<'R> =
pr?``then`` (unbox a) |> unbox
let toPromise (a : Thenable<'T>) = a |> unbox<Promise<'T>>
let toThenable (a : Promise<'T>) = a |> unbox<Thenable<'T>>
Using the utility module above, I was able to convert the functions that return Thenable to Promises so they could be resloved.
let result = commands.getCommands ()
|> PromiseUtils.toPromise
|> PromiseUtils.success (fun item ->
let firstOne = item.Item 1
console.log(firstOne))

Mocked Interface with NSubstitute on F# does not allow Returns

I have the following code:
open NSubstitute
type MyClass()=
let myObject = Substitute.For<IMyInterface>()
do myObject.MyProperty.Returns(true)
do myObject.MyMethod().Returns(true)
On "Returns" (both) I get the error that is not defined. The equivalent C# code works without issue. Adding |> ignore at the end of the do lines does not help. Am I missing something there?
I know you wrote that adding |> ignore at the end doesn't help, but this compiles on my machine:
type IMyInterface =
abstract MyProperty : bool with get, set
abstract member MyMethod : unit -> bool
open NSubstitute
type MyClass() =
let myObject = Substitute.For<IMyInterface>()
do myObject.MyProperty.Returns(true) |> ignore
do myObject.MyMethod().Returns(true) |> ignore
I attempted to infer the definition of IMyInterface from the question; did I get it wrong?
So after I tried the code (Mark Seemann's, as to avoid my C# class) on VS2012, fsi, through direct compilation with fsc and on VS2013, the issue is clearly a VS2012 problem. The code works correctly with the other three.
Not sure yet if it is using a different version of F#. Will need further investigation. But at least, for now, on VS2012 I can use:
do SubstituteExtensions.Returns(myObject.MyProperty, true) |> ignore
It works as well when I need to pass parameters to methods.

Usage of AddXmlDocComputed in an F# type provider

I have a type provider which provides a static property but the documentation is subject to change at recurring intervals throughout. I have the following property setup.
let prop = ProvidedProperty("Test", typeof<string>,
IsStatic = true,
GetterCode = fun args -> <## "Test" ##>)
I then tried to add some documentation to it with AddXmlDocComputed as follows
let GetDocumentation () = "Test documentation"
do prop.AddXmlDocComputed(GetDocumentation)
However, I get no text displayed in the Intellisense comments. I then raised an exception in the GetDocumentation function which is reflected in the intellisense through the addition of the [<Note>] and the message saying that it originated from the call to GetDocumentation. I also tried using AddXmlDoc and AddXmlDocDelayed, both of which added the documentation as expected.
So this leads to my question of does anyone have any experience using AddXmlDocComputed and why does my current implementation add no documentation to the property?
Edit:
I've now tried debugging a VS2013 instance and can see that the documentation is being called and the expected string is being passed through the type provider for that property, however, there is still no documentation appearing in the Intellisense window.
I believe this to be a bug in ProvidedTypes.fs. The explanation is that the computed XML doc attribute is never actually returned when GetCustomAttributesData() in type CustomAttributesImpl(). Instead of returning the attribute as part of the array of attributes, it is added to an internal list of attributes (by accident I assume).
To fix the issue locally, replace the implementation with this code:
member __.GetCustomAttributesData() =
[| yield! customAttributesOnce.Force()
match xmlDocAlwaysRecomputed with None -> () | Some f -> yield mkXmlDocCustomAttributeData (f()) |]
:> IList<_>
I have issued a pull request on GitHub with the fix.
Update:
The fix has been merged into the master branch of FSharp.TypeProviders.StarterPack.

F# async web request, handling exceptions

I'm trying to use async workflows in F# to fetch several web requests.
However, some of my requests are occasionally returning errors (e.g. http 500), and I don't know how to handle this. It appears like my F# program gets stuck in an infinite loop when running in the debugger.
I'm probably missing some stuff, cause examples I seen didn't compile out of the box. First thing I found that helped was this bit of code:
type System.Net.WebRequest with
member req.GetResponseAsync() =
Async.BuildPrimitive(req.BeginGetResponse, req.EndGetResponse)
and then I have my bit of code to fetch the requests, which is pretty standard from examples I've seen:
let async_value = async {
let req = WebRequest.Create(url)
let! rsp = req.GetResponseAsync()
return (rsp :?> HttpWebResponse).StatusCode
}
and then I try to get the result:
let status = Async.RunSynchronously(async_value)
But when I run my program in debugger, it breaks at req.EndGetResponse because server returned internal server error 500. If I keep just continuing execution, it gets in a funky loop, breaking at req.EndGetResponse (sometimes several in a row), and at let status = Async.RunSynchronously(async_value).
How do I get around the exception problem so I can get my status code? Also, do I need the type thing I did above? Or am I missing some library/dll for F#/VS 2010 Beta 1, of which this is already a part of?
I actually run several requests in parallel, using Async.RunSynchronously(Async.Parallel(my_array_of_async_values)), though I don't think that is related to the exception issue I'm having.
The fact the examples I've come across only use Async.Run rather than Async.RunSynchronously is probably an indicator I'm missing something... =/
It's now called 'AsyncGetResponse' (no longer 'GetResponseAsync'). And 'Run' was renamed to 'RunSynchronously'. So I don't think you're missing anything substantial here, just name changes in the latest release.
What are your debugger settings with regard to "Tools\Options\Debugging\General\Enable Just My Code" and "Debug\Exceptions" (e.g. set to break when any first-chance CLR exception is thrown or not)? I am unclear if your question involves the program behavior, or the VS tooling behavior (sounds like the latter). This is further confounded by the fact that breakpoint/debugging 'locations' in F# Beta1 have some bugs, especially regarding async workflows, which means that the behavior you see in the debugger may look a little strange even if the program is executing properly...
Are you using VS2008 CTP or VS2010 Beta1?
In any case, it appears the exception due to a 500 response is expected, this is how WebRequest works. Here's a short demo program:
open System
open System.ServiceModel
open System.ServiceModel.Web
[<ServiceContract>]
type IMyContract =
[<OperationContract>]
[<WebGet(UriTemplate="/Returns500")>]
abstract Returns500 : unit -> unit
[<OperationContract>]
[<WebGet(UriTemplate="/Returns201")>]
abstract Returns201 : unit -> unit
type MyService() =
interface IMyContract with
member this.Returns500() =
WebOperationContext.Current.OutgoingResponse.StatusCode <-
System.Net.HttpStatusCode.InternalServerError
member this.Returns201() =
WebOperationContext.Current.OutgoingResponse.StatusCode <-
System.Net.HttpStatusCode.Created
let addr = "http://localhost/MyService"
let host = new WebServiceHost(typeof<MyService>, new Uri(addr))
host.AddServiceEndpoint(typeof<IMyContract>, new WebHttpBinding(), "") |> ignore
host.Open()
open System.Net
let url500 = "http://localhost/MyService/Returns500"
let url201 = "http://localhost/MyService/Returns201"
let async_value (url:string) =
async {
let req = WebRequest.Create(url)
let! rsp = req.AsyncGetResponse()
return (rsp :?> HttpWebResponse).StatusCode
}
let status = Async.RunSynchronously(async_value url201)
printfn "%A" status
try
let status = Async.RunSynchronously(async_value url500)
printfn "%A" status
with e ->
printfn "%s" (e.ToString())
You can use try...with inside the async to catch exceptions:
let async_value =
async {
let req = WebRequest.Create("http://unknown")
try
let! resp = req.AsyncGetResponse()
return "success"
with
| :? WebException as e -> return "failure"
}

Resources