Blazor navigator access

194 Views Asked by At

Anybody know how to get the following code to work? It's from: https://web.dev/file-system-access/#accessing-the-origin-private-file-system

const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('Untitled.txt', { create: true });

Ultimately I'm trying to gain access to the origin directory to store files created by my Blazor site. I prefer the origin directory because it doesn't require user interaction and is somewhat protected from the user.

Absolutely not to be confused with the key/pair 'localstorage' feature. I'm talking about genuine file access.

2

There are 2 best solutions below

1
Mister Magoo On

Here is a basic sample of creating/writing/reading a simple text file.

<button @onclick=CreateFile>Create File</button>
<button @onclick=ReadFile>Read File</button>

@code
{
    [Inject] public IJSRuntime JS { get; set; } 

    async Task CreateFile()
    {
        var textToSave = await JS.InvokeAsync<string>("prompt","What is your name?");
        var jsDirHandle = await JS.InvokeAsync<IJSObjectReference>("navigator.storage.getDirectory");
        var jsFileHandle = await jsDirHandle.InvokeAsync<IJSObjectReference>("getFileHandle", "testfile", new { create = true });
        var jsFileStream = await jsFileHandle.InvokeAsync<IJSObjectReference>("createWritable");
        await jsFileStream.InvokeVoidAsync("write",$"You said your name is {textToSave} on {DateTime.Now}");
        await jsFileStream.InvokeVoidAsync("close");
        await JS.InvokeVoidAsync("alert", "File created");
    }
    async Task ReadFile()
    {
        var jsDirHandle = await JS.InvokeAsync<IJSObjectReference>("navigator.storage.getDirectory");
        var jsFileHandle = await jsDirHandle.InvokeAsync<IJSObjectReference>("getFileHandle", "testfile", new { create = true });
        var jsFile = await jsFileHandle.InvokeAsync<IJSObjectReference>("getFile");
        var fileText = await jsFile.InvokeAsync<string>("text");
        await JS.InvokeVoidAsync("alert", fileText);
    }
}

And a live sample: https://blazorrepl.telerik.com/mmkAQgPL05sNJ72w42

0
Sean On

Thanks to Mister Magoo's answer, I was able to augment Kristoffer Strube's File System Access library. To his FileSystemAccessService.cs file, I added:

/// <summary>
/// Get handle to the exclusive origin directory for executing website
/// </summary>
/// <returns>handle to origin directory</returns>
public async Task<FileSystemDirectoryHandle> GetOriginDirectoryAsync()
{
    IJSInProcessObjectReference helper = await helperTask.Value;
    IJSObjectReference? jSFileHandle = await jSRuntime.InvokeAsync<IJSObjectReference>("navigator.storage.getDirectory");
    return new FileSystemDirectoryHandle(jSFileHandle, helper);
}

and then to demonstrate usage, I have the following:

//write/create
directoryHandle = await FileSystemAccessService.GetOriginDirectoryAsync();
var jsFileHandle = await directoryHandle.GetFileHandleAsync("testfile", new FileSystemGetFileOptions() { Create = true });
var jsFileStream = await jsFileHandle.CreateWritableAsync(new FileSystemCreateWritableOptions(false));
await jsFileStream.WriteAsync("hello");
await jsFileStream.CloseAsync();
// read
jsFileHandle = await directoryHandle.GetFileHandleAsync("testfile");
var jsFile = await jsFileHandle.GetFileAsync();
var fileText = await jsFile.TextAsync();