You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Avalonia WebAssembly下文件读写及.csproj关联文件访问问题

在Avalonia WASM中处理C#项目文件的关联文件访问

浏览器环境的安全限制决定了WASM无法像桌面端那样直接通过文件路径读写本地文件,必须基于Avalonia的StorageProvider提供的沙箱式文件访问API来实现。针对你的场景,核心思路是获取项目目录的访问权限,而非仅单个csproj文件,以此遍历和读取关联文件,最终通过用户交互完成转换结果的导出。

核心步骤与实现

1. 调整文件选择逻辑:获取项目根目录

单个csproj文件无法提供其所在目录的访问权限,因此必须引导用户选择整个项目根目录。通过OpenFolderPickerAsync获取IStorageFolder实例,后续所有文件操作都基于这个目录:

var folderOptions = new FolderPickerOpenOptions
{
    Title = "选择C#项目根目录"
};
var projectFolder = await StorageProvider.OpenFolderPickerAsync(folderOptions);
if (projectFolder == null) return;

// 在目录中查找csproj文件
var csprojFiles = await projectFolder.GetFilesAsync(new[] { ".csproj" });
var targetCsproj = csprojFiles.FirstOrDefault();
if (targetCsproj == null)
{
    // 提示用户选择包含csproj文件的目录
    return;
}

2. 解析csproj文件,提取关联文件路径

使用MSBuild API解析csproj文件(和桌面端逻辑一致,确保你的项目引用了Microsoft.Build包),提取所有显式/隐式关联的文件路径(如Compile、Content项):

using var csprojStream = await targetCsproj.OpenReadAsync();
var project = new Project();
project.Load(csprojStream);

// 获取所有编译/资源文件的相对路径
var referencedFilePaths = project.Items
    .Where(item => item.ItemType is "Compile" or "Content")
    .Select(item => item.EvaluatedInclude)
    .ToList();

3. 读取关联文件内容

基于项目目录的IStorageFolder实例,通过相对路径调用GetFileAsync获取对应文件的IStorageFile,再通过OpenReadAsync读取流:

foreach (var relativePath in referencedFilePaths)
{
    try
    {
        var targetFile = await projectFolder.GetFileAsync(relativePath);
        using var fileStream = await targetFile.OpenReadAsync();
        using var reader = new StreamReader(fileStream);
        var content = await reader.ReadToEndAsync();
        
        // 执行你的源代码转换逻辑
    }
    catch (FileNotFoundException)
    {
        // 处理缺失文件的异常(如日志提示用户)
    }
}

4. 导出转换后的文件

浏览器不允许直接写入本地文件系统,因此需要通过用户交互完成导出:

  • 单个文件:使用SaveFilePickerAsync让用户选择保存位置,写入转换后的内容:
    var saveOptions = new FilePickerSaveOptions
    {
        Title = "保存转换后的文件",
        SuggestedFileName = "ConvertedFile.cs"
    };
    var saveFile = await StorageProvider.SaveFilePickerAsync(saveOptions);
    if (saveFile != null)
    {
        using var writeStream = await saveFile.OpenWriteAsync();
        using var writer = new StreamWriter(writeStream);
        await writer.WriteAsync(convertedContent);
    }
    
  • 多个文件:将所有转换后的文件打包为ZIP,通过JS互操作触发浏览器下载:
    // 假设convertedFiles是键为相对路径、值为转换后内容的字典
    var convertedFiles = new Dictionary<string, string>();
    
    using var zipStream = new MemoryStream();
    using var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true);
    foreach (var (path, content) in convertedFiles)
    {
        var entry = archive.CreateEntry(path);
        using var entryWriter = new StreamWriter(entry.Open());
        await entryWriter.WriteAsync(content);
    }
    zipStream.Position = 0;
    
    // 调用JS下载函数
    await JSRuntime.Current.InvokeVoidAsync("downloadZip", "converted-project.zip", zipStream.ToArray());
    
    对应的JS函数(添加到项目的index.html中):
    function downloadZip(filename, data) {
        const blob = new Blob([data], { type: "application/zip" });
        const url = URL.createObjectURL(blob);
        const link = document.createElement("a");
        link.href = url;
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
    }
    

关键注意事项

  • MSBuild兼容性:确保使用支持.NET WASM的Microsoft.Build版本(17.4及以上),可通过NuGet安装。
  • 相对路径处理:csproj中定义的相对路径是相对于csproj文件所在目录的,若csproj不在项目根目录,需先计算目录层级差,调整路径后再调用GetFileAsync。
  • 浏览器安全限制:所有文件操作必须由用户主动触发(如点击按钮打开选择器),无法后台自动访问文件系统。

内容的提问来源于stack exchange,提问作者Dave Doknjas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 13:43:17