views:

2081

answers:

3

I'm calling a webservice that is returning an unknown quantity of images in the form of an a collection of byte arrays. (I can't change this)

I need to display each image on a single aspx webpage.

I'm currently using the Microsoft.Web.GeneratedImage control; http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=16449 to display the images.

The issue i have is that since the control calls a seperate code file to load the image content, i am using session state to store the bytearray, which i'm not overly happy about.

Here's some code from my test project;

     Private Sub btnGetChart_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnGetChart.Click
    Dim reportHub As New HubWrapper

    Dim repCharts() As ReportHub.Chart = reportHub.ReportHubChart(Me.ddlReports.SelectedValue, ViewState("params"))

    For Each chart As ReportHub.Chart In repCharts
      Dim sessionKey As String = "img" & System.Guid.NewGuid().ToString

      Dim imgParam As New Microsoft.Web.ImageParameter()
      imgParam.Name = "sessionVar"
      imgParam.Value = sessionKey

      Session(sessionKey) = chart.ChartData

      Dim img As New Microsoft.Web.GeneratedImage
      img.ImageHandlerUrl = "~/chartImageHandler.ashx"
      img.Parameters.Add(imgParam)

      phChart.Controls.Add(img)
    Next
  End Sub


<%@ WebHandler Language="VB" Class="chartImageHandler" %>

Imports System
Imports System.Collections.Specialized
Imports System.Drawing
Imports System.Web
Imports Microsoft.Web

Public Class chartImageHandler
  Inherits ImageHandler

  Implements IRequiresSessionState

  Public Sub New()
    MyBase.New()
    'Set caching settings and add image transformations here
    'EnableServerCache = True

  End Sub

  Public Overrides Function GenerateImage(ByVal parameters As NameValueCollection) As ImageInfo
    Dim byteArry As Byte() = CType(HttpContext.Current.Session(parameters("sessionVar")), Byte())

    HttpContext.Current.Session.Remove(parameters("sessionVar"))

    Return New ImageInfo(byteArry)

  End Function
End Class

What's the most elegant way of achieving this?

Any input welcome!!!

EDIT: Additional info;

  • The images from the webservice are coming from SQL Reporting Services.
  • The images would generally be changing all the time (no real caching requirement).
  • Images would be user specific.
  • The webservice is only called once per page.
  • I'm actually disposing of the image from session state after the generated image uses it, as the image won't be needed to be viewed again for a while.
+2  A: 

I suppose that you want to call your web service only once per page request. In fact, it would be good to somehow cache the byte array, so that the web service isn't called again in the case the user momentarily moves away from the page and then comes back. In that case saving the byte array in the session is inevitable. If you didn't use GeneratedImage control, you would still need to save the byte array somewhere.

I understand your worries regarding big sessions. Based on the details of your applications, there are some things you could do to avoid it. Are all images refer to a single user, or are some images shared among users? Do the images change often? If all the images belong to a single user and change frequently, then saving them in the session is the only solution. If however some users share images or the images aren't expected to frequently change, then you could create a proxy between the web service and the web application. The proxy will save the images, either in memory or in a database (or perhaps in the file system) and will make them available as resources, through a URL mapping. You would need to define this mapping, based on the internals of your applications. It could be something like this:

http://imageproxy/username/photo123123

You also need to create a URL to return the number of available images:

http://imageproxy/username/imagecount

There would be no need to use the GeneratedImage component. You could easily build the html source of the page using standard img tags.

kgiannakakis
The images from the webservice are coming from SQL Reporting Services. The images would generally be changing all the time. Images would be user specific.The webservice is only called once per page. Caching might be a good idea, i might just use web.caching for a very short time.I'm actually disposing of the image from session state after the generated image uses it, as the image hopefully won't be needed to be viewed again for a while.
GordonB
+1  A: 

You can embed the image data directly into the page source using the data: URI scheme. Here's the Wikipedia description. That doesn't work with IE versions prior to 8 though, which may make it unacceptable for your situation.

Skirwan
Oh, the IE < 8 issue didn't bother me.
GordonB
Works nicely.... the only problem IE has is the size limit on data uri's. Convert.ToBase64String(imageToDisplay).Length < 32768 etc etc
GordonB
A: 

In asp.net you can write and image directly with the response object and the major browsers will be able to display it. But you cannot pass an array of bytes, you need to pass a memory stream.

get your System.Web.HttpContext

Dim ms as New Io.MemoryStream(yourarray) httpcontext.Response.OutputStream.Write(ms.ToArray,0,ms.Length)

you put that in an display.aspx page and if "yourarray" is an array of bytes that represents an image the browser will display it.

You can use then an image control on any page (even plain html) and set the image source to "display.aspx" and your image will show up.

Now, since you have multiple images, you might need to create a control and create multiple instance of it, one for each image passing the corresponding byte array.

jvanderh
Have used this method for displaying images from a database previously... I initially wanted to find a "better" way of displaying the images, hence looking at the microsoft.generatedimage control.... Which also has its drawbacks.
GordonB