aspnetcore: Blazor Image component to display images that are not accessible through HTTP endpoints

Summary

Introduce an Image component to display images coming from dynamic sources like API calls or databases.

Motivation

Currently the most common way to display an image coming from the Database is to base64 encoded it and create an object URL for it. This is problematic since images have a big size and that results in the allocation of large strings, which has a big impact on performance. We want to display images on the browser without allocating large amounts of memory on the .NET side.

Goals

  • Simplify rendering images that come from sources that are not addressable via URLs.
  • Prevent users from allocating large amounts of memory on their applications to display images.

Non-goals

  • Implement responsive images or advanced functionality available in HTML like srcset and Picture

Scenarios

  • As a developer I want to display a profile picture for my users that comes from the database.
<Image Source="_imageSource" />

@code
{
    private ImageSource _imageSource;

    protected override OnInitializedAsync()
    {
        var data = await client.GetProfileAsync();
        _imageSource = new ImageSource("img/jpg", "profile.jpg", data);
    }
}

Risks

  • Customers might not discover the feature:
    • We can limit that with docs, and maybe an “analyzer like” warning.

Interaction with other parts of the framework

Detailed design

This is a rough sketch, but the idea is to create an object on the JS side attached to the image. Use JS interop or other means to transfer the image down to the client (at which points its not longer on the .NET memory) and display it.

Drawbacks

We’ll likely want to cache these things in the browser and will have to handle what happens when the input data changes and so on in the server. We’ll likely also want to avoid performing unnecessary requests on the server to retrieve an image that has already been retrieved, which might complicate things.

Considered alternatives

The current alternatives are:

  • Base64 encode the image and add it to the source element.
    • This allocates large strings which we are trying to avoid.
  • Create a separate endpoint on the server to retrieve and serve the image specifically.
    • This can interfere with the authorization rules in your app since the browser is making the request and might not have access to the credentials you need to call the API.
    • In general it requires much more work and knowledge to get it right.

Open questions

TBD

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 17
  • Comments: 31 (26 by maintainers)

Most upvoted comments

Reopening as after some discussion within the team we believe there will still be value from having a separate components for this.

We could consider this a special case of “support passing byte[] in JS interop calls without base64 serialization”. If we supported that, then it would be trivial to convert a byte[] to a blob URL, which could then be used on an <img src>.

We are going to be using this issue to track https://github.com/dotnet/aspnetcore/issues/30290. In 6.0 we added support for dealing with streams of data in 6.0

As part of this issue, we want to add some component primitives that simplify some common scenarios.

  • We want to have some sort of MediaComponent base component that:
    • Receives a stream as a parameter.
    • Converts the stream into an object URL.
    • Handles the lifetime of the object URL (meaning it revokes it under certain circumstances).
    • Might potentially support caching the content on the client by providing a key, to avoid repeated roundtrips if the content was already sent once.
  • An Image component that uses the object URL in the component to display an image.
  • A Video component that uses the object URL in the component to display a video.
  • Optionally, a FileDownload component counterpart to FileUpload that allows the user to save the file.

All this builds on top of the APIs we already provided in 6.0 to deal with large binary data.

We’ve moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.