9.0 KiB
title | author | description | monikerRange | ms.author | ms.custom | no-loc | ms.date | uid | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Work with images in ASP.NET Core Blazor apps | TanayParikh | Learn how to work with images in ASP.NET Core Blazor apps. | >= aspnetcore-6.0 | taparik | mvc |
|
11/09/2021 | blazor/images |
Work with images in ASP.NET Core Blazor apps
This article describes common scenarios for working with images in Blazor apps.
Dynamically set an image source
The following example demonstrates how to dynamically set an image's source with a C# field.
For the example in this section:
- Obtain three small PNG images from any source.
- Name the images
image1.png
,image2.png
, andimage3.png
. - Place the images in a new folder (
images
) in the app's static assets folder (wwwroot
).
The following directory tree shows the images in the wwwroot/images
folder:
wwwroot
- ...
images
image1.png
image2.png
image3.png
In the following ShowImage
component:
- The image's source (
src
) is dynamically set to the value ofimageSource
in C#. - The
ShowImage
method updates theimageSource
field based on an imageid
argument passed to the method. - Rendered buttons call the
ShowImage
method with an image ID argument for each of the three available images in theimages
folder.
Pages/ShowImage.razor
:
@page "/show-image"
@if (imageSource is not null)
{
<div>
<img src="@imageSource" />
</div>
}
@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";
}
}
The preceding example uses a C# field to hold the image's source data, but you can also use a C# property to hold the data.
[!NOTE] Do not use a loop variable directly in a lambda expression, such as
i
in the precedingfor
loop example. Otherwise, the same variable is used by all lambda expressions, which results in use of the same value in all lambdas. Always capture the variable's value in a local variable and then use the local variable. In the preceding example:
- The loop variable
i
is assigned toimageId
.imageId
is used in the lambda expression.
Streaming examples
The examples in this section stream image source data using JS interop. The following JavaScript setImageUsingStreaming
function accepts the <img>
tag id
and data stream for the image. The function performs the following steps:
- Reads the provided stream into an
ArrayBuffer
. - Creates a
Blob
to wrap theArrayBuffer
. - Creates an object URL to serve as the address for the image to be shown.
- Updates the
<img>
element with the specifiedimageElementId
with the object URL just created.
async function setImageUsingStreaming(imageElementId, imageStream) {
const arrayBuffer = await imageStream.arrayBuffer();
const blob = new Blob([arrayBuffer]);
const url = URL.createObjectURL(blob);
document.getElementById(imageElementId).src = url;
}
To prevent memory leaks, call URL.revokeObjectURL()
to dispose of the object URL (url
in the preceding example) when the component is finished working with an image. In a form, the object URL is typically revoked after the user submits the form for processing, as the object URL is no longer required at that point.
URL.revokeObjectURL(url);
Stream image data to a client
Sometimes, it's necessary to send an image directly to the client instead of hosting the image in a public directory. The following guidance explains how how to accomplish this goal using Blazor's streaming interop features.
Add @inject
directives for the following services to a Razor component (.razor
):
- xref:System.Net.Http.HttpClient?displayProperty=fullName
- xref:Microsoft.JSInterop.IJSRuntime?displayProperty=fullName
[!NOTE] Blazor Server apps use a dedicated
HttpClient
service to make requests. If you haven't already added anHttpClient
to the app's service collection, do so now by addingbuilder.Services.AddHttpClient();
in theProgram.cs
file beforebuilder.Build()
. For more information, see xref:fundamentals/http-requests.
Add an <img>
tag to display the image. Also, add a button to trigger .NET to send the image to the client with a click event handler that calls a SetImageUsingStreamingAsync
method:
<img id="image1" />
<button @onclick="SetImageUsingStreamingAsync">
Set Image Using Image Stream
</button>
Add a C# method that retrieves a xref:System.IO.Stream for the image. At this point, you may dynamically generate an image based on the specific user or retrieve an image from storage. The following example retrieves the dotnet
avatar from GitHub:
@code {
private async Task<Stream> GetImageStreamAsync()
{
return await HttpClient.GetStreamAsync(
"https://avatars.githubusercontent.com/u/9141961");
}
}
Add the following SetImageUsingStreamingAsync
method, which is triggered on the button's selection by the user. SetImageUsingStreamingAsync
performs the following steps:
- Retrieves the xref:System.IO.Stream from
GetImageStreamAsync
. - Wraps the xref:System.IO.Stream in a xref:Microsoft.JSInterop.DotNetStreamReference, which allows streaming the image data to the client.
- Invokes
setImageUsingStreaming
(shown earlier), which is a JavaScript function that accepts the data on the client. ThesetImageUsingStreaming
function is shown later in this article.
@code {
private async Task SetImageUsingStreamingAsync()
{
var imageStream = await GetImageStreamAsync();
var dotnetImageStream = new DotNetStreamReference(imageStream);
await JSRuntime.InvokeVoidAsync("setImageUsingStreaming",
"image1", dotnetImageStream);
}
}
Preview an image provided by the InputFile
component
Use the xref:Microsoft.AspNetCore.Components.Forms.InputFile component to read browser file data into .NET code. In some apps, you may wish to show a preview of a selected image.
Add an <img>
tag for displaying the image preview in a Razor component (.razor
):
<img id="showImageHere" />
Add the following xref:Microsoft.AspNetCore.Components.Forms.InputFile tag to the component:
<InputFile OnChange="ResizeAndDisplayImageUsingStreaming" />
When a file is selected, the ResizeAndDisplayImageUsingStreaming
method is called with xref:Microsoft.AspNetCore.Components.Forms.InputFileChangeEventArgs. Examine the following ResizeAndDisplayImageUsingStreaming
method example:
@code {
private async Task ResizeAndDisplayImageUsingStreaming(InputFileChangeEventArgs e)
{
var imageFile = e.File;
var resizedImage =
await imageFile.RequestImageFileAsync("image/jpg", 250, 250);
var jsImageStream = resizedImage.OpenReadStream();
var dotnetImageStream = new DotNetStreamReference(jsImageStream);
await JSRuntime.InvokeVoidAsync("setImageUsingStreaming",
"showImageHere", dotnetImageStream);
}
}
The preceding ResizeAndDisplayImageUsingStreaming
method performs the following steps:
- Accesses the xref:Microsoft.AspNetCore.Components.Forms.InputFileChangeEventArgs.File which is an xref:Microsoft.AspNetCore.Components.Forms.IBrowserFile.
- Requests an image file from the specified xref:Microsoft.AspNetCore.Components.Forms.IBrowserFile and resizes it to 250 pixels by 250 pixels.
- Opens a xref:System.IO.Stream to read the
resizedImage
. - Wraps the
resizedImage
xref:System.IO.Stream in a xref:Microsoft.JSInterop.DotNetStreamReference, which allows streaming the image data to the client. - Invokes
setImageUsingStreaming
(shown earlier), which is a JavaScript function that accepts the data on the client.
[!NOTE] The image preview technique described in this section involves round-tripping the image data from the client to the server and back. In a future release, this aspect might be optimized to better facilitate image previews. In the meantime, you may elect to create an event listener for the
InputFile
component that captures theFileList
and displays a preview using JavaScript.