Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# async lambda interop with C# async model

I have such a piece of code (C#, Pulumi), which I want to translate to F#:

var registryInfo = repo.RegistryId.Apply(async (id) =>
        {
            var creds = await GetCredentials.InvokeAsync(new GetCredentialsArgs {RegistryId = id});
            var decodedData = Convert.FromBase64String(creds.AuthorizationToken);
            var decoded = ASCIIEncoding.ASCII.GetString(decodedData);

            var parts = decoded.Split(':');

            return new ImageRegistry
            {
                Server = creds.ProxyEndpoint,
                Username = parts[0],
                Password = parts[1],
            };
        });

What I have managed to do so far is:

let registryInfo = repo.RegistryId.Apply (fun id -> async {
let! creds = GetCredentialsArgs ( RegistryId = id) |> GetCredentials.InvokeAsync |> Async.AwaitTask
let decodedData = Convert.FromBase64String creds.AuthorizationToken
let decoded = ASCIIEncoding.ASCII.GetString decodedData
let parts = decoded.Split ':'
return ImageRegistry( Server = input creds.ProxyEndpoint, Username= input parts.[0], Password = input parts.[1])
} 
) 

The problem is that the code above in F# returns Output<Async<ImageRegistry>>, while C# code returns expected Output<ImageRegistry>. I am doing a transition from C# to F# (to extend my skills), but I cannot handle this case myself. How this should be properly done?

like image 876
user1658223 Avatar asked Mar 24 '26 20:03

user1658223


2 Answers

The library Pulumi.FSharp provides a useful helper Outputs.applyAsync for this:

open Pulumi.FSharp

let registryInfo =
    repo.RegistryId |>
    Outputs.applyAsync (fun id -> async {
        let! creds = GetCredentialsArgs ( RegistryId = id) |> GetCredentials.InvokeAsync |> Async.AwaitTask
        let decodedData = Convert.FromBase64String creds.AuthorizationToken
        let decoded = ASCIIEncoding.ASCII.GetString decodedData
        let parts = decoded.Split ':'
        return ImageRegistry( Server = input creds.ProxyEndpoint, Username= input parts.[0], Password = input parts.[1])
    })
like image 160
Mikhail Shilkov Avatar answered Mar 26 '26 09:03

Mikhail Shilkov


Without knowing too much about the Pulimu API's I'd guess that Apply is expecting a Task<T>.

You can convert from F# async to Task using Async.StartAsTask like so:

let registryInfo = repo.RegistryId.Apply (fun id -> async {
//snip
return ImageRegistry( Server = input creds.ProxyEndpoint, Username= input parts.[0], Password = input parts.[1])
} |> Async.StartAsTask
) 

Although if you are working with Task's you might be better using the task computation expression over the native F# async using a library such as Ply (as of writing the native task support is still in development).

like image 38
DaveShaw Avatar answered Mar 26 '26 08:03

DaveShaw



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!