Udostępnij za pośrednictwem


Wyświetlanie obrazów i dokumentów w programie ASP.NET Core Blazor

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu dla .NET 9.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu dla .NET 9.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu dla .NET 9.

W tym artykule opisano metody wyświetlania obrazów i dokumentów w Blazor aplikacjach.

Przykłady w tym artykule są dostępne do inspekcji i użycia w przykładowych Blazor aplikacjach:

dotnet/blazor-samples Repozytorium GitHub: przejdź do aplikacji o nazwie BlazorSample_BlazorWebApp (8.0 lub nowszej), BlazorSample_Server (7.0 lub starszej) lub BlazorSample_WebAssembly.

Dynamiczne ustawianie źródła obrazu

W poniższym przykładzie pokazano, jak dynamicznie ustawić źródło obrazu przy użyciu pola języka C#.

W przykładzie w tej sekcji użyto trzech plików obrazów o nazwie image1.png, image2.pngi image3.png. Obrazy są umieszczane w folderze o nazwie images w katalogu głównym aplikacji (wwwroot). Korzystanie z images folderu jest przeznaczone tylko do celów demonstracyjnych. Zasoby statyczne można organizować w dowolnym układzie folderów według własnych upodobań, łącznie z możliwością obsługi zasobów bezpośrednio z folderu wwwroot.

W poniższym składniku ShowImage1:

  • Źródło obrazu (src) jest dynamicznie ustawiane na wartość imageSource w języku C#.
  • Metoda ShowImage aktualizuje imageSource pole na podstawie argumentu obrazu id przekazanego do metody .
  • Renderowane przyciski wywołują metodę ShowImage z argumentem obrazu dla każdej z trzech dostępnych grafik w folderze images. Nazwa pliku składa się przy użyciu argumentu przekazanego do metody i pasuje do jednego z trzech obrazów w folderze images .

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"

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

W poprzednim przykładzie do przechowywania danych źródłowych obrazu jest używane pole języka C#, ale do przechowywania danych można również użyć właściwości języka C#.

Unikaj używania zmiennej pętli bezpośrednio w wyrażeniu lambda, takim jak i w poprzednim przykładzie for pętli. W przeciwnym razie ta sama zmienna jest używana przez wszystkie wyrażenia lambda, co powoduje użycie tej samej wartości we wszystkich wyrażeniach lambda. Uchwyć wartość zmiennej w zmiennej lokalnej. W powyższym przykładzie:

  • Zmienna sterująca pętli i jest przypisywana do imageId.
  • imageId jest używany w wyrażeniu lambda.

Można użyć foreach pętli z Enumerable.Range, która nie ma problemu występującego wcześniej.

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

Aby uzyskać więcej informacji na temat wyrażeń lambda z obsługą zdarzeń, zobacz Blazor ASP.NET Core.

Przesyłanie strumieniowe danych obrazu lub dokumentu

Obraz lub inny typ dokumentu, taki jak PDF, można przesyłać bezpośrednio do klienta przy użyciu Blazor funkcji przesyłania strumieniowego zamiast umieszczania pliku pod publicznym adresem URL.

Przykład w tej sekcji przesyła strumieniowo dane źródłowe przy użyciu JS języka JavaScript (). Następująca setSourceJS funkcja:

  • Może służyć do przesyłania strumieniowego zawartości dla następujących elementów: <body>, <embed>, <iframe>, <img>, <link>, <object>, <script>, <style> i <track>.
  • Akceptuje element id do wyświetlania zawartości pliku, strumienia danych dokumentu, typu zawartości i tytułu elementu wyświetlania.

Funkcja:

  • Odczytuje dostarczony strumień do elementu ArrayBuffer.
  • Tworzy Blob do opakowania ArrayBuffer, ustawiając typ zawartości obiektu blob.
  • Tworzy adres URL obiektu, który będzie służył jako adres dokumentu do wyświetlenia.
  • Ustaw tytuł elementu (title) z parametru title i ustawia źródło elementu (src) na podstawie utworzonego adresu URL obiektu.
  • Aby zapobiec wyciekom pamięci, funkcja wywołuje revokeObjectURL w celu zamknięcia adresu URL obiektu po załadowaniu zasobu (load wydarzenie).
<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>

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Blazor ASP.NET Core.

ShowImage2 Następujący składnik:

  • Wprowadza usługi dla komponentu System.Net.Http.HttpClient i Microsoft.JSInterop.IJSRuntime.
  • <img> Zawiera tag do wyświetlenia obrazu.
  • Ma metodę C# GetImageStreamAsync, aby pobrać Stream dla obrazu. Aplikacja produkcyjna może dynamicznie generować obraz na podstawie określonego użytkownika lub pobierać obraz z magazynu. Poniższy przykład pobiera obrazek awatara dla platformy .NET do dotnet repozytorium GitHub.
  • Ma metodę SetImageAsync wyzwalaną przez użytkownika po wybraniu przycisku. SetImageAsync wykonuje następujące kroki:
    • Pobiera element Stream z GetImageStreamAsync.
    • Opakowuje element Stream w element DotNetStreamReference, co umożliwia strumieniowanie danych obrazu do klienta.
    • setSource Wywołuje funkcję JavaScript, która akceptuje dane na kliencie.

Uwaga

Aplikacje po stronie serwera używają dedykowanej HttpClient usługi do tworzenia żądań, więc deweloper aplikacji po stronie Blazor serwera nie musi wykonywać żadnych działań w celu zarejestrowania HttpClient usługi. Aplikacje po stronie klienta mają domyślną HttpClient rejestrację usługi podczas tworzenia aplikacji na podstawie Blazor szablonu projektu. HttpClient Jeśli rejestracja usługi nie istnieje w Program pliku aplikacji po stronie klienta, należy ją dodać, dodając builder.Services.AddHttpClient();. Aby uzyskać więcej informacji, zobacz Tworzenie żądań HTTP za pomocą interfejsu IHttpClientFactory na platformie 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() => 
        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" />
</div>

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

Poniższy składnik ShowFile ładuje plik tekstowy (files/quote.txt) lub plik PDF (files/quote.pdf) do elementu <iframe>.

Ostrzeżenie

Użycie elementu <iframe> w poniższym przykładzie jest bezpieczne i nie wymaga kontroli w izolowanym środowisku, ponieważ zawartość jest ładowana z aplikacji, która jest zaufanym źródłem.

Podczas ładowania zawartości z niezaufanego źródła lub danych wejściowych użytkownika nieprawidłowo zaimplementowany <iframe> element stanowi zagrożenie związane z tworzeniem luk w zabezpieczeniach.

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

@code
{
    private async Task<(Stream, string?)> DownloadFileAsync(string url)
    {
        var absoluteUrl = Navigation.ToAbsoluteUri(url);
        Console.WriteLine($"Downloading file from {absoluteUrl}");

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

@code
{
    private async Task<(Stream, string?)> DownloadFileAsync(string url)
    {
        var absoluteUrl = Navigation.ToAbsoluteUri(url);
        Console.WriteLine($"Downloading file from {absoluteUrl}");

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

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

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

Dodatkowe zasoby