Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Images article versioning #28178

Merged
merged 1 commit into from
Jan 24, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 14 additions & 105 deletions aspnetcore/blazor/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ uid: blazor/images

This article describes common scenarios for working with images in Blazor apps.

:::moniker range=">= aspnetcore-7.0"

## Dynamically set an image source

The following example demonstrates how to dynamically set an image's source with a C# field.
Expand All @@ -34,115 +32,18 @@ In the following `ShowImage1` component:

`Pages/ShowImage1.razor`:

:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/images/ShowImage1.razor":::

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]
> Avoid using a loop variable directly in a lambda expression, such as `i` in the preceding `for` loop example. Otherwise, the same variable is used by all lambda expressions, which results in use of the same value in all lambdas. Capture the variable's value in a local variable. In the preceding example:
>
> * The loop variable `i` is assigned to `imageId`.
> * `imageId` is used in the lambda expression.
>
> Alternatively, use a `foreach` loop with <xref:System.Linq.Enumerable.Range%2A?displayProperty=nameWithType>, which doesn't suffer from the preceding problem:
>
> ```razor
> @foreach (var imageId in Enumerable.Range(1,3))
> {
> <button @onclick="() => ShowImage(imageId)">
> Image @imageId
> </button>
> }
> ```
>
> For more information, see <xref:blazor/components/event-handling#lambda-expressions>.

## Stream image data

An image can be directly sent to the client using Blazor's streaming interop features instead of hosting the image at a public URL.

The example in this section streams image source data using [JavaScript (JS) interop](xref:blazor/js-interop/index). The following `setImage` JS 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`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).
* Creates a [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob) to wrap the `ArrayBuffer`.
* Creates an object URL to serve as the address for the image to be shown.
* Updates the `<img>` element with the specified `imageElementId` with the object URL just created.
* To prevent memory leaks, the function calls [`revokeObjectURL`](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL) to dispose of the object URL when the component is finished working with an image.

```html
<script>
window.setImage = async (imageElementId, imageStream) => {
const arrayBuffer = await imageStream.arrayBuffer();
const blob = new Blob([arrayBuffer]);
const url = URL.createObjectURL(blob);
const image = document.getElementById(imageElementId);
image.onload = () => {
URL.revokeObjectURL(url);
}
image.src = url;
}
</script>
```

[!INCLUDE[](~/blazor/includes/js-location.md)]

The following `ShowImage2` component:

* Injects services for an <xref:System.Net.Http.HttpClient?displayProperty=fullName> and <xref:Microsoft.JSInterop.IJSRuntime?displayProperty=fullName>.
* Includes an `<img>` tag to display an image.
* Has a `GetImageStreamAsync` C# method to retrieve a <xref:System.IO.Stream> for an image. A production app may dynamically generate an image based on the specific user or retrieve an image from storage. The following example retrieves the .NET avatar for the `dotnet` GitHub repository.
* Has a `SetImageAsync` method that's triggered on the button's selection by the user. `SetImageAsync` 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 the `setImage` JavaScript function, which accepts the data on the client.

> [!NOTE]
> Blazor Server apps use a dedicated <xref:System.Net.Http.HttpClient> service to make requests, so no action is required by the developer in Blazor Server apps to register an <xref:System.Net.Http.HttpClient> service. Blazor WebAssembly apps have a default <xref:System.Net.Http.HttpClient> service registration when the app is created from a Blazor WebAssembly project template. If an <xref:System.Net.Http.HttpClient> service registration isn't present in `Program.cs` of a Blazor WebAssembly app, provide one by adding `builder.Services.AddHttpClient();`. For more information, see <xref:fundamentals/http-requests>.

`Pages/ShowImage2.razor`:

:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/images/ShowImage2.razor":::

## Additional resources

<!--

* <xref:blazor/forms-and-input-components#preview-an-image-provided-by-the-inputfile-component>

-->
:::moniker range=">= aspnetcore-7.0"

* <xref:blazor/file-uploads>
* <xref:blazor/file-downloads>
* <xref:blazor/js-interop/call-dotnet-from-javascript#stream-from-javascript-to-net>
* <xref:blazor/js-interop/call-javascript-from-dotnet#stream-from-net-to-javascript>
* [Blazor samples GitHub repository (`dotnet/blazor-samples`)](https://github.com/dotnet/blazor-samples)
:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/images/ShowImage1.razor":::

:::moniker-end

:::moniker range="< aspnetcore-7.0"

## 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 images from any source or right-click each of the following images to save them locally. Name the images `image1.png`, `image2.png`, and `image3.png`.

![Computer icon](~/blazor/images/_static/image1.png) &nbsp;&nbsp; ![Smiley icon](~/blazor/images/_static/image2.png) &nbsp;&nbsp; ![Earth icon](~/blazor/images/_static/image3.png)

* Place the images in a new folder named `images` in the app's web root (`wwwroot`). The use of the `images` folder is only for demonstration purposes. You can organize images in any folder layout that you prefer, including serving the images directly from the `wwwroot` folder.

In the following `ShowImage1` component:

* The image's source (`src`) is dynamically set to the value of `imageSource` in C#.
* The `ShowImage` method updates the `imageSource` field based on an image `id` argument passed to the method.
* Rendered buttons call the `ShowImage` method with an image argument for each of the three available images in the `images` folder. The file name is composed using the argument passed to the method and matches one of the three images in the `images` folder.

`Pages/ShowImage1.razor`:

:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/images/ShowImage1.razor":::

:::moniker-end

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]
Expand Down Expand Up @@ -208,8 +109,18 @@ The following `ShowImage2` component:

`Pages/ShowImage2.razor`:

:::moniker range=">= aspnetcore-7.0"

:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/images/ShowImage2.razor":::

:::moniker-end

:::moniker range="< aspnetcore-7.0"

:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/images/ShowImage2.razor":::

:::moniker-end

## Additional resources

<!--
Expand All @@ -223,5 +134,3 @@ The following `ShowImage2` component:
* <xref:blazor/js-interop/call-dotnet-from-javascript#stream-from-javascript-to-net>
* <xref:blazor/js-interop/call-javascript-from-dotnet#stream-from-net-to-javascript>
* [Blazor samples GitHub repository (`dotnet/blazor-samples`)](https://github.com/dotnet/blazor-samples)

:::moniker-end