Skip to content

Document usage of InputFile when displaying images #36991

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

Closed
nelsonmarro opened this issue Sep 26, 2021 · 4 comments · Fixed by dotnet/AspNetCore.Docs#23720
Closed

Document usage of InputFile when displaying images #36991

nelsonmarro opened this issue Sep 26, 2021 · 4 comments · Fixed by dotnet/AspNetCore.Docs#23720
Assignees
Labels
area-blazor Includes: Blazor, Razor Components Docs This issue tracks updating documentation Done This issue has been fixed

Comments

@nelsonmarro
Copy link

nelsonmarro commented Sep 26, 2021

Bug Description.
I have an <InputFile class="form-control" OnChange="@LoadAlbumCover" /> and when I try to load an Image the method LoadAlbumCover get call normally, but there is something wrong happening, the following errors occurs.
1 - The application freeze (Navigation to other pages doesn't work until I restart the app or refresh the browser)
2 - The image is presented badly like the bytes from the image where not load correctly.
3 - If you wait a wile without restarting the app or refresh the Browser (wait like 3 minutes or more)
the following exception appears:
-- Expection.
Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost[111]
Unhandled exception in circuit '-xJw5fUSzdXA7MRXfA5F1DmUZ-qlWzv4-dgHr-5oVFo'.
System.TimeoutException: Did not receive any data in the allotted time.

This is the code to reproduce the issue. Create a new Blazor Server App in Visual Studio 2022 Preview 4.1 targeting .NET 6 RC1 and put the following code in the Index.razor page:

@page "/"

<PageTitle>Index</PageTitle>

<InputFile class="form-control" OnChange=LoadImageAsync />
<img class="img-fluid" src="data:image/jpg;base64,@_imageBase64"/>

@code {
    private string _imageBase64 = "";
    private async Task LoadImageAsync(InputFileChangeEventArgs e)
    {
        var resizedImage = await e.File.RequestImageFileAsync("image/jpg", 500, 500);
        var imageBytes = new byte[resizedImage.Size];
        await resizedImage.OpenReadStream().ReadAsync(imageBytes);
        _imageBase64 = Convert.ToBase64String(imageBytes);
    }
}

Select any image an load it. See the if the problems mentioned before occurs.

I'll also leave a link to a repo with the minimum code and requirements to reproduce the issue:(https://github.com/Nelson9991/BlazorAppNET6InputFileIssue.git)

Technical requirements.

IDE. Visual Studio 2022 Preview 4.1

  • ASP.NET Core version: .NET 6.0.100-rc.1.21458.32

.NET SDK (reflecting any global.json):
Version: 6.0.100-rc.1.21458.32
Commit: d7c22323c4

Runtime Environment:
OS Name: Windows
OS Version: 10.0.22000
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\6.0.100-rc.1.21458.32\

Host (useful for support):
Version: 6.0.0-rc.1.21451.13
Commit: d7619cd4b1

.NET SDKs installed:
5.0.401 [C:\Program Files\dotnet\sdk]
6.0.100-rc.1.21458.32 [C:\Program Files\dotnet\sdk]
6.0.100-rc.1.21463.6 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.0-rc.1.21452.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.0-rc.1.21451.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.0-rc.1.21451.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

@mkArtakMSFT mkArtakMSFT added the area-blazor Includes: Blazor, Razor Components label Sep 26, 2021
@mkArtakMSFT mkArtakMSFT added the Docs This issue tracks updating documentation label Sep 27, 2021
@mkArtakMSFT mkArtakMSFT added this to the 6.0.0 milestone Sep 27, 2021
@nelsonmarro
Copy link
Author

Hi, here to report that the issue is still happening in .NET 6 RC2

@TanayParikh
Copy link
Contributor

Hi, here to report that the issue is still happening in .NET 6 RC2

Thanks for your comment. We're using this issue to track docs/samples work in line with the 6.0 public release.

@mkArtakMSFT mkArtakMSFT modified the milestones: 6.0.0, 6.0-docs-infra Oct 19, 2021
@ghost ghost added the Working label Oct 27, 2021
@TanayParikh
Copy link
Contributor

TanayParikh commented Oct 28, 2021

There's two ways to do this, the proper documented way using streaming, as well as the somewhat "hacky" way that avoids round-tripping the image to/from the server (NOT recommended).

Please see https://docs.microsoft.com/aspnet/core/blazor/images?view=aspnetcore-6.0 for more details.

Streaming

@inject IJSRuntime JSRuntime

<InputFile OnChange="ResizeAndDisplayImageUsingStreaming" />
<img id="showImageHere" />

@code {
    private async Task ResizeAndDisplayImageUsingStreaming(InputFileChangeEventArgs e)
    {
        var resizedImage = await e.File.RequestImageFileAsync("image/jpg", 250, 250);
        var jsImageStream = resizedImage.OpenReadStream();
        var dotnetImageStream = new DotNetStreamReference(jsImageStream);
        await JSRuntime.InvokeVoidAsync("setImageUsingStreaming", "showImageHere", dotnetImageStream);
    }
}
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;

    // Note: once you're done working with the image,
    // you should dispose of the object to prevent memory leaks via:
    // URL.revokeObjectURL(url);
}

Inspecting the InputFile to extract the original blob

We do NOT recommend using the following approach as it uses undocumented internal Blazor APIs. This implementation may stop working without notice.

@inject IJSRuntime JSRuntime

<InputFile @ref="InputFileElement" OnChange="ResizeAndDisplayImageUsingInputElement" />
<img id="showImageHere" />

@code {
    private InputFile? InputFileElement { get; set; }

    private async Task ResizeAndDisplayImageUsingInputElement(InputFileChangeEventArgs e)
    {
        var resizedImage = await e.File.RequestImageFileAsync("image/jpg", 250, 250);
        await JSRuntime.InvokeVoidAsync("setImageUsingInputElement", InputFileElement, "showImageHere", resizedImage);
    }
}
function setImageUsingInputElement(inputElement, imageElementId, image) {
    const blob = getBlobFromInputElement();

    const url = URL.createObjectURL(blob);

    document.getElementById(imageElementId).src = url;

    // Note: once you're done working with the image, 
    // you should dispose of the object to prevent memory leaks via:
    // URL.revokeObjectURL(url);

    function getBlobFromInputElement() {
        if (!(inputElement?.element?._blazorFilesById instanceof Object)) {
            return undefined;
        }
        return inputElement.element._blazorFilesById[image.id]?.blob;
    }
}

The getBlobFromInputElement is really the most concerning part as we're using an internal implementation detail to extract the blob. We have to do this as the BrowserFile doesn't preserve the blob when it goes to/from .NET to JS. This is something we'd likely want to remediate for .NET 7 via #30290.

@TanayParikh TanayParikh changed the title Loading an image with InputFile control doesn't work correctly and freeze the app. Blazor Server App targeting .NET 6 RC1 Document usage of InputFile when displaying images Oct 28, 2021
@ghost ghost added Done This issue has been fixed and removed Working labels Nov 4, 2021
@nelsonmarro
Copy link
Author

Hi, thanks for the clarification on this issue. Awesome work! :)

@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components Docs This issue tracks updating documentation Done This issue has been fixed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants