Freigeben über


Anzeigen von Bildern und Dokumenten in ASP.NET Core Blazor

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Warnung

Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der Supportrichtlinie für .NET und .NET Core. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

In diesem Artikel werden Ansätze zum Anzeigen von Bildern und Dokumenten in Blazor-Apps beschrieben.

Die Beispiele in diesem Artikel können in den Blazor-Beispiel-Apps eingesehen und verwendet werden:

dotnet/blazor-samples GitHub-Repository: Navigieren Sie zur App mit dem Namen BlazorSample_BlazorWebApp (8.0 oder höher), BlazorSample_Server (7.0 oder früher) oder BlazorSample_WebAssembly.

Dynamisches Festlegen einer Bildquelle

Im folgenden Beispiel wird veranschaulicht, wie die Quelle eines Bilds dynamisch mit einem C#-Feld festgelegt wird.

In diesem Abschnitt werden drei Bilddateien mit den Namen image1.png, image2.png und image3.png verwendet. Die Bilder werden in einem Ordner mit dem Namen images im Web-Stammverzeichnis der App (wwwroot) abgelegt. Die Verwendung des Ordners images dient nur zur Demonstrationszwecken. Sie können statische Assets in jedem beliebigen Ordnerlayout organisieren, das Sie bevorzugen, einschließlich der Bereitstellung von Assets direkt aus dem wwwroot-Ordner.

In der folgenden ShowImage1-Komponente:

  • Die Quelle des Bilds (src) wird in C# dynamisch auf den Wert imageSource festgelegt.
  • Mit der ShowImage-Methode wird das imageSource-Feld basierend auf einem id-Bildargument aktualisiert, das an die Methode übergeben wird.
  • Die ShowImage-Methode wird von gerenderten Schaltflächen mit einem Bild-Argument für jedes der drei verfügbaren Bilder im Ordner images aufgerufen. Der Dateiname besteht aus dem Argument, das an die Methode übergeben wird, und entspricht einem der drei Bilder im images Ordner.

ShowImage1.razor:

@page "/show-image-1"

<PageTitle>Show Image 1</PageTitle>

<h1>Show Image Example 1</h1>

@if (imageSource is not null)
{
    <p>
        <img src="@imageSource" />
    </p>
}

@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)
{
    <p>
        <img src="@imageSource" />
    </p>
}

@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)
{
    <p>
        <img src="@imageSource" />
    </p>
}

@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";
    }
}

Im vorherigen Beispiel wird ein C#-Feld verwendet, um die Quelldaten des Bilds zu aufzunehmen. Für die Aufnahme der Daten können Sie jedoch auch eine C#-Eigenschaft verwenden.

Hinweis

Verwenden Sie die direkte Verwendung einer Schleifenvariablen in einem Lambdaausdruck wie i im vorangehenden for-Schleifenbeispiel. Ansonsten wird dieselbe Variable von allen Lambdaausdrücken verwendet, sodass der gleiche Wert in allen Lambdaausdrücken verwendet wird. Erfassen Sie den Wert der Variablen in einer lokalen Variablen. Im vorherigen Beispiel:

  • Die Schleifenvariable i wird imageId zugewiesen.
  • imageId wird im Lambdaausdruck verwendet.

Verwenden Sie alternativ eine foreach Schleife mit Enumerable.Range, welche nicht vom vorherigen Problem betroffen ist:

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

Weitere Informationen finden Sie unter Ereignisbehandlung in Blazor in ASP.NET Core.

Streamen von Bild- oder Dokumentdaten

Ein Bild oder ein anderes Dokument, wie z. B. eine PDF-Datei, kann mithilfe der Streaming-Interop-Funktionen von Blazor direkt an den Client übertragen werden, anstatt die Datei unter einer öffentlichen URL zu hosten.

Das Beispiel in diesem Abschnitt streamt Quelldaten mithilfe von JavaScript (JS) Interop. Die folgende JS-Funktion setSource:

  • Kann zum Streamen von Inhalten für die folgenden Elemente verwendet werden: <body>, <embed>, <iframe>, <img>, <link>, <object>, <script>, <style> und <track>.
  • Akzeptiert das Element id, um den Inhalt der Datei, einen Datenstrom für das Dokument, den Inhaltstyp und einen Titel für das Anzeigeelement anzuzeigen.

