添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在 Blazor Hybrid 应用中,静态文件是应用资源,由 Razor 组件采用以下方法进行访问:

  • .NET MAUI : .NET MAUI file system helpers
  • WPF Windows 窗体 ResourceManager
  • 当静态资产仅在 Razor 组件中使用时,可以从 Web 根目录( wwwroot 文件夹)中以类似于 Blazor WebAssembly 和 Blazor Server 应用的方式使用它。 有关详细信息,请参阅 受限于 Razor 组件的静态资产 部分。

    .NET MAUI

    在 .NET MAUI 应用中,使用 MauiAsset 生成操作的 原始资产 .NET MAUI file system helpers 用于静态资产。

    用于跨所有受支持平台的设备上的存储,以实现选择文件、保存首选项和使用安全存储等功能的接口、类和支持类型位于 Microsoft.Maui.Storage 命名空间中。 命名空间在整个 MAUI Blazor Hybrid 应用中可用,因此无需针对命名空间在类文件中指定 using 语句或在 Razor 组件中指定 @using Razor 指令。

    将原始资产放入应用的 Resources/Raw 文件夹中。 本部分中的示例使用静态文本文件。

    Resources/Raw/Data.txt :

    This is text from a static text file resource.
    

    以下 Razor 组件:

  • 调用 OpenAppPackageFileAsync 获取资源的 Stream
  • 使用 StreamReader 读取 Stream
  • 调用 StreamReader.ReadToEndAsync 以读取文件。
  • Pages/StaticAssetExample.razor:

    @page "/static-asset-example"
    @using System.IO
    @using Microsoft.Extensions.Logging
    @inject ILogger<StaticAssetExample> Logger
    <h1>Static Asset Example</h1>
    <p>@dataResourceText</p>
    @code {
        public string dataResourceText = "Loading resource ...";
        protected override async Task OnInitializedAsync()
                using var stream = 
                    await FileSystem.OpenAppPackageFileAsync("Data.txt");
                using var reader = new StreamReader(stream);
                dataResourceText = await reader.ReadToEndAsync();
            catch (FileNotFoundException ex)
                dataResourceText = "Data file not found.";
                Logger.LogError(ex, "'Resource/Raw/Data.txt' not found.");
    

    有关更多信息,请参见以下资源:

  • 以 .NET MAUI 单个项目(.NET MAUI 文档)中的多个平台为目标
  • 使用 resizetizer (dotnet/maui #4367) 提高一致性
  • 将资产放入应用的文件夹(通常位于项目的根目录下)中,例如 Resources 文件夹。 本部分中的示例使用静态文本文件。

    Resources/Data.txt:

    This is text from a static text file resource.
    

    如果应用中不存在 Properties 文件夹,请在应用的根目录下创建一个 Properties 文件夹。

    如果 Properties 文件夹未包含资源文件 (Resources.resx),请使用“添加”>“新建项”上下文菜单命令在“解决方案资源管理器”中创建文件。

    双击 Resource.resx 文件。

    从下拉列表中,选择“字符串”>“文件”。

    选择“添加资源”>“添加现有文件”。 如果 Visual Studio 提示确认编辑文件,请选择“是”。 导航到 Resources 文件夹,选择 Data.txt 文件,然后选择“打开”。

    在以下示例组件中,ResourceManager.GetString 获取字符串资源文本以供显示。

    请勿对不受信任的数据采用 ResourceManager 方法。

    StaticAssetExample.razor:

    @page "/static-asset-example"
    @using System.Resources
    <h1>Static Asset Example</h1>
    <p>@dataResourceText</p>
    @code {
        public string dataResourceText = "Loading resource ...";
        protected override void OnInitialized()
            var resources = 
                new ResourceManager(typeof(WpfBlazor.Properties.Resources));
            dataResourceText = resources.GetString("Data") ?? "'Data' not found.";
    

    Windows 窗体

    将资产放入应用的文件夹(通常位于项目的根目录下)中,例如 Resources 文件夹。 本部分中的示例使用静态文本文件。

    Resources/Data.txt:

    This is text from a static text file resource.
    

    在“解决方案资源管理器”中检查与 Form1 关联的文件。 如果 Form1 没有资源文件 (.resx),请使用“添加”>“新建项”上下文菜单命令添加 Form1.resx 文件。

    双击 Form1.resx 文件。

    从下拉列表中,选择“字符串”>“文件”。

    选择“添加资源”>“添加现有文件”。 如果 Visual Studio 提示确认编辑文件,请选择“是”。 导航到 Resources 文件夹,选择 Data.txt 文件,然后选择“打开”。

    在下面的示例组件中:

  • 应用的程序集名称为 WinFormsBlazor。 将 ResourceManager 的基名称设置为 Form1 的程序集名称 (WinFormsBlazor.Form1)。
  • ResourceManager.GetString 获取字符串资源的文本以供显示。
  • 请勿对不受信任的数据采用 ResourceManager 方法。

    StaticAssetExample.razor:

    @page "/static-asset-example"
    @using System.Resources
    <h1>Static Asset Example</h1>
    <p>@dataResourceText</p>
    @code {
        public string dataResourceText = "Loading resource ...";
        protected override async Task OnInitializedAsync()
            var resources = 
                new ResourceManager("WinFormsBlazor.Form1", this.GetType().Assembly);
            dataResourceText = resources.GetString("Data") ?? "'Data' not found.";
    

    静态资产受限于 Razor 组件

    BlazorWebView 控件具有配置的主机文件 (HostPage),通常为 wwwroot/index.html。 HostPage 路径是项目的相对路径。 从 BlazorWebView 引用的所有静态 Web 资产(脚本、CSS 文件、图像和其他文件)都是其配置的 HostPage 的相对资产。

    Razor 类库 (RCL) 中的静态 Web 资产使用特殊路径:_content/{PACKAGE ID}/{PATH AND FILE NAME}{PACKAGE ID} 占位符是库的包 ID。 如果项目文件中没有指定 <PackageId>,则包 ID 默认为项目的程序集名称。 {PATH AND FILE NAME} 占位符是 wwwroot 下的路径和文件名。 这些路径在逻辑上是应用的 wwwroot 文件夹的子路径,尽管它们实际上来自其他包或项目。 特定于组件的 CSS 样式捆绑包也在 wwwroot 文件夹的根目录中生成。

    HostPage 的 Web 根目录决定了哪些静态资产子集可用:

  • wwwroot/index.html推荐):应用 wwwroot 文件夹中的所有资产可用(例如:可从 /image.png 获取 wwwroot/image.png),包括子文件夹(例如:可从 /subfolder/image.png 获取 wwwroot/subfolder/image.png)。 RCL 的 wwwroot 文件夹中的 RCL 静态资源可用(例如:可从路径 _content/{PACKAGE ID}/image.png 获得 wwwroot/image.png),包括子文件夹(例如:可从路径 _content/{PACKAGE ID}/subfolder/image.png 获得 wwwroot/subfolder/image.png)。
  • wwwroot/{PATH}/index.html:应用的 wwwroot/{PATH} 文件夹中的所有资产都可用(使用应用 Web 根相对路径)。 wwwroot/{PATH} 中的 RCL 静态资产不可用,因为它们将位于不存在的理论位置,例如 ../../_content/{PACKAGE ID}/{PATH},该位置不是受支持的相对路径。
  • wwwroot/_content/{PACKAGE ID}/index.html:RCL 的 wwwroot/{PATH} 文件夹中的所有资产都可用(使用 RCL Web 根相对路径)。 wwwroot/{PATH} 中应用的静态资产不可用,因为它们将位于不存在的理论位置,例如 ../../{PATH},该位置不是受支持的相对路径。
  • 对于大多数应用,我们建议将 HostPage 放在应用的 wwwroot 文件夹的根目录中,这样可以最大程度地灵活地从应用、RCL 以及通过应用和 RCL 的子文件夹提供静态资产。

    以下示例演示了如何使用来源于 wwwroot 文件夹的 HostPage,从应用的 Web 根目录(wwwroot 文件夹)引用静态资产。

    wwwroot/data.txt:

    This is text from a static text file resource.
    

    wwwroot/scripts.js:

    export function showPrompt(message) {
      return prompt(message, 'Type anything here');
    

    本部分的示例中还使用了下面的 Jeep® 图像。 可以右键单击以下图像以将其保存在本地,以便在本地测试应用中使用。

    wwwroot/jeep-yj.png:

    在 Razor 组件中:

  • 可以使用以下技术读取静态文本文件内容:
    • .NET MAUI: .NET MAUI file system helpersOpenAppPackageFileAsync
    • WPF 和 Windows 窗体:StreamReader.ReadToEndAsync
    • 可在 wwwroot 的逻辑子路径下获取 JavaScript 文件(使用 ./ 路径)。
    • 图像可以是图像标记 (<img>) 的源属性 (src)。
    • StaticAssetExample2.razor:

      @page "/static-asset-example-2"
      @using Microsoft.Extensions.Logging
      @implements IAsyncDisposable
      @inject IJSRuntime JS
      @inject ILogger<StaticAssetExample2> Logger
      <h1>Static Asset Example 2</h1>
      <h2>Read a file</h2>
      <p>@dataResourceText</p>
      <h2>Call JavaScript</h2>
          <button @onclick="TriggerPrompt">Trigger browser window prompt</button>
      <p>@result</p>
      <h2>Show an image</h2>
      <p><img alt="1991 Jeep YJ" src="/jeep-yj.png" /></p>
          <em>Jeep</em> and <em>Jeep YJ</em> are registered trademarks of 
          <a href="https://www.stellantis.com">FCA US LLC (Stellantis NV)</a>.
      @code {
          private string dataResourceText = "Loading resource ...";
          private IJSObjectReference? module;
          private string result;
          protected override async Task OnInitializedAsync()
                  dataResourceText = await ReadData();
              catch (FileNotFoundException ex)
                  dataResourceText = "Data file not found.";
                  Logger.LogError(ex, "'wwwroot/data.txt' not found.");
          protected override async Task OnAfterRenderAsync(bool firstRender)
              if (firstRender)
                  module = await JS.InvokeAsync<IJSObjectReference>("import",
                      "./scripts.js");
          private async Task TriggerPrompt()
              result = await Prompt("Provide some text");
          public async ValueTask<string> Prompt(string message) =>
              module is not null ?
                  await module.InvokeAsync<string>("showPrompt", message) : null;
          async ValueTask IAsyncDisposable.DisposeAsync()
              if (module is not null)
                      await module.DisposeAsync();
                  catch (JSDisconnectedException)
      

      在 .NET MAUI 应用中,将以下 ReadData 方法添加到前面组件的 @code 块中:

      private async Task<string> ReadData()
          using var stream = await FileSystem.OpenAppPackageFileAsync("wwwroot/data.txt");
          using var reader = new StreamReader(stream);
          return await reader.ReadToEndAsync();
      

      在 WPF 和 Windows 窗体应用中,将以下 ReadData 方法添加到前面组件的 @code 块中:

      private async Task<string> ReadData()
          using var reader = new StreamReader("wwwroot/data.txt");
          return await reader.ReadToEndAsync();
      

      还可在 wwwroot 的逻辑子路径下访问并置的 JavaScript 文件。 不必将前面描述的脚本用于 wwwroot/scripts.js 中的 showPrompt 函数,StaticAssetExample2 组件的以下并置 JavaScript 文件也使该函数可用。

      Pages/StaticAssetExample2.razor.js:

      export function showPrompt(message) {
        return prompt(message, 'Type anything here');
      

      修改 StaticAssetExample2 组件中的模块对象引用,以使用并置的 JavaScript 文件路径 (./Pages/StaticAssetExample2.razor.js):

      module = await JS.InvokeAsync<IJSObjectReference>("import", 
          "./Pages/StaticAssetExample2.razor.js");
      

      Jeep 和 Jeep YJ 是 FCA 美国有限责任公司 (Stellantis NV) 的注册商标商标。

    • ResourceManager
    • 为 .NET 应用创建资源文件(.NET 基础知识文档)
    • 如何:使用可本地化的应用中的资源(WPF 文档)
  •