Dela via


Visa bilder och dokument i ASP.NET Core Blazor

Anmärkning

Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Viktigt!

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

I den här artikeln beskrivs metoder för att visa bilder och dokument i Blazor appar.

Exemplen i den här artikeln är tillgängliga för inspektion och användning i Blazor exempelappar:

dotnet/blazor-samples GitHub-lagringsplats: Navigera till appen med namnet BlazorSample_BlazorWebApp (8.0 eller senare), BlazorSample_Server (7.0 eller tidigare) eller BlazorSample_WebAssembly.

Ange en bildkälla dynamiskt

I följande exempel visas hur du dynamiskt anger en bilds källa med ett C#-fält.

Exemplet i det här avsnittet använder tre bildfiler med namnet image1.png, image2.pngoch image3.png. Bilderna placeras i en mapp med namnet images i appens webbrot (wwwroot). Användningen av mappen images är endast i demonstrationssyfte. Du kan ordna statiska tillgångar i valfri mapplayout som du föredrar, inklusive att hantera tillgångar direkt från mappen wwwroot.

I den följande komponenten ShowImage1:

  • Bildens källa (src) är dynamiskt inställd på värdet för imageSource i C#.
  • Metoden ShowImage uppdaterar fältet imageSource baserat på en bild id argument som skickas till metoden.
  • Renderade knappar anropar metoden ShowImage med ett bildargument för var och en av de tre tillgängliga bilderna i mappen images. Filnamnet består av argumentet som skickas till metoden och matchar en av de tre bilderna i mappen 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";
    }
}

I föregående exempel används ett C#-fält för att lagra bildens källdata, men du kan också använda en C#-egenskap för att lagra data.

Undvik att använda en loopvariabel direkt i ett lambda-uttryck, till exempel i i föregående for loopexempel. I annat fall används samma variabel av alla lambda-uttryck, vilket resulterar i användning av samma värde i alla lambdas. Avbilda variabelns värde i en lokal variabel. I föregående exempel:

  • Loopvariabeln i tilldelas till imageId.
  • imageId används i lambda-uttrycket.

Du kan också använda en foreach-loop med Enumerable.Range, som inte lider av föregående problem:

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

Mer information om lambda-uttryck med händelsehantering finns i ASP.NET Core Blazor händelsehantering.

Strömma bild- eller dokumentdata

En bild eller annan dokumenttyp, till exempel en PDF, kan överföras direkt till klienten genom Blazor:s strömmande interopfunktioner istället för att lägga upp filen på en offentlig URL.

Exemplet i det här avsnittet strömmar källdata med hjälp av JavaScript (JS) interop. Följande setSourceJS funktion:

  • Kan användas för att strömma innehåll för följande element: <body>, <embed>, <iframe>, <img>, <link>, <object>, <script>, <style>och <track>.
  • Accepterar ett element id för att visa filens innehåll, en dataström för dokumentet, innehållstypen och en rubrik för visningselementet.

Funktionen:

  • Läser den angivna strömmen till en ArrayBuffer.
  • Skapar en Blob för att omsluta ArrayBufferoch anger blobens innehållstyp.
  • Skapar en objekt-URL som ska fungera som adress för dokumentet som ska visas.
  • Ange elementets rubrik (title) från parametern title och anger elementets källa (src) från den skapade objekt-URL:en.
  • För att förhindra minnesläckor anropar funktionen revokeObjectURL att ta bort objekt-URL:en när elementet har läst in resursen (load händelse).
<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>

Anmärkning

Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.

Följande ShowImage2 komponent:

  • Implementerar tjänster för en System.Net.Http.HttpClient och Microsoft.JSInterop.IJSRuntime.
  • Innehåller en <img> tagg för att visa en bild.
  • Har en GetImageStreamAsync C#-metod för att hämta en Stream för en bild. En produktionsapp kan dynamiskt generera en avbildning baserat på den specifika användaren eller hämta en avbildning från lagring. I följande exempel hämtas .NET-avatar för dotnet GitHub-repository.
  • Har en SetImageAsync-metod som aktiveras när användaren väljer knappen. SetImageAsync utför följande steg:
    • Hämtar Stream från GetImageStreamAsync.
    • Omsluter Stream i en DotNetStreamReference, vilket gör det möjligt att strömma bilddata till klienten.
    • Anropar funktionen setSource JavaScript, som accepterar data på klienten.

Anmärkning

Appar på serversidan använder en dedikerad HttpClient-tjänst för att göra begäranden, så ingen åtgärd krävs av utvecklaren av en Blazor app på serversidan för att registrera en HttpClient-tjänst. Klientprogram har en standardregistrering för tjänsten HttpClient när appen skapas från en projektmall Blazor. Om en HttpClient tjänstregistrering inte finns i Program-filen för en app på klientsidan, anger du en genom att lägga till builder.Services.AddHttpClient();. Mer information finns i Gör HTTP-begäranden med IHttpClientFactory i 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");
    }
}

Följande ShowFile komponent läser antingen in en textfil (files/quote.txt) eller en PDF-fil (files/quote.pdf) till ett <iframe> element.

Varning

Användningen av elementet <iframe> i följande exempel är säker och kräver inte sandbox-miljö eftersom innehållet läses in från appen, som är en betrodd källa.

När innehåll läses in från en ej betrodd källa eller användarindata riskerar en felaktigt implementerad <iframe> element att skapa säkerhetsrisker.

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 ShowFileAsync(string url, string title)
    {
        var absoluteUrl = Navigation.ToAbsoluteUri(url);
        using var response = await Http.GetAsync(absoluteUrl);
        string? contentType = null;

        if (response.Content.Headers.TryGetValues("Content-Type", out var values))
        {
            contentType = values.FirstOrDefault();
        }

        var fileStream = await response.Content.ReadAsStreamAsync();
        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 ShowFileAsync(string url, string title)
    {
        var absoluteUrl = Navigation.ToAbsoluteUri(url);
        using var response = await Http.GetAsync(absoluteUrl);
        string? contentType = null;

        if (response.Content.Headers.TryGetValues("Content-Type", out var values))
        {
            contentType = values.FirstOrDefault();
        }

        var fileStream = await response.Content.ReadAsStreamAsync();
        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 ShowFileAsync(string url, string title)
    {
        var absoluteUrl = NavigationManager.ToAbsoluteUri(url);
        using var response = await Http.GetAsync(absoluteUrl);
        string? contentType = null;

        if (response.Content.Headers.TryGetValues("Content-Type", out var values))
        {
            contentType = values.FirstOrDefault();
        }

        var fileStream = await response.Content.ReadAsStreamAsync();
        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 ShowFileAsync(string url, string title)
    {
        var absoluteUrl = NavigationManager.ToAbsoluteUri(url);
        using var response = await Http.GetAsync(absoluteUrl);
        string? contentType = null;

        if (response.Content.Headers.TryGetValues("Content-Type", out var values))
        {
            contentType = values.FirstOrDefault();
        }

        var fileStream = await response.Content.ReadAsStreamAsync();
        var strRef = new DotNetStreamReference(fileStream);

        await JS.InvokeVoidAsync("setSource", "iframe", strRef, contentType, title);
    }
}

I föregående exempel, instruktionen using för variabeln response tar inte bort instansen HttpResponseMessage förrän omfånget för ShowFileAsync slutar. Den öppna dataströmmen underhålls tillräckligt länge för att överföra fildata till setSource funktionen via JavaScript-interop. Allmän vägledning om vikten av att göra sig av med HttpResponseMessage instanser finns i Anropa ett webb-API från en ASP.NET Core Blazor-app.

Ytterligare resurser