question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

I’d like to upload a file and process it on server-side.

I may do this to encode a file into string like base64, but can I upload a file not to decode on server-side?

The following codes illustrate what I’d like to do.

This works, but maybe not for large files.

type Message =
   | FileChanged
   | ContentsRead of string
   | (* ... *)

type UploadService =
   {
      Upload : string-> Async<unit>
   }
   interface IRemoteService with (* ... *)

let update remote jsRuntime message model =
   match message with
   | FileChanged ->
      let readFileJs () = jsRuntime .InvokeAsync<string>("readFile") |> Async.AwaitTask
      model, Cmd.ofAsync readFileJs () ContentsRead (* ofError *)
   | ContentsRead(contents) ->
      model, Cmd.ofRemote remote.Upload contents (* ... *)
   | (* ... *)

let view model dispatch = input [
   attr.id "input-file"
   attr.``type`` "file"
   on.change (fun e -> FileChanged |> dispatch)
]
readFile: () => {
   const input = document.getElementById('input-file');
   const reader = new FileReader();
   return new Promise((resolve, reject) => {
      reader.addEventListener('load', () => {
         resolve(reader.result);
      });
      reader.readAsBinaryString(input.files[0]);
   });
}

This is what I’d like to do and doesn’t work.

type Message =
   | SetFile of string 
   | (* ... *)

type UploadService =
   {
      Upload : Stream -> Async<unit>
   }
   interface IRemoteService with (* ... *)

let update remote message model =
   match message with
   | SetFile(file) ->
      model, Cmd.ofRemote remote.Upload (File.OpenRead(file)) (* ... *)

Do I need to prepare a non-Bolero endpoint and call it from JS directly?

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
Bananas-Are-Yellowcommented, Jun 5, 2020

Thank you, that’s a good solution. Two implementations of IFileTransfer, one with an HttpClient and one without.

Client

In Program.Main we have:

services.AddHttpClient<IFileTransfer, ClientFileTransfer> (fun http ->
    http.BaseAddress <- Uri env.BaseAddress)

The implementation of IFileTransfer posts to the endpoint in the server:

type ClientFileTransfer (http: HttpClient) =
    interface IFileTransfer with
        member _.UploadFiles files =
            async {
                // use MultipartFormDataContent and http.PostAsync
            }

Server

In Startup.ConfigureServices we have:

AddSingleton<IFileTransfer, ServerFileTransfer>()

No uploading required. Just directly call the code that the upload endpoint uses.

type ServerFileTransfer () =
    interface IFileTransfer with
        member _.UploadFiles files = // share code with Http upload endpoint
0reactions
Tarmilcommented, Jun 5, 2020

Is this to be expected? Do services need to be added in two places?

Yes, that’s how it goes: in client mode, the services are setup in Client’s main function, and in server mode, in Startup’s ConfigureServices.

Assuming so, I want to add it to Startup.ConfigureServices in the server too. In this case, uploading a file will use an HttpClient to upload to “localhost:5000”. I can hardwire this, and it works for development, but how should I obtain the base address when using the HttpClient to loop back to the Asp.Net Core server endpoint in this way?

It seems like if you do things this way, then in server mode, you will have two requests: the first one, done by InputFile over SignalR, to send the data to the server-side Blazor; and then from the server to itself, to send it to the Post endpoint. It should be possible to avoid this second one.

If I understand correctly the purpose of your IFileTransfer interface, you could provide two different implementations of it:

  • the client-side implementation would be what you have currently, which posts the data to your ASP.NET Core endpoint;
  • the server-side implementation would directly perform the actual processing you need to do on the file. It would be injected in ConfigureServices, and therefore used by your Bolero code in server-side mode, but also it can be used by your ASP.NET Core endpoint.
Read more comments on GitHub >

github_iconTop Results From Across the Web

Upload files & folders to Google Drive - Computer
On your computer, go to drive.google.com. Open or create a folder. To upload files and folders, drag them into the Google Drive folder....
Read more >
Upload files & folders to Google Drive - Android
On your Android phone or tablet, open the Google Drive app. Tap Add Add question . Tap Upload. Find and tap the files...
Read more >
Uploading Files to Google Drive
From Google Drive, locate and select the New button, then select File upload. Uploading a file. Locate and select the file(s) you want...
Read more >
Upload Files Of Any Size – Free Up To 5 GB
Upload files free and share anonymously using a direct download link. No download limits. No Ads. No need to register. Share more with...
Read more >
Getting Started | Uploading Files
To upload files with Servlet containers, you need to register a MultipartConfigElement class (which would be <multipart-config> in web.xml). Thanks to Spring ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found