相关文章推荐
坚强的紫菜汤  ·  java httpclient ipv6 ...·  1 周前    · 
纯真的橙子  ·  在 ASP.NET Core ...·  7 小时前    · 
爱喝酒的荔枝  ·  [Solved] i need to ...·  1 年前    · 
开朗的茄子  ·  react native ...·  1 年前    · 

本文介绍在 Blazor 应用中显示图像和文档的方法。

本文中的示例可在 Blazor 示例应用 中查看和使用:

dotnet/blazor-samples GitHub 存储库 :导航到名为 BlazorSample_BlazorWebApp (8.0 或更高版本)、 BlazorSample_Server (7.0 或更早版本)或 BlazorSample_WebAssembly 的应用。

动态设置图像源

下面的示例演示如何使用 C# 字段动态设置图像的源。

本节中的示例使用三个图像文件,分别名为 image1.png image2.png image3.png 。 图像放置在应用的 Web 根目录 ( wwwroot ) 中名为 images 的文件夹中。 images 文件夹的使用仅用于演示目的。 可以按照你喜欢的任何文件夹布局来组织图像资产,包括直接从 wwwroot 文件夹提供图像。

在下面的 ShowImage1 组件中:

  • 图像中的源 ( src ) 动态设置为 C# 中的值 imageSource
  • ShowImage 方法基于传递到方法的图像 id 参数更新 imageSource 字段。
  • 呈现的按钮使用 images 文件夹中每个可用图像(共三个)的图像参数调用 ShowImage 方法。 文件名使用传递给该方法的参数组成,并匹配 images 文件夹中的三个图像之一。
  • ShowImage1.razor :

    @page "/show-image-1"
    <PageTitle>Show Image 1</PageTitle>
    <h1>Show Image Example 1</h1>
    @if (imageSource is not null)
            <img src="@imageSource" />
    @for (var i = 1; i <= 3; i++)
        var imageId = i;
        <button @onclick="() => ShowImage(imageId)">
            Image @imageId
        </button>
    @code {
        private string? imageSource;
        private void ShowImage(int id) => imageSource = $"images/image{id}.png";
    
    @page "/show-image-1"
    <PageTitle>Show Image 1</PageTitle>
    <h1>Show Image Example 1</h1>
    @if (imageSource is not null)
            <img src="@imageSource" />
    @for (var i = 1; i <= 3; i++)
        var imageId = i;
        <button @onclick="() => ShowImage(imageId)">
            Image @imageId
        </button>
    @code {
        private string? imageSource;
        private void ShowImage(int id) => imageSource = $"images/image{id}.png";
    
    @page "/show-image-1"
    <h1>Dynamic Image Source Example</h1>
    @if (imageSource is not null)
            <img src="@imageSource" />
    @for (var i = 1; i <= 3; i++)
        var imageId = i;
        <button @onclick="() => ShowImage(imageId)">
            Image @imageId
        </button>
    @code {
        private string? imageSource;
        private void ShowImage(int id)
            imageSource = $"images/image{id}.png";
    
    @page "/show-image-1"
    <h1>Dynamic Image Source Example</h1>
    @if (imageSource is not null)
            <img src="@imageSource" />
    @for (var i = 1; i <= 3; i++)
        var imageId = i;
        <button @onclick="() => ShowImage(imageId)">
            Image @imageId
        </button>
    @code {
        private string? imageSource;
        private void ShowImage(int id)
            imageSource = $"images/image{id}.png";
    

    前面的示例使用 C# 字段来保存图像的源数据,但也可使用 C# 属性来保存数据。

    避免直接在 Lambda 表达式中使用循环变量,如前面的 for 循环示例中的 i。 否则,所有 Lambda 表达式将使用相同的变量,这将导致在所有 Lambda 中使用相同的值。 在局部变量中捕获该变量的值。 在上面的示例中:

  • 将循环变量 i 分配到 imageId
  • imageId 用于 lambda 表达式。
  • 或者,将 foreach 循环与 Enumerable.Range 结合使用,这样就能避开上述问题:

    @foreach (var imageId in Enumerable.Range(1, 3))
        <button @onclick="() => ShowImage(imageId)">
            Image @imageId
        </button>
    

    有关 lambda 表达式和事件处理的详细信息,请参阅 ASP.NET Core Blazor 事件处理

    流式传输图像或文档数据

    可以使用 Blazor 的流式互操作功能将图像或其他文档类型(例如 PDF)直接传输到客户端,而不是将文件托管在公共 URL 上。

    本部分中的示例使用 JavaScript (JS) 互操作流式传输源数据。 以下 setSourceJS 函数:

  • 可用于流式传输以下元素的内容:<body><embed><iframe><img><link><object><script><style><track>
  • 接受用于显示文件内容的元素 id、文档的数据流、内容类型以及显示元素的标题。
  • 将提供的流读入 ArrayBuffer
  • 创建一个 Blob 来包装 ArrayBuffer,并设置 Blob 的内容类型。
  • 创建一个对象 URL,作为要显示的文档的地址。
  • title 参数设置元素的标题 (title),并从创建的对象 URL 设置元素的源 (src)。
  • 为了防止内存泄漏,函数会在元素加载资源(load 事件)后调用 revokeObjectURL 来处理对象 URL。
  • <script>
      window.setSource = async (elementId, stream, contentType, title) => {
        const arrayBuffer = await stream.arrayBuffer();
        let blobOptions = {};
        if (contentType) {
          blobOptions['type'] = contentType;
        const blob = new Blob([arrayBuffer], blobOptions);
        const url = URL.createObjectURL(blob);
        const element = document.getElementById(elementId);
        element.title = title;
        element.onload = () => {
          URL.revokeObjectURL(url);
        element.src = url;
    </script>
    

    有关 JS 的常规指导和我们对常规应用的建议,请参阅 ASP.NET Core Blazor 应用中的 JavaScript 位置

    以下 ShowImage2 组件:

  • System.Net.Http.HttpClientMicrosoft.JSInterop.IJSRuntime 注入服务。
  • 包含用于显示图像的标记 <img>
  • 拥有用于检索图像的 StreamGetImageStreamAsync C# 方法。 生产应用可以基于特定用户动态生成图像,或者从存储中检索图像。 以下示例检索 dotnet GitHub 存储库的 .NET 头像。
  • 拥有在用户选择按钮时触发的 SetImageAsync 方法。 SetImageAsync 执行下列步骤:
    • GetImageStreamAsync 检索 Stream
    • Stream 包装在 DotNetStreamReference 中,这允许将图像数据流式传输到客户端。
    • 调用 setSource JavaScript 函数,该函数接受客户端上的数据。
    • 服务器端应用使用专用的 HttpClient 服务发出请求,因此服务器端 Blazor 应用的开发人员无需执行任何操作即可注册 HttpClient 服务。 根据 Blazor 项目模板创建应用时,客户端应用提供默认的 HttpClient 服务注册。 如果客户端应用的 Program 文件中不存在 HttpClient 服务注册,请通过添加 builder.Services.AddHttpClient(); 来提供。 有关详细信息,请参阅在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

      ShowImage2.razor:

      @page "/show-image-2"
      @inject HttpClient Http
      @inject IJSRuntime JS
      <PageTitle>Show Image 2</PageTitle>
      <h1>Show Image Example 2</h1>
      <button @onclick="SetImageAsync">
          Set Image
      </button>
      <div class="p-3">
          <img id="avatar" />
      @code {
          private async Task<Stream> GetImageStreamAsync() => 
              await Http.GetStreamAsync("https://avatars.githubusercontent.com/u/9141961");
          private async Task SetImageAsync()
              var imageStream = await GetImageStreamAsync();
              var strRef = new DotNetStreamReference(imageStream);
              await JS.InvokeVoidAsync("setSource", "avatar", strRef, "image/png", 
                  ".NET GitHub avatar");
      
      @page "/show-image-2"
      @inject HttpClient Http
      @inject IJSRuntime JS
      <PageTitle>Show Image 2</PageTitle>
      <h1>Show Image Example 2</h1>
      <button @onclick="SetImageAsync">
          Set Image
      </button>
      <div class="p-3">
          <img id="avatar" />
      @code {
          private async Task<Stream> GetImageStreamAsync() => 
              await Http.GetStreamAsync("https://avatars.githubusercontent.com/u/9141961");
          private async Task SetImageAsync()
              var imageStream = await GetImageStreamAsync();
              var strRef = new DotNetStreamReference(imageStream);
              await JS.InvokeVoidAsync("setSource", "avatar", strRef, "image/png", 
                  ".NET GitHub avatar");
      
      @page "/show-image-2"
      @inject HttpClient Http
      @inject IJSRuntime JS
      <h1>Show Image Example 2</h1>
      <button @onclick="SetImageAsync">
          Set Image
      </button>
      <div class="p-3">
          <img id="avatar" />
      @code {
          private async Task<Stream> GetImageStreamAsync()
              return await Http.GetStreamAsync(
                  "https://avatars.githubusercontent.com/u/9141961");
          private async Task SetImageAsync()
              var imageStream = await GetImageStreamAsync();
              var strRef = new DotNetStreamReference(imageStream);
              await JS.InvokeVoidAsync("setSource", "avatar", strRef, "image/png", 
                  ".NET GitHub avatar");
      
      @page "/show-image-2"
      @inject HttpClient Http
      @inject IJSRuntime JS
      <h1>Show Image Example 2</h1>
      <button @onclick="SetImageAsync">
          Set Image
      </button>
      <div class="p-3">
          <img id="avatar" />
      @code {
          private async Task<Stream> GetImageStreamAsync()
              return await Http.GetStreamAsync(
                  "https://avatars.githubusercontent.com/u/9141961");
          private async Task SetImageAsync()
              var imageStream = await GetImageStreamAsync();
              var strRef = new DotNetStreamReference(imageStream);
              await JS.InvokeVoidAsync("setSource", "avatar", strRef, "image/png", 
                  ".NET GitHub avatar");
      

      以下 ShowFile 组件可将文本文件 (files/quote.txt) 或 PDF 文件 (files/quote.pdf) 加载到 <iframe> 元素(MDN 文档)

      在以下示例中使用 <iframe> 元素是安全的,不需要沙盒,因为内容是从应用(受信任的源)加载的。

      从不受信任的源或用户输入加载内容时,未正确地实现 <iframe> 元素可能会导致安全漏洞。

      ShowFile.razor:

      @page "/show-file"
      @inject NavigationManager Navigation
      @inject HttpClient Http
      @inject IJSRuntime JS
      <PageTitle>Show File</PageTitle>
      <div class="d-flex flex-column">
          <h1>Show File Example</h1>
          <div class="mb-4">
              <button @onclick="@(() => ShowFileAsync("files/quote.txt", 
                      "General Ravon quote (text file)"))">
                  Show text ('quote.txt')
              </button>
              <button @onclick="@(() => ShowFileAsync("files/quote.pdf", 
                      "General Ravon quote (PDF file)"))">
                  Show PDF ('quote.pdf')
              </button>
          <iframe id="iframe" style="height: calc(100vh - 200px)" />
      @code
          private async Task<(Stream, string?)> DownloadFileAsync(string url)
              var absoluteUrl = Navigation.ToAbsoluteUri(url);
              Console.WriteLine($"Downloading file from {absoluteUrl}");
              var response = await Http.GetAsync(absoluteUrl);
              string? contentType = null;
              if (response.Content.Headers.TryGetValues("Content-Type", out var values))
                  contentType = values.FirstOrDefault();
              return (await response.Content.ReadAsStreamAsync(), contentType);
          private async Task ShowFileAsync(string url, string title)
              var (fileStream, contentType) = await DownloadFileAsync(url);
              var strRef = new DotNetStreamReference(fileStream);
              await JS.InvokeVoidAsync("setSource", "iframe", strRef, contentType, title);
      
      @page "/show-file"
      @inject NavigationManager Navigation
      @inject HttpClient Http
      @inject IJSRuntime JS
      <PageTitle>Show File</PageTitle>
      <div class="d-flex flex-column">
          <h1>Show File Example</h1>
          <div class="mb-4">
              <button @onclick="@(() => ShowFileAsync("files/quote.txt", 
                      "General Ravon quote (text file)"))">
                  Show text ('quote.txt')
              </button>
              <button @onclick="@(() => ShowFileAsync("files/quote.pdf", 
                      "General Ravon quote (PDF file)"))">
                  Show PDF ('quote.pdf')
              </button>
          <iframe id="iframe" style="height: calc(100vh - 200px)" />
      @code
          private async Task<(Stream, string?)> DownloadFileAsync(string url)
              var absoluteUrl = Navigation.ToAbsoluteUri(url);
              Console.WriteLine($"Downloading file from {absoluteUrl}");
              var response = await Http.GetAsync(absoluteUrl);
              string? contentType = null;
              if (response.Content.Headers.TryGetValues("Content-Type", out var values))
                  contentType = values.FirstOrDefault();
              return (await response.Content.ReadAsStreamAsync(), contentType);
          private async Task ShowFileAsync(string url, string title)
              var (fileStream, contentType) = await DownloadFileAsync(url);
              var strRef = new DotNetStreamReference(fileStream);
              await JS.InvokeVoidAsync("setSource", "iframe", strRef, contentType, title);
      
      @page "/show-file"
      @inject NavigationManager NavigationManager
      @inject HttpClient Http
      @inject IJSRuntime JS
      <div class="d-flex flex-column">
          <h1>Show File Example</h1>
          <div class="mb-4">
              <button @onclick="@(() => ShowFileAsync("files/quote.txt", 
                      "General Ravon quote (text file)"))">
                  Show text ('quote.txt')
              </button>
              <button @onclick="@(() => ShowFileAsync("files/quote.pdf", 
                      "General Ravon quote (PDF file)"))">
                  Show PDF ('quote.pdf')
              </button>
          <iframe id="iframe" style="height: calc(100vh - 200px)" />
      @code
          private async Task<(Stream, string?)> DownloadFileAsync(string url)
              var absoluteUrl = NavigationManager.ToAbsoluteUri(url);
              Console.WriteLine($"Downloading file from {absoluteUrl}");
              var response = await Http.GetAsync(absoluteUrl);
              string? contentType = null;
              if (response.Content.Headers.TryGetValues("Content-Type", out var values))
                  contentType = values.FirstOrDefault();
              return (await response.Content.ReadAsStreamAsync(), contentType);
          private async Task ShowFileAsync(string url, string title)
              var (fileStream, contentType) = await DownloadFileAsync(url);
              var strRef = new DotNetStreamReference(fileStream);
              await JS.InvokeVoidAsync("setSource", "iframe", strRef, contentType, title);
      
      @page "/show-file"
      @inject NavigationManager NavigationManager
      @inject HttpClient Http
      @inject IJSRuntime JS
      <div class="d-flex flex-column">
          <h1>Show File Example</h1>
          <div class="mb-4">
              <button @onclick="@(() => ShowFileAsync("files/quote.txt", 
                      "General Ravon quote (text file)"))">
                  Show text ('quote.txt')
              </button>
              <button @onclick="@(() => ShowFileAsync("files/quote.pdf", 
                      "General Ravon quote (PDF file)"))">
                  Show PDF ('quote.pdf')
              </button>
          <iframe id="iframe" style="height: calc(100vh - 200px)" />
      @code
          private async Task<(Stream, string?)> DownloadFileAsync(string url)
              var absoluteUrl = NavigationManager.ToAbsoluteUri(url);
              Console.WriteLine($"Downloading file from {absoluteUrl}");
              var response = await Http.GetAsync(absoluteUrl);
              string? contentType = null;
              if (response.Content.Headers.TryGetValues("Content-Type", out var values))
                  contentType = values.FirstOrDefault();
              return (await response.Content.ReadAsStreamAsync(), contentType);
          private async Task ShowFileAsync(string url, string title)
              var (fileStream, contentType) = await DownloadFileAsync(url);
              var strRef = new DotNetStreamReference(fileStream);
              await JS.InvokeVoidAsync("setSource", "iframe", strRef, contentType, title);
      
    • ASP.NET Core Blazor 文件上传
    • 文件上传:上传图像预览
    • ASP.NET Core Blazor 文件下载
    • 在 ASP.NET Core Blazor 中从 JavaScript 函数调用 .NET 方法
    • 在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数
    • Blazor 示例 GitHub 存储库 (dotnet/blazor-samples)下载方法
  •