Giraffe: [Question] Multipart file upload without writing to disc?

Created on 30 Jan 2021  路  2Comments  路  Source: giraffe-fsharp/Giraffe

I am trying to stream a very large file via Giraffe. I came across the discussion starting here and tried to leverage FormFeature:

let formHandler =
  fun (next : HttpFunc) (ctx : HttpContext) ->
    task {
      if ctx.Request.HasFormContentType
      then

        use cts = new CancellationTokenSource ()

        let formOptions = FormOptions ()

        formOptions.BufferBody <- false
        formOptions.MultipartBodyLengthLimit <- TerabyteInBytes

        let formFeature = FormFeature (ctx.Request, formOptions)

        let! form = formFeature.ReadFormAsync (cts.Token)

        for x in form.Files do
          printfn "file: %A" (x.Name, x.ContentType, x.FileName)

        let recordsFile =
          form.Files
          |> Seq.tryPick (fun x -> if x.Name = "records" then Some x else None)

        match recordsFile with
        | Some recordsFile ->
          printfn "Found records file: %A" recordsFile

          use stream = recordsFile.OpenReadStream ()

          let encoding = Encoding.ASCII // TODO

          use reader = new StreamReader (stream, encoding)

          let mutable keepGoing = true
          let mutable linesRead = 0

          printfn "Streaming... "

          while keepGoing do
            let! maybeLine = reader.ReadLineAsync ()
            let maybeLine = Option.ofObj maybeLine

            match maybeLine with
            | Some line ->
              printfn "%s" line
              linesRead <- linesRead + 1
            | None ->
              keepGoing <- false

          let response =
            {|
              linesRead = linesRead
              message = sprintf "Received %i line(s) of data. Thanks! " linesRead
            |}

          return! json response next ctx
        | None ->
          return! RequestErrors.BAD_REQUEST "No records file found" next ctx

      else
        return! RequestErrors.BAD_REQUEST "Not a form request" next ctx
    }

But after some testing, it appears to first write the uploaded file to /tmp and then stream from there.

I want to take the stream directly from the request.

Is there some documentation / examples on how to do this?

documentation question

Most helpful comment

I figured this out and made a demo repo: https://github.com/njlr/giraffe-file-upload

Yes, perhaps the docs could be improved!

All 2 comments

Have you had a look at the official ASP.NET Core documentation for file uploads?

There is an entire section describing how to stream a large file upload. It uses MVC as an example but only to show how to disable MVC model binding for a large file upload and how to use the Anti forgery token attribute. If you discount these two things then the rest of the example is also applicable to all of ASP.NET Core including Giraffe. They also show some helper classes to help you with the implementation, such as the MultipartRequestHelper.

Use this as a starting point and let me know if there is something unclear and I'll try my best to help!

I figured this out and made a demo repo: https://github.com/njlr/giraffe-file-upload

Yes, perhaps the docs could be improved!

Was this page helpful?
0 / 5 - 0 ratings