Mit der Funktion werden folgende Aktionen ausgeführt:

  • Sie liest den bereitgestellten Datenstrom in einen ArrayBuffer ein.
  • Erstellt ein Blob, um das ArrayBuffer zu umschließen, und legt den Inhaltstyp des Blobs fest.
  • Erstellt eine Objekt-URL, die als Adresse für das darzustellende Dokument dient.
  • Legt den Titel des Elements (title) aus dem title-Parameter fest und legt die Quelle des Elements (src) aus der URL des erstellten Objekts fest.
  • Um Speicherverluste zu vermeiden, ruft die Funktion revokeObjectURL auf, um die Objekt-URL zu entsorgen, nachdem das Element die Ressource geladen hat (load-Ereignis).
<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>

Hinweis

Allgemeine Anleitungen zu JS Standort und unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET Core Blazor -Apps.

Die folgende ShowImage2-Komponente:

  • Fügt Dienste für eine System.Net.Http.HttpClient und Microsoft.JSInterop.IJSRuntime ein.
  • Enthält ein <img> Tag, um ein Bild anzuzeigen.
  • Verfügt über eine GetImageStreamAsync C#-Methode zum Abrufen einer Stream für ein Bild. Eine Produktions-App kann ein Bild auf der Grundlage des jeweiligen Benutzers dynamisch erzeugen oder ein Bild aus dem Speicher abrufen. Im folgenden Beispiel wird der .NET-Avatar für das dotnet GitHub-Repository abgerufen.
  • Verfügt über eine SetImageAsync Methode, die mit der Auswahl der Schaltfläche durch den Benutzer ausgelöst wird. SetImageAsync führt die folgenden Schritte aus:
    • Die Methode ruft den Stream aus GetImageStreamAsync ab.
    • Sie umschließt den Stream in einem DotNetStreamReference, der das Streamen der Bilddaten an den Client ermöglicht.
    • Ruft die JavaScript-Funktion setSource auf, die die Daten auf dem Client entgegennimmt.

Hinweis

Serverseitige Apps verwenden einen dedizierten HttpClient-Dienst für Anforderungen, sodass keine Aktion von den Entwickelnden einer serverseitigen Blazor-App zum Registrieren eines HttpClient-Diensts erforderlich ist. Clientseitige Apps verfügen über eine HttpClient-Standarddienstregistrierung, wenn die App aus einer Blazor-Projektvorlage erstellt wird. Wenn keine HttpClient-Dienstregistrierung in der Datei Program einer clientseitigen App vorhanden ist, stellen Sie eine durch Hinzufügen von builder.Services.AddHttpClient(); bereit. Weitere Informationen erhalten Sie unter Stellen von HTTP-Anforderungen mithilfe von IHttpClientFactory in ASP.NET Core.

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" />
</div>

@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" />
</div>

@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" />
</div>

@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");
    }
}

Die folgende ShowFile-Komponente lädt entweder eine Textdatei (files/quote.txt) oder eine PDF-Datei (files/quote.pdf) in ein <iframe>-Element (MDN-Dokumentation).

Achtung

Die Verwendung des <iframe>-Elements im folgenden Beispiel ist sicher und erfordert kein [sandboxing] (https://developer.mozilla.org/docs/Web/HTML/Element/iframe#sandbox), da der Inhalt aus der App, einer vertrauenswürdigen Quelle, geladen wird.

Beim Laden von Inhalten aus einer nicht vertrauenswürdigen Quelle oder bei Benutzereingaben besteht bei einem nicht ordnungsgemäß implementierten <iframe>-Element das Risiko, dass Sicherheitslücken entstehen.

ShowFile.razor:

@page "/show-file"
@inject NavigationManager NavigationManager
@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>
    </div>
    <iframe id="iframe" style="height: calc(100vh - 200px)" />
</div>

@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>
    </div>
    <iframe id="iframe" style="height: calc(100vh - 200px)" />
</div>

@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>
    </div>
    <iframe id="iframe" style="height: calc(100vh - 200px)" />
</div>

@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);
    }
}

Zusätzliche Ressourcen