Nico
Nico

Reputation: 3489

How to get FileUpload working in WASM for Uno Platform

I'm trying to get HTML file upload control working on WASM. So far I've tried to do the following:

[HtmlElement("input")]
public class FilePickerView : FrameworkElement
{
    public FilePickerView()
    {
        // XAML behavior: a non-null background is required on an element to be "visible to pointers".
        // Uno reproduces this behavior, so we must set it here even if we're not using the background.
        // Not doing this will lead to a `pointer-events: none` CSS style on the control.
        Background = new SolidColorBrush(Colors.Transparent);

        this.SetHtmlAttribute("type", "file");
    }
}

And then in the view:

<wasm:FilePickerView Height="35"  Width="300" x:Name="filePicker" HorizontalAlignment="Left" />

I get the control displayed, I can click on it and it displays the name of the file I've selected.

I am pretty lost after this.

I'd like to be able to do two things:

  1. Access file path in code behind.
  2. Send file contents to code behind for processing.

Would appreciate any pointers on this.

I've been through the following pages in the documentation:

Upvotes: 3

Views: 510

Answers (1)

Jan Kleprl&#237;k
Jan Kleprl&#237;k

Reputation: 330

After connecting pieces from the internet, I came up with this method. However, it only works with files max 500 kb big.

To enable large file upload I had to upgrade wasm target to .net 5 and use developer versions (2.0.0-dev.167) of Uno.Wasm.Bootstrap and Uno.WasmBootstrap.DevServer (how to upgrade target is described here).

In this code I enabled upload of only .wav audio files

   private async void uploadBtn_Click(object sender, RoutedEventArgs e)
       {
           FileSelectedEvent -=OnFileUploadedEvent;
           FileSelectedEvent += OnFileUploadedEvent;
           
           WebAssemblyRuntime.InvokeJS(@"
               var input = document.createElement('input');
               input.type = 'file';
               input.accept = '.wav';
               input.onchange = e => {
                   var file = e.target.files[0];
                       var reader = new FileReader();
                       reader.readAsDataURL(file);
                       reader.onload = readerEvent => {
                           //this is the binary uploaded content
                           var content = readerEvent.target.result; 
                           //invoke C# method to get audio binary data
                           var selectFile = Module.mono_bind_static_method(" + "\"[MyApp.Wasm] MyApp.Shared.MyPage:SelectFile\""+@");
                           selectFile(content);
                       
                   };
               };
               input.click(); "
           );
       }
       public static void SelectFile(string fileAsDataUrl) => FileSelectedEvent?.Invoke(null, new FileSelectedEventHandlerArgs(fileAsDataUrl));

       private void OnFileUploadedEvent(object sender, FileSelectedEventHandlerArgs e)
       {
           FileSelectedEvent -= OnFileUploadedEvent;
           var base64Data = Regex.Match(e.FileAsDataUrl, @"data:audio/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
           var binData = Convert.FromBase64String(base64Data); //this is the data I want
           Console.Out.WriteLine("I got binary data of uploaded file");
       }

       private static event FileSelectedEventHandler FileSelectedEvent;

       private delegate void FileSelectedEventHandler(object sender, FileSelectedEventHandlerArgs args);

       private class FileSelectedEventHandlerArgs
       {
           public string FileAsDataUrl { get; }
           public FileSelectedEventHandlerArgs(string fileAsDataUrl) => FileAsDataUrl = fileAsDataUrl;

       }

Also I was not able to run it with SQLite at the same time. Sadly, I still haven't figured out why.

Sources:

EDIT: Appareantly SQLite for .NET 5/6 is still work in progress and there are some packages that need changes.

Upvotes: 2

Related Questions