skip to Main Content

I am making an API call that should return a list of PNGs . I’m storing the PNG in blob storage and I’m able to successfully grab them. In the past when I’ve only had to return one image, I’d convert the blob to a memory stream and just handle the memory stream on the client side. That does not seem to work for multiple files though.

[HttpGet("getThumbnails/{seriesId}")]
public async Task<ActionResult<List<MemoryStream>>> GetThumbnails(string seriesId)
{          
    var pngs = await _service.LoadPNGsMs(seriesId);

    Response.ContentType = "image/png ";
    return pngs;
}

public async Task<List<MemoryStream>> LoadPNGsMs(string seriesID)
{
    var returnList = new List<MemoryStream>();
    var blobls = await _azureBlobStorageService.GetBlockBlob(seriesID);

    foreach (var blob in blobls)
    {
            var stream = new MemoryStream();
            await blob.DownloadToStreamAsync(stream);
            stream.Position = 0;
            returnList.Add(stream);
    }
    return returnList;
}

public async Task<List<CloudBlockBlob>> GetBlockBlob(string seriesID)
{
    var blobFiles = containerClient.GetBlobs(prefix: seriesID);
    var blobFilePaths = blobFiles.Select(x => x.Name).ToList();
    List<CloudBlockBlob> cloudBlockBlobs = new List<CloudBlockBlob>();

    foreach (var blob in blobFilePaths)
    {
        CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(blob);
        bool isExists = await blockBlob.ExistsAsync();
        if (isExists)
            cloudBlockBlobs.Add(blockBlob);
    }
    return cloudBlockBlobs;
}

I am getting a 406 for running this code. Am I doing too much setting the response type to be image/png? Should I just work with the blobs and forget about the memory streams? I’ll keep playing around with this here and post results if I find anything.

2

Answers


  1. Instead of using List<MemoryStream> use a IEnumerable<byte[]> and write each blob to byte arrays. Your client won’t be able to use the memory stream for multiple blobs in the same way you probably wrote it out to the response for a single item. I would also change it to

    public async Task<ActionResult<IEnumerable<byte[]>>> GetThumbnails(string seriesId)

    so you can yield return byte[] and improve the throughput to the client with less memory consumption on the server overall.

    Login or Signup to reply.
  2. Well, you could say use a repeater, and simple then push out the image to the repeater for the number of pictures.

    So if I have a table of pictures, then I want the picture name, and then the byte-stream of each picture.

    So, this markup:

    <asp:Repeater ID="Repeater1" runat="server" OnItemDataBound="Repeater1_ItemDataBound">
        <ItemTemplate>
            <div class="mybox">
                <div style="text-align: center; padding: 2px 10px 12px 10px">
                    <asp:Button ID="cmdMyView" runat="server" Text="View"
                        CssClass="btn-info" Style="float: right"
                        OnClick="cmdMyView_Click"
                        CommandArgument='<%# Eval("ID") %>' />
                    <br />
                    <h3><%# Eval("Fighter") %></h3>
                    <asp:Image ID="Image2" runat="server" Width="180" Height="120" />
                    <h4>Engine</h4>
                    <asp:Label ID="EngineLabel2" runat="server" Text='<%# Eval("Engine") %>' />
                    <h4>Description</h4>
                    <asp:Label ID="DescLabel" runat="server" Text='<%# Eval("Description") %>' />
                </div>
            </div>
        </ItemTemplate>
    </asp:Repeater>
    

    (nothing special).

    but, in above is a plain jane image control.

    So, code to load is this:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadGrid();
    }
    
    void LoadGrid()
    {
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            string strSQL = "SELECT * FROM Fighters";
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                DataTable rstData = new DataTable();
                rstData.Load(cmdSQL.ExecuteReader());
                Repeater1.DataSource = rstData;
                Repeater1.DataBind();
            }
        }
    }
    

    And row item data bound is where we push out the byte array to each image.

    protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if ( (e.Item.ItemType == ListItemType.Item) ||  
            (e.Item.ItemType == ListItemType.AlternatingItem) )
        {
            Image ctlImage = (Image)e.Item.FindControl("Image2");
            DataRowView rData = (DataRowView)e.Item.DataItem;
            byte[] MyBytes = (byte[])rData["MyImage"];
    
            ctlImage.ImageUrl =
                $@"data:image/jpg;base64,{Convert.ToBase64String(MyBytes)}";
        }
    }
    

    And the result is this:

    enter image description here

    So, if you have some type of repeater, listview, grid view, datalist view or repeater?

    Then just push out the byte array to the image control as a base64 string.

    Above is not only simple, but requires no special image handler’s and all that jazz.

    You do however, need the mine type.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search