Search code examples
uno-platform

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:


Solution

  • 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.