Table of Contents

Use with F# and Visual Basic

Asynchronous methods in the Paramore.Fences.Core API return either ValueTask or ValueTask<T> instead of Task or Task<T>. This is because the v8 API was designed to be optimized for high performance and uses ValueTask to avoid unnecessary allocations.

One downside to this choice is that in Visual Basic and F#, it is not possible to directly await a method that returns ValueTask or ValueTask<T>, instead requiring the use of Task and Task<T>.

A proposal to support awaiting ValueTask can be found in F# language design repository: [RFC FS-1021 Discussion] Support Interop with ValueTask in Async Type.

To work around this limitation, you can use the AsTask() method to convert a ValueTask to a Task in F# and Visual Basic. This does however introduce an allocation and make the code a bit more difficult to work with compared to C#.

Examples of such conversions are shown below.

F#

open FSharp.Control
open System
open System.Threading
open System.Threading.Tasks
open IcedTasks
open Paramore.Fences

let getBestFilmAsync token =
    task {
        do! Task.Delay(1000, token)
        return "https://www.imdb.com/title/tt0080684/"
    }

let demo () =
    task {
        // The ResiliencePipelineBuilder creates a ResiliencePipeline
        // that can be executed synchronously or asynchronously
        // and for both void and result-returning user-callbacks.
        let pipeline =
            ResiliencePipelineBuilder()
                .AddTimeout(TimeSpan.FromSeconds(5))
                .Build()

        let token = CancellationToken.None

        // Synchronously
        pipeline.Execute(fun () -> printfn "Hello, world!")

        // Asynchronously
        // Note that Fences expects a ValueTask to be returned, so the function uses the valueTask builder
        // from IcedTasks to make it easier to use ValueTask. See https://github.com/TheAngryByrd/IcedTasks.
        do! pipeline.ExecuteAsync(
            fun token ->
                valueTask {
                    printfn "Hello, world! Waiting for 2 seconds..."
                    do! Task.Delay(1000, token)
                    printfn "Wait complete."
                }
            , token
        )

        // Synchronously with result
        let someResult = pipeline.Execute(fun token -> "some-result")

        // Asynchronously with result
        // Note that Fences expects a ValueTask<T> to be returned, so the function uses the valueTask builder
        // from IcedTasks to make it easier to use ValueTask<T>. See https://github.com/TheAngryByrd/IcedTasks.
        let! bestFilm = pipeline.ExecuteAsync(
            fun token ->
                valueTask {
                    let! url = getBestFilmAsync(token)
                    return url
                }
            , token
        )

        printfn $"Link to the best film: {bestFilm}"
    }

Source

Visual Basic

Imports System.Threading
Imports Paramore.Fences

Module Program
    Sub Main()
        Demo().Wait()
    End Sub

    Async Function Demo() As Task
        ' The ResiliencePipelineBuilder creates a ResiliencePipeline
        ' that can be executed synchronously or asynchronously
        ' and for both void and result-returning user-callbacks.
        Dim pipeline = New ResiliencePipelineBuilder().AddTimeout(TimeSpan.FromSeconds(5)).Build()

        ' Synchronously
        pipeline.Execute(Sub()
                             Console.WriteLine("Hello, world!")
                         End Sub)

        ' Asynchronously
        ' Note that the function is wrapped in a ValueTask for Fences to use as VB.NET cannot
        ' await ValueTask directly, and AsTask() is used to convert the ValueTask returned by
        ' ExecuteAsync() to a Task so it can be awaited.
        Await pipeline.ExecuteAsync(Function(token)
                                        Return New ValueTask(GreetAndWaitAsync(token))
                                    End Function,
                                    CancellationToken.None).AsTask()

        ' Synchronously with result
        Dim someResult = pipeline.Execute(Function(token)
                                              Return "some-result"
                                          End Function)

        ' Asynchronously with result
        ' Note that the function is wrapped in a ValueTask(Of String) for Fences to use as VB.NET cannot
        ' await ValueTask directly, and AsTask() is used to convert the ValueTask(Of String) returned by
        ' ExecuteAsync() to a Task(Of String) so it can be awaited.
        Dim bestFilm = Await pipeline.ExecuteAsync(Function(token)
                                                       Return New ValueTask(Of String)(GetBestFilmAsync(token))
                                                   End Function,
                                    CancellationToken.None).AsTask()

        Console.WriteLine("Link to the best film: {0}", bestFilm)

    End Function

    Async Function GreetAndWaitAsync(token As CancellationToken) As Task
        Console.WriteLine("Hello, world! Waiting for 1 second...")
        Await Task.Delay(1000, token)
    End Function

    Async Function GetBestFilmAsync(token As CancellationToken) As Task(Of String)
        Await Task.Delay(1000, token)
        Return "https://www.imdb.com/title/tt0080684/"
    End Function
End Module

Source