Why is File.WriteAllText Working in a Blazor Server app, and then why not in a WASM WPA app?

Steve Rehling 105 Reputation points
2024-06-19T20:24:02.1433333+00:00

I have a Blazor Server app that I am converting to WASM WPA. The app uses System.IO.File.WriteAllText to create local files. That's working in the Server app running in Chrome (i.e. files are created in directories I select). But it's not working in the WASM WPA app and no exception is being thrown.

My impression has been that accessing the local file system from a browser is not allowed due to security concerns. But I am seeing things that suggest it is now allowed, at least in some browsers.

So what is the current situation? Is it allowed, as my Server app demonstrates it is? If so, do all/most browsers support it? And why may it not be working in my WASM WPA version?

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,595 questions
0 comments No comments
{count} votes

Accepted answer
  1. Bruce (SqlWork.com) 66,866 Reputation points
    2024-06-19T21:06:36.81+00:00

    with Blazor server app, file I/O is handled by the hosting operating system, and has full access to the servers filesystem.

    with Blazor WASM, file I/O is handled by jsinterop to browser javascript.

    • the browser supports reading a file selected with the <input type="file"> control or window.showOpenFilePicker()
    • the browser supports writing a file via a data url on an anchor or the window.showSaveFilePicker() which give a handle.

    the file api is async (returns promise which is not supported by jsinterop serialization), so can not be called directly from Blazor. you should write a javascript function that calls back to a Blazor static method when complete:

    // blazor must call with InvokeVoidAsync as a promise is returned.
    const readFile = async (assemblyName, methodName) =>  {
      try {
        // Always returns an array.
        const [handle] = await window.showOpenFilePicker();
        const file = await handle.getFile();
        const text = await file.text();
        await DotNet.invokeMethodAsync(assemblyName, methodName, text);
      } catch (err) {
        console.error(err.name, err.message);
      }
    }
    
    // blazor must call with InvokeVoidAsync as a promise is returned.
    const saveFile = async (assemblyName, methodName, text) => {
      try {
        const handle = await window.showSaveFilePicker({
          types: [{
            accept: {
              // Omitted
            },
          }],
        });
        const writable = await handle.createWritable();
        await writable.write(text);
        await writable.close();
        await DotNet.invokeMethodAsync(assemblyName, methodName);
      } catch (err) {
        console.error(err.name, err.message);
      }
    };
    

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.