Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write and read files from .NET MAUI Blazor?

I'm trying to write an audio file into a .NET MAUI Blazor on Windows, so I can play it via HTML Audio Element via https://0.0.0.0/... or such link.

How can I get the application local storage path that I can write to, which points to that url?

like image 509
Elie Tebchrani Avatar asked Oct 29 '25 17:10

Elie Tebchrani


2 Answers

Here is the answer: .NET MAUI Documentation about Storage

You can use AppDataDirectory static property of the FileSystem class:

string path = FileSystem.AppDataDirectory;

Gets the location where app data can be stored.

like image 142
Ignotus Avatar answered Oct 31 '25 10:10

Ignotus


In theory, the suggestion is to use the AppDataDirectory and/or the CacheDirectory of the MAUI app, as mentioned in the official docs.

In practice, there is an issue: those folders can't be directly accessed by HTML elements in a Razor page.

Edit: how to access MAUI's AppData/Cache files from HTML elements

This is actually achievable by implementing a BlazorWebView class with access to the desired directory. Then, we must replace the default WebView with this one in MainPage.xaml. This way, HTML elements will be able to reference (e.g., via src="myfile.ext") any file in the desired MAUI directory.

See this SO answer for a detailed explanation.


Original answer

I'm going to make an example referring to images, but it's the same thing in case of audio files.

The only way I found to access files stored in those folders from HTML elements is to have an intermediate code read them and serve them as Base64, e.g. see this answer on loading an image stored in the CacheDirectory, which proposes to override the OnInitialized() method to perform the reading and conversion ToBase64String when the image gets loaded the first time.

The issues with this solutions are:

  • it's slow
  • you need to handle when the reading/ToBase64String should be called. This can mess up with things like Virtualization: overriding the OnInitialized() may not be enough.

For example, say that you have a long list of big images you want to show. You design a component where you want to parametrize which image (or audio file, for your case) should be loaded. You will want to perform the loading of each image only if it's in view: you will want to use Virtualization, or a similar technique.

However, if you use Virtualization, each component may get reused (e.g. when scrolling up and down). OnInitialized() may not get called! Overriding only that is not enough, we need to also override OnParametersSet() and make sure we are loading the right media file.
With reference to the example from the same answer (it would be the same thing for an audio file), we need to modify the code such as:

@if (imageSource is not null)
{
    <div>
        <img src="@imageSource" width="200" height="200" />
    </div>
}

@code {
    [Parameter]
    public string ImageFileName { get; set; }
    private string imageFileName;

    // This will store the Base64 read image.
    private string imageSource;

    protected override void OnInitialized()
    {
        // Store the parameter value in a private variable.
        imageFileName = ImageFileName;
        
        // Perform the first load.
        var newFile = Path.Combine(FileSystem.CacheDirectory, imageFileName);
        var imageBytes  = File.ReadAllBytes(newFile);
        imageSource = Convert.ToBase64String(imageBytes);
        imageSource = string.Format("data:image/png;base64,{0}", imageSource);
    }

    protected override void OnParametersSet()
    {
        if (ImageFileName == imageFileName) 
        {
            // we don't need to do anything, the component is
            // reusing the same image with which it was first initialized.
            return; 
        }

        // If we are here, the Virtualization has reused an existing
        // instance of this component but set a different parameter value.
        // Call the initialization again. This will load the right image.
        OnInitialized();
    }
}

I'm still actively looking for a better solution. Please leave a comment or another answer if you have one! I'd really love to just reference the right filename in the image source! This would basically remove the need for all this code! (please see the above-mentioned workaround)

like image 41
alelom Avatar answered Oct 31 '25 10:10

alelom