Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working with F# types in C#

Tags:

c#

types

f#

I have a C# web api which I use to access an F# library. I have created a DU of the types I want to return and use pattern matching to choose which is return back to the c# controller.

In the C# controller how do I access the data of the type which is return from the function call to the F# library?

C# Controller

public HttpResponseMessage Post()
{
    var _result = Authentication.GetAuthBehaviour();
    //Access item1 of my tuple
    var _HTTPStatusCode = (HttpStatusCode)_result.item1;
    //Access item2 of my tuple
    var _body = (HttpStatusCode)_result.item2;
    return base.Request.CreateResponse(_HTTPStatusCode, _body);
}

F# Types

module Types =
    [<JsonObject(MemberSerialization=MemberSerialization.OptOut)>]
    [<CLIMutable>]
    type ValidResponse = {
         odata: string;
         token: string; 
    }

    [<JsonObject(MemberSerialization=MemberSerialization.OptOut)>]
    [<CLIMutable>]
    type ErrorResponse = {
         code: string;
         message: string;
         url: string; 
    }

    type AuthenticationResponse = 
    | Valid of int * ValidResponse
    | Error of int * ErrorResponse

F# function

module Authentication = 
    open Newtonsoft.Json

    let GetAuthBehaviour () =
        let behaviour = GetBehaviour.Value.authentication
        match behaviour.statusCode with
        | 200 ->
            let deserializedAuthenticationResponse = JsonConvert.DeserializeObject<Types.ValidResponse>(behaviour.body)
            Types.Valid (behaviour.statusCode, deserializedAuthenticationResponse)
        | _ ->
            let deserializedAuthenticationResponse = JsonConvert.DeserializeObject<Types.ErrorResponse>(behaviour.body)
            Types.Error (behaviour.statusCode, deserializedAuthenticationResponse)
like image 204
Alan Mulligan Avatar asked Jan 03 '16 21:01

Alan Mulligan


1 Answers

F# Discriminated Unions are compiled as abstract classes, with each case being a derived nested class. From C#, you can access the cases by attempting to downcast the result from GetAuthBehaviour:

public HttpResponseMessage Post()
{
    var result = Authentication.GetAuthBehaviour();

    var valid = result as Types.AuthenticationResponse.Valid;
    if (valid != null)
    {
        int statusCode = valid.Item1;
        Types.ValidResponse body = valid.Item2;
        return this.CreateResponse(statusCode, body);
    }

    var error = result as Types.AuthenticationResponse.Error;
    if (error != null)
    {
        int statusCode = error.Item1;
        Types.ErrorResponse body = error.Item2;
        return this.CreateResponse(statusCode, body);
    }

    throw new InvalidOperationException("...");
}

Notice that the C# compiler doesn't know that you've handled all the cases, so you'll need to supply a branch that handles the case where result is neither Valid nor Error. Here, I've simply thrown an exception as an example, but in a Web API, it'd probably be more appropriate to return a 500 status code.

All that said, though, why even have the trouble of writing and maintaining the Controllers in C#? You can write an ASP.NET Web API purely in F#.

like image 147
Mark Seemann Avatar answered Oct 26 '22 11:10

Mark Seemann