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ą, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy (Zasady obsługi platformy .NET Core). Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

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ą, zapoznaj się z wersją tego artykułu platformy .NET 8.

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 preferowanym układzie folderów, w tym obsługiwać wwwroot zasoby bezpośrednio z folderu.

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 .
  • Przyciski renderowane powodują wywołanie ShowImage metody z argumentem obrazu dla każdego z trzech dostępnych obrazów 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. Przechwyć wartość zmiennej w zmiennej lokalnej. W powyższym przykładzie:

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

Alternatywnie należy użyć foreach pętli z elementem Enumerable.Range, która nie ma problemu z poprzednim:

@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 obsługa zdarzeń ASP.NET CoreBlazor.

Przesyłanie strumieniowe danych obrazu lub dokumentu

Obraz lub inny typ dokumentu, taki jak PLIK PDF, można przesyłać bezpośrednio do klienta przy użyciu Blazorfunkcji międzyoperacyjnej przesyłania strumieniowego zamiast hostowania pliku pod publicznym adresem URL.

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

  • Może służyć do przesyłania strumieniowego zawartości dla następujących elementów: <body>, , <iframe><embed>, <img><link><script><object>, <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 udostępniony strumień do elementu ArrayBuffer.
  • Tworzy obiekt w Blob celu opakowania ArrayBufferobiektu , ustawiając typ zawartości obiektu blob.
  • Tworzy adres URL obiektu, który będzie służył jako adres, który ma być wyświetlany.
  • 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 metodę usuwania adresu URL obiektu po załadowaniu zasobu (load zdarzenia).
<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 Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

ShowImage2 Następujący składnik:

  • Wprowadza usługi dla elementu System.Net.Http.HttpClient i Microsoft.JSInterop.IJSRuntime.
  • <img> Zawiera tag do wyświetlenia obrazu.
  • Ma metodę GetImageStreamAsync języka C#, aby pobrać Stream element 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 awatar platformy .NET dla 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 obiekcie DotNetStreamReference, który umożliwia przesyłanie strumieniowe 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, podaj je, dodając element 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 ShowFile składnik ładuje plik tekstowy (files/quote.txt) lub plik PDF (files/quote.pdf) do <iframe> elementu (dokumentacja MDN).

Uwaga

<iframe> Użycie elementu w poniższym przykładzie jest bezpieczne i nie wymaga piaskownicy, 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 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

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

Dodatkowe zasoby