ca9163d9
ca9163d9

Reputation: 29227

F# cannot post to web api?

I have the following code to post to a web api.

[<CLIMutable>]
type MyModel = { FileName:string; Period:DateTime; DownloadedTime:DateTimeOffset; Url:string; }

let PostDownload (filepath, date, url) = 
  async {
    try
        use client = new HttpClient()
        let content = { FileName = filepath; Period = date; DownloadedTime = DateTimeOffset.Now; Url = url }
        let! response = Async.AwaitTask(client.PostAsJsonAsync("http://localhost:5000/api/DownloadedFiles", content))
    with 
    | ex -> logger.Error(ex, "Exception: " + ex.Message)
  } |> Async.Start

The service has the following code and the debugger shows all the fields of downloadedFile are the default values (nulls or the minimum values for value types).

    [HttpPost]
    public void Post([FromBody]DownloadedFile downloadedFile)
    {
        try
        {
            _context.DownloadedFile.Add(downloadedFile);
            _context.SaveChanges();
        }
        catch (Exception ex) { ...... }
    }

The fiddler shows the F# code (or PostAsJsonAsync cannot handle F# mutable record type?) added @ at the end of field name?

{"FileName@":"test","Period@":"2100-01-01T00:00:00","DownloadedTime@":"2016-08-18T15:50:37.5004391-04:00","Url@":"test"}

Upvotes: 4

Views: 657

Answers (2)

jannikb
jannikb

Reputation: 524

I just ran into this issue and lost some hours solving it. It seems the serializer that is used in HttpClient.PostAsJsonAsync does not handle fsharp types well. The @ symbol issue is also not easily googleable. Using the following code however seems to work:

task {
  let content = JObject.FromObject({ Id = "foo" }).ToString()
  let! response = client.PostAsync("url", new StringContent(content, Encoding.UTF8, "application/json"))
  return "Hello world"
}

Upvotes: 0

Mark Seemann
Mark Seemann

Reputation: 233447

I don't know from where you get HttpClient.PostAsJsonAsync, because it's not on the version of HttpClient I'm currently looking at. Nevertheless, I typically use this extension, which works for me:

type HttpClient with
    member this.PostAsJsonAsync (requestUri : string, value : obj) =
        let json = string value
        let content = new StringContent (json)
        content.Headers.ContentType <-
            Headers.MediaTypeHeaderValue "application/json"
        this.PostAsync (requestUri, content)

Upvotes: 2

Related Questions