'Show an image stream to client in blazor server without javascript?

Right now i have the following lines of code:

private async Task SetImageUsingStreamingAsync()
{
    var imageStream = await GetImageStreamAsync();
    var dotnetImageStream = new DotNetStreamReference(imageStream);
    await JSRuntime.InvokeVoidAsync("setImageUsingStreaming", 
        "image1", dotnetImageStream);
}

Above snippet gets a Stream, and repackages that stream into DotNetStreamReferance, and then passes that DotNetStreamReferance to a JS function:

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;
} 

which populates an html element by ID. This is all fine, and works, but if i want to have a loadingscreen while i get the streams from the DB things get messy:

if(isloading)
{
  show loadingscreen
}
else
{
   foreach(string in listofstrings)
   {
     <img id="somename"></img>
   }
}

the img element does not "show up", and causes an error in the js snippet if the bool isloading is not changed to false BEFORE populating the images on the site. Which kind of defeats the purpose with a loadingscreen.

Is there a smarter way of doing this? Preferably without using javascript, since i dont really know that language and cannot modify it to my needs.

The above code is a direct reference from .net documentation on blazor(not the loading part, but the stream to image part): https://docs.microsoft.com/en-us/aspnet/core/blazor/images?view=aspnetcore-6.0



Solution 1:[1]

I figured it based on Yogi's answer in the comment section of my post:

there is absolutely no need to use JS here, i dont know why the blazor docs prefer it that way.

a simple sample on how i did:

private async Task PopulateImageFromStream(Stream stream)
    {
            MemoryStream ms = new MemoryStream();
            stream.CopyTo(ms);
            byte[] byteArray = ms.ToArray();
            var b64String = Convert.ToBase64String(byteArray);
            string imageURL = "data:image/png;base64," + b64String;
        }
    }

add the imageURL to an array, or simply declare it globaly to get it in HTML:

<img src="@imageURL">

Solution 2:[2]

if (isloading) 
{
  // show loadingscreen
} 
else 
{
    // Populate a list with image elements...
    List imageElements = new List();
    foreach(string in listofstrings) 
    {
        Element image = new Element("img");
        image.Id = "somename";
        imageElements.Add(image);
    }

    // ...and append the list to the DOM using RenderElementsAsync
    // to ensure that it is rendered only when the list is fully
    // populated.
    await JSRuntime.InvokeAsync("setImageUsingStreaming", imageElements, dotnetImageStream);
}

The idea is to populate an in-memory list of elements, and then append the list to the DOM in one go, by rendering it asynchronously using RenderElementsAsync. Note: In your original code, you should invoke the JavaScript function setImageUsingStreaming() asynchronously. That is, you should use InvokeAsync instead of InvokeVoidAsync. Let me know if this helps...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Cryptojanne
Solution 2 Almost