Mostrar imágenes y documentos en ASP.NET Core Blazor
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulta la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulta la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulta la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulta la versión .NET 8 de este artículo.
En este artículo se describen métodos para mostrar imágenes y documentos en aplicaciones Blazor.
Los ejemplos de este artículo están disponibles para su inspección y uso en las aplicaciones Blazor de ejemplo:
dotnet/blazor-samples
Repositorio de GitHub: ve a la aplicación denominada BlazorSample_BlazorWebApp
(8.0 o posterior), BlazorSample_Server
(7.0 o anterior) o BlazorSample_WebAssembly
.
Establecer dinámicamente un origen de imagen
En el ejemplo siguiente se muestra cómo establecer dinámicamente el origen de una imagen con un campo de C#.
En el ejemplo de esta sección se usan tres archivos de imagen, denominados image1.png
, image2.png
y image3.png
. Las imágenes se colocan en una carpeta denominada images
en la raíz web de la aplicación (wwwroot
). El uso de la carpeta images
es solo con fines de demostración. Puedes organizar los activos estáticos en la disposición de carpetas que prefieras, incluso servir activos directamente desde la carpeta wwwroot
.
En el componente ShowImage1
siguiente:
- El origen de la imagen (
src
) se establece dinámicamente en el valor deimageSource
en C#. - El método
ShowImage
actualiza el campoimageSource
en función de un argumentoid
de imagen pasado al método. - Los botones representados llaman al método
ShowImage
con un argumento de imagen para cada una de las tres imágenes disponibles en la carpetaimages
. El nombre de archivo se compone mediante el argumento pasado al método y coincide con una de las tres imágenes de la carpetaimages
.
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";
}
}
En el ejemplo anterior se usa un campo de C# para contener los datos de origen de la imagen, pero también se puede usar una propiedad de C# para contener los datos.
No uses una variable de bucle directamente en una expresión lambda (como i
en el ejemplo de bucle for
anterior). De lo contrario, todas las expresiones lambda usarán la misma variable, con lo cual se usará el mismo valor en todas las expresiones lambda. Captura el valor de la variable en una variable local. En el ejemplo anterior:
- La variable de bucle
i
se asigna aimageId
. imageId
se usa en la expresión lambda.
Como alternativa, utiliza un bucle foreach
con Enumerable.Range, que no sufre el problema anterior:
@foreach (var imageId in Enumerable.Range(1, 3))
{
<button @onclick="() => ShowImage(imageId)">
Image @imageId
</button>
}
Para obtener más información sobre las expresiones lambda con el control de eventos, consulta control de eventos Blazor de ASP.NET Core.
Transmisión de datos de imagen o documento
Una imagen u otro tipo de documento, como un PDF, se puede enviar directamente al cliente mediante las características de streaming interop de Blazor en lugar de hospedar el archivo en una dirección URL pública.
El ejemplo de esta sección transmite datos de origen mediante la interoperabilidad de JavaScript (JS). La siguiente función setSource
JS:
- Se puede usar para transmitir contenido para los siguientes elementos:
<body>
,<embed>
,<iframe>
,<img>
,<link>
,<object>
,<script>
,<style>
y<track>
. - Acepta un elemento
id
para mostrar el contenido del archivo, un flujo de datos para el documento, el tipo de contenido y un título para el elemento de visualización.
La función :
- Lee la secuencia proporcionada en
ArrayBuffer
. - Crea un
Blob
para encapsularArrayBuffer
y establece el tipo de contenido del blob. - Crea un objeto de dirección URL que sirva de dirección para el documento que se va a mostrar.
- Establece el título del elemento (
title
) a partir del parámetrotitle
y establece el origen del elemento (src
) a partir de la dirección URL del objeto creado. - Para evitar pérdidas de memoria, la función llama a
revokeObjectURL
para eliminar el objeto de dirección URL después de que el elemento cargue el recurso (eventoload
).
<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:
Para obtener una guía general sobre la ubicación de JS y nuestras recomendaciones para aplicaciones de producción, consulta Ubicación de JavaScript en aplicaciones Blazor de ASP.NET Core.
El componente ShowImage2
siguiente:
- Inserta servicios para System.Net.Http.HttpClient y Microsoft.JSInterop.IJSRuntime.
- Incluye una etiqueta
<img>
para mostrar una imagen. - Tiene un método
GetImageStreamAsync
de C# para recuperar un Stream para una imagen. Una aplicación de producción puede generar dinámicamente una imagen basada en el usuario específico o recuperar una imagen del almacenamiento. En el ejemplo siguiente se recupera el avatar de .NET para el repositorio de GitHubdotnet
. - Tienes un método
SetImageAsync
que se desencadena en la selección del botón por parte del usuario.SetImageAsync
realiza las tareas siguientes:- Recupera el elemento Stream de
GetImageStreamAsync
. - Ajusta la clase Stream en un DotNetStreamReference, lo que permite el streaming de los datos de archivo al cliente.
- Invoca la función
setSource
de JavaScript, que acepta los datos en el cliente.
- Recupera el elemento Stream de
Nota:
Las aplicaciones del lado servidor usan un servicio dedicado HttpClient para realizar solicitudes, por lo que el desarrollador de una aplicación del lado Blazor servidor no requiere ninguna acción para registrar un HttpClient servicio. Las aplicaciones HttpClient tienen un registro de servicio predeterminado Blazor cuando la aplicación se crea a partir de una plantilla de proyecto. Si un HttpClient registro de servicio no está presente en el Program
archivo de una aplicación del lado cliente, proporcione uno agregando builder.Services.AddHttpClient();
. Para más información, consulta Realización de solicitudes HTTP con IHttpClientFactory en 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");
}
}
El siguiente componente ShowFile
carga un archivo de texto (files/quote.txt
) o un archivo PDF (files/quote.pdf
) en un elemento <iframe>
(documentación MDN).
Precaución
El uso del elemento <iframe>
en el siguiente ejemplo es seguro y no requiere de un espacio aislado porque el contenido se carga desde la aplicación, que es un origen de confianza.
Al cargar contenido desde un origen o entrada de usuario que no es de confianza, un elemento implementado <iframe>
incorrectamente corre el riesgo de crear vulnerabilidades de seguridad.
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);
}
}
Recursos adicionales
- Cargas de archivos de Blazor en ASP.NET Core
- Cargas de archivos: Carga de la vista previa de imágenes
- Descargas de archivos de Blazor en ASP.NET Core
- Llamada a métodos de .NET desde funciones de JavaScript en ASP.NET Core Blazor
- Llamada a funciones de JavaScript con métodos de .NET en de ASP.NET CoreBlazor
- Repositorio de GitHub con ejemplos de Blazor (
dotnet/blazor-samples
) (cómo descargar)