How to get FileUpload working in WASM for Uno Platform

Viewed 333

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:

1 Answers

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.

Related