Condividi tramite


Visualizzare immagini e documenti in ASP.NET Core Blazor

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Questo articolo descrive gli approcci per la visualizzazione di immagini e documenti nelle Blazor app.

Gli esempi in questo articolo sono disponibili per l'ispezione e l'uso Blazor nelle app di esempio:

dotnet/blazor-samples Repository GitHub: passare all'app denominata BlazorSample_BlazorWebApp (8.0 o versione successiva), BlazorSample_Server (7.0 o versioni precedenti) o BlazorSample_WebAssembly.

Impostare dinamicamente un'origine immagine

L'esempio seguente illustra come impostare dinamicamente l'origine di un'immagine con un campo C#.

L'esempio in questa sezione usa tre file di immagine, denominati image1.png, image2.pnge image3.png. Le immagini vengono inserite in una cartella denominata images nella radice Web dell'app (wwwroot). L'uso della images cartella è solo a scopo dimostrativo. È possibile organizzare gli asset statici in qualsiasi layout di cartella preferito, inclusa la gestione degli asset direttamente dalla wwwroot cartella.

Nel componente ShowImage1 seguente:

  • L'origine dell'immagine (src) viene impostata dinamicamente sul valore di imageSource in C#.
  • Il ShowImage metodo aggiorna il imageSource campo in base a un argomento immagine id passato al metodo .
  • I pulsanti sottoposti a rendering chiamano il ShowImage metodo con un argomento immagine per ognuna delle tre immagini disponibili nella images cartella. Il nome del file è composto usando l'argomento passato al metodo e corrisponde a una delle tre immagini nella images cartella.

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

L'esempio precedente usa un campo C# per contenere i dati di origine dell'immagine, ma è anche possibile usare una proprietà C# per contenere i dati.

Evitare di usare una variabile di ciclo direttamente in un'espressione lambda, ad esempio i nell'esempio di ciclo precedente for . In caso contrario, la stessa variabile viene usata da tutte le espressioni lambda, che comporta l'uso dello stesso valore in tutte le espressioni lambda. Acquisire il valore della variabile in una variabile locale. Nell'esempio precedente:

  • La variabile i di ciclo viene assegnata a imageId.
  • imageId viene usato nell'espressione lambda.

In alternativa, usare un foreach ciclo con Enumerable.Range, che non soffre del problema precedente:

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

Per altre informazioni sulle espressioni lambda con la gestione degli eventi, vedere gestione degli eventi ASP.NET CoreBlazor.

Trasmettere dati di immagine o documento

Un'immagine o un altro tipo di documento, ad esempio un PDF, può essere trasmessa direttamente al client usando Blazorle funzionalità di interoperabilità di streaming anziché ospitare il file in un URL pubblico.

L'esempio in questa sezione trasmette i dati di origine usando l'interoperabilità JavaScript (JS). La funzione seguente setSourceJS :

  • Può essere usato per trasmettere il contenuto per gli elementi seguenti: , , <img>, , <object><link>, <script>, , <style>, e <track>. <iframe><embed><body>
  • Accetta un elemento id per visualizzare il contenuto del file, un flusso di dati per il documento, il tipo di contenuto e un titolo per l'elemento di visualizzazione.

La funzione :

  • Legge il flusso fornito in un oggetto ArrayBuffer.
  • Crea un Blob oggetto per eseguire il wrapping di ArrayBuffer, impostando il tipo di contenuto del BLOB.
  • Crea un URL dell'oggetto da usare come indirizzo per il documento da visualizzare.
  • Imposta il titolo dell'elemento (title) dal title parametro e imposta l'origine dell'elemento (src) dall'URL dell'oggetto creato.
  • Per evitare perdite di memoria, la funzione chiama revokeObjectURL per eliminare l'URL dell'oggetto dopo che l'elemento carica la risorsa (load evento).
<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>

Nota

Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.

Componente seguente ShowImage2 :

  • Inserisce i servizi per un oggetto System.Net.Http.HttpClient e Microsoft.JSInterop.IJSRuntime.
  • Include un <img> tag per visualizzare un'immagine.
  • Dispone di un GetImageStreamAsync metodo C# per recuperare un oggetto Stream per un'immagine. Un'app di produzione può generare dinamicamente un'immagine in base all'utente specifico o recuperare un'immagine dall'archiviazione. L'esempio seguente recupera l'avatar .NET per il dotnet repository GitHub.
  • Dispone di un SetImageAsync metodo attivato dalla selezione del pulsante da parte dell'utente. SetImageAsync esegue i passaggi seguenti:
    • Recupera l'oggetto Stream da GetImageStreamAsync.
    • Esegue il wrapping di Stream in un DotNetStreamReferenceoggetto , che consente di trasmettere i dati dell'immagine al client.
    • Richiama la setSource funzione JavaScript, che accetta i dati nel client.

Nota

Le app lato server usano un servizio dedicato HttpClient per effettuare richieste, quindi non è richiesta alcuna azione da parte dello sviluppatore di un'app lato Blazor server per registrare un HttpClient servizio. Le app sul lato client hanno una registrazione del servizio predefinita HttpClient quando l'app viene creata da un Blazor modello di progetto. Se una HttpClient registrazione del servizio non è presente nel Program file di un'app lato client, specificarne una aggiungendo builder.Services.AddHttpClient();. Per altre informazioni, vedere Effettuare richieste HTTP usando 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() => 
        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");
    }
}

Il componente seguente ShowFile carica un file di testo (files/quote.txt) o un file PDF (files/quote.pdf) in un <iframe> elemento (documentazione MDN).

Attenzione

L'uso dell'elemento nell'esempio <iframe> seguente è sicuro e non richiede la sandboxing perché il contenuto viene caricato dall'app, che è un'origine attendibile.

Quando si carica il contenuto da un'origine o un input utente non attendibile, un elemento implementato <iframe> in modo non corretto rischia di creare vulnerabilità di sicurezza.

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

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

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

Risorse aggiuntive