Display Images From Database In Silverlight 2

Posted by: Suprotim Agarwal , on 10/25/2008, in Category Silverlight 2, 3, 4 and 5
Views: 73155
Abstract: In this article, we will see how to display images from database in Silverlight using an ASP.NET HttpHandler. The article will first demonstrate how to do a simple image fetch using an HttpHandler. We will then modify our approach to use WebClient to download images on demand. We will also see how to cancel the image fetch operation midway.
Display Images From Database In Silverlight 2
 
In this article, we will see how to display images from database in Silverlight using an ASP.NET HttpHandler. The article will first demonstrate how to do a simple image fetch using an HttpHandler. We will then modify our approach to use WebClient to download images on demand. We will also see how to cancel the image fetch operation midway.
Note: I hope you have upgraded your development environment from Silverlight Beta 2 to the final release of Silverlight 2. If you have not yet done so, I would suggest you to read my post: Silverlight 2 Beta 2 TO Silverlight 2 Final Release - A Complete Step By Step Guide for Upgrading your Development Environment
We will make use of the Employees table in the Northwind database.
Step 1: Open Visual Studio 2008 > File > New Project > Select the language (C# or VB) > Select ‘Silverlight’ in the Project Types > from the templates, select ‘Silverlight Application’. Type a name ‘AccessImagesInDatabase’ and location for the project and click ok.
Note: If you are unable to view the templates, you do not have Microsoft Silverlight Tools for Visual Studio 2008. Check out this link to see how to obtain it.
Step 2: You will observe that a default page called ‘Page.xaml’ gets created. Remove the <Grid> and replace it with <Canvas> and set its background to Gray. Now add a few controls like the Image, TextBlock, TextBox and Buttons inside the Canvas. After setting a few layout properties, the markup will look similar to the following:
<UserControl x:Class="AccessImagesInDatabase.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/
presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Canvas x:Name="LayoutRoot" Background="Gray">
        <Image x:Name="img1" Width="300" Height="230" Visibility="Visible" HorizontalAlignment="Center"></Image>               
        <TextBlock x:Name="lblEmployee" Text="EmployeeID" Canvas.Top="244" Canvas.Left="10"/>
        <TextBox x:Name="txtEmpID" Canvas.Top="240" Canvas.Left="110" Width="40" Text="1"/>
        <Button x:Name="btnImage" Canvas.Top="270" Canvas.Left="110" Content="Fetch" Click="btnImage_Click"></Button>
    </Canvas>
</UserControl>
 
The ‘btnImage’ is for fetching the image. ‘txtEmpId’ is the textbox where we will enter the EmployeeId whose image is to be retrieved from the database.
Step 3: Since we are retrieving the images from the database, we would need a connection string. Add the following connection string to your web.config
      <connectionStrings>
            <add name="NorthwindConnectionString" connectionString="Data Source=(local);Initial Catalog=Northwind;Integrated Security=True"
             providerName="System.Data.SqlClient" />
      </connectionStrings>
Step 4: We will be using an HttpHandler to pull images from the database. Handlers provide a lot of flexibility while accessing server-side resources. To create an Http handler, right click project AccessImagesInDatabase.Web > Add New Item > Generic Handler > DisplayImage.ashx. Add the following code to the handler.
C#
using System;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web;
using System.Web.Services;
 
 
namespace AccessImagesInDatabase.Web
{
///<summary>
/// Summary description for $codebehindclassname$
///</summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class DisplayImage : IHttpHandler
{
    byte[] empPic = null;
    long seq = 0;
 
    public void ProcessRequest(HttpContext context)
    {
        Int32 empno;
 
        if (context.Request.QueryString["id"] != null)
            empno = Convert.ToInt32(context.Request.QueryString["id"]);
        else
            throw new ArgumentException("No parameter specified");
 
        // Convert Byte[] to Bitmap
        Bitmap newBmp = ConvertToBitmap(ShowEmpImage(empno));
        if (newBmp != null)
        {
            newBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
            newBmp.Dispose();
        }
    }
 
    // Convert byte array to Bitmap (byte[] to Bitmap)
    protected Bitmap ConvertToBitmap(byte[] bmp)
    {
        if (bmp != null)
        {
            TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
            Bitmap b = (Bitmap)tc.ConvertFrom(bmp);               
            return b;
        }
        return null;
    }
 
    public byte[] ShowEmpImage(int empno)
    {
        string conn = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
        SqlConnection connection = new SqlConnection(conn);
        string sql = "SELECT photo FROM Employees WHERE EmployeeID = @ID";
        SqlCommand cmd = new SqlCommand(sql, connection);
        cmd.CommandType = CommandType.Text;
        cmd.Parameters.AddWithValue("@ID", empno);
        connection.Open();
        SqlDataReader dr = cmd.ExecuteReader();
        if (dr.Read())
        {
            seq = dr.GetBytes(0, 0, null, 0, int.MaxValue) - 1;
            empPic = new byte[seq + 1];
            dr.GetBytes(0, 0, empPic, 0, Convert.ToInt32(seq));
            connection.Close();
        }
 
        return empPic;
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}
 
}
 
VB.NET
Imports System
Imports System.ComponentModel
Imports System.Configuration
Imports System.Data
Imports System.Data.SqlClient
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Web
Imports System.Web.Services
 
 
Namespace AccessImagesInDatabase.Web
''' <summary>
''' Summary description for $codebehindclassname$
''' </summary>
<WebService(Namespace := "http://tempuri.org/"), WebServiceBinding(ConformsTo := WsiProfiles.BasicProfile1_1)> _
Public Class DisplayImage
      Implements IHttpHandler
      Private empPic() As Byte = Nothing
      Private seq As Long = 0
 
      Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
            Dim empno As Int32
 
            If context.Request.QueryString("id") IsNot Nothing Then
                  empno = Convert.ToInt32(context.Request.QueryString("id"))
            Else
                  Throw New ArgumentException("No parameter specified")
            End If
 
            ' Convert Byte[] to Bitmap
            Dim newBmp As Bitmap = ConvertToBitmap(ShowEmpImage(empno))
            If newBmp IsNot Nothing Then
                  newBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
                  newBmp.Dispose()
            End If
      End Sub
 
      ' Convert byte array to Bitmap (byte[] to Bitmap)
      Protected Function ConvertToBitmap(ByVal bmp() As Byte) As Bitmap
            If bmp IsNot Nothing Then
                  Dim tc As TypeConverter = TypeDescriptor.GetConverter(GetType(Bitmap))
                  Dim b As Bitmap = CType(tc.ConvertFrom(bmp), Bitmap)
                  Return b
            End If
            Return Nothing
      End Function
 
      Public Function ShowEmpImage(ByVal empno As Integer) As Byte()
            Dim conn As String = ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString
            Dim connection As New SqlConnection(conn)
            Dim sql As String = "SELECT photo FROM Employees WHERE EmployeeID = @ID"
            Dim cmd As New SqlCommand(sql, connection)
            cmd.CommandType = CommandType.Text
            cmd.Parameters.AddWithValue("@ID", empno)
            connection.Open()
            Dim dr As SqlDataReader = cmd.ExecuteReader()
            If dr.Read() Then
                  seq = dr.GetBytes(0, 0, Nothing, 0, Integer.MaxValue) - 1
                  empPic = New Byte(seq){}
                  dr.GetBytes(0, 0, empPic, 0, Convert.ToInt32(seq))
                  connection.Close()
            End If
 
            Return empPic
      End Function
 
      Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
            Get
                  Return False
            End Get
      End Property
End Class
 
End Namespace
 
The steps for retrieving images from database, using the handler are as follows:
1.    The EmployeeID whose image is to be retrieved, is passed to the handler via query string. We use the Request.QueryString[“id”] to retrieve the EmployeeID(emp_id) from the handler url. The ID is then passed to the ‘ShowEmpImage()’ method where the image is fetched from the database using SqlDataReader and returned in a byte[] object.
2.    We pass this byte[] to the ConvertToBitmap() function where we use the TypeConverter class to convert a byte array to bitmap.
3.    The last step is to save the image to the page's output stream and indicate the image format as shown here convBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
Note: Silverlight does not support .bmp images. For this reason, we set the ImageFormat to Jpeg while saving the image to the OutputStream.
Step 5: The next step is to call this handler from our Silverlight application.
C#
using System.Windows.Media.Imaging;
public partial class Page : UserControl
{
    public Page()
    {
        InitializeComponent();
    }
 
    private void btnImage_Click(object sender, RoutedEventArgs e)
    {
        string imgUri = "http://localhost:57711/DisplayImage.ashx?id=" + Convert.ToInt32(txtEmpID.Text).ToString();
        img1.Source = new BitmapImage(new Uri(imgUri, UriKind.Absolute));         
    }
 
 
}
VB.NET
Imports System.Windows.Media.Imaging
Partial Public Class Page
      Inherits UserControl
      Public Sub New()
            InitializeComponent()
      End Sub
 
      Private Sub btnImage_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Dim imgUri As String = "http://localhost:57711/DisplayImage.ashx?id=" & Convert.ToInt32(txtEmpID.Text).ToString()
            img1.Source = New BitmapImage(New Uri(imgUri, UriKind.Absolute))
      End Sub
 
End Class
Note: In this example, I have configured the port to be static (57711) for this application to avoid Cross Domain issues. To do so, Right Click project AccessImagesInDatabase.Web > Properties > Web tab > Check the radio button ‘Specific Port’ and assign it a value of 57711 as shown in the image below. You can choose a different port too. Just remember to change it while accessing the image url.
Fixed Port
If you plan to deploy the image service on a different server or port, use the ClientAccessPoilcy.xml at the root of the domain.
That was a simple fetch operation. Let us now see how to fetch images on demand using the WebClient class.
 
Fetching Images on Demand using the WebClient class
 
The WebClient class provides functionality for initiating the download request, monitoring the progress of the download, and then finally retrieving the content requested. You can also cancel a download in progress. Let us modify our sample to see how we can use the WebClient class to download images
You need to import the System.Net and System.Windows.Media.Imaging namespaces. Also we will be using event-handlers while using the WebClient, since all requests are asynchronous.
The event-handler we will use is the OpenReadCompleted event handler which occurs when an asynchronous resource-read operation is completed. To request the image as a stream, we will use the OpenReadAsync method of the WebClient. Let us see some code:
First, add a button and a label control to the Page.Xaml. The ‘btnCancel’ is for cancelling the image fetch operation. The ‘txtProgress’ is for displaying status messages at the time of fetching the image and cancelling the operation.
<TextBlock x:Name="txtProgress" Canvas.Top ="240" Canvas.Left="160" Text="" FontSize="10" />
<Button x:Name="btnCancel" Canvas.Top="270" Canvas.Left="150" Content="Cancel" Click="btnCancel_Click"></Button>
 
C#
public partial class Page : UserControl
{
WebClient wc = null;
 
public Page()
{
    InitializeComponent();
}
 
private void btnImage_Click(object sender, RoutedEventArgs e)
{
    string imgUri = "http://localhost:57711/DisplayImage.ashx?id=" + Convert.ToInt32(txtEmpID.Text).ToString();
    txtProgress.Text = String.Empty;
 
    wc = new WebClient();
    wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
    wc.OpenReadAsync(new Uri(imgUri, UriKind.Absolute));
    txtProgress.Text = "Fetching Image...";    
 
    //img1.Source = new BitmapImage(new Uri(s, UriKind.Absolute));        
}
 
void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if (e.Error == null)
    {
        try
        {
            BitmapImage image = new BitmapImage();
            image.SetSource(e.Result);
            img1.Source = image;
            txtProgress.Text = String.Empty;
        }
        catch(Exception ex)
        {
            txtProgress.Text = "Error while fetching image";
        }
    }
}
 
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
    if (wc.IsBusy)
    {
        wc.CancelAsync();
        txtProgress.Text = "Image fetch cancelled! ";
    }
}
 
}
VB.NET
Partial Public Class Page
      Inherits UserControl
Private wc As WebClient = Nothing
 
Public Sub New()
      InitializeComponent()
End Sub
 
Private Sub btnImage_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
      Dim imgUri As String = "http://localhost:57711/DisplayImage.ashx?id=" & Convert.ToInt32(txtEmpID.Text).ToString()
      txtProgress.Text = String.Empty
 
      wc = New WebClient()
      AddHandler wc.OpenReadCompleted, AddressOf wc_OpenReadCompleted
      wc.OpenReadAsync(New Uri(imgUri, UriKind.Absolute))
      txtProgress.Text = "Fetching Image..."
 
      'img1.Source = new BitmapImage(new Uri(s, UriKind.Absolute));        
End Sub
 
Private Sub wc_OpenReadCompleted(ByVal sender As Object, ByVal e As OpenReadCompletedEventArgs)
      If e.Error Is Nothing Then
            Try
                  Dim image As New BitmapImage()
                  image.SetSource(e.Result)
                  img1.Source = image
                  txtProgress.Text = String.Empty
            Catch ex As Exception
                  txtProgress.Text = "Error while fetching image"
            End Try
      End If
End Sub
 
Private Sub btnCancel_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
      If wc.IsBusy Then
            wc.CancelAsync()
            txtProgress.Text = "Image fetch cancelled! "
      End If
End Sub
 
End Class
In the btnImage_Click event, we first initialize the WebClient object through a constructor, add the OpenReadCompleted event handler and then initiate the request to read the image as a stream using the OpenReadAsync. The OpenReadAsyc accepts a URI which is the path to an ImageHandler in our case. We pass the EmployeeID as a query string parameter.
The OpenReadCompleted contains a parameter of the type OpenReadCompletedEventArgs. This parameter has a property called 'Result' which is of type Stream. So we create an instance of the BitmapStream and set this stream directly to populate the graphics source file for the BitmapImage using 'SetSource'. Finally, we set the img1.Source property to this instance of the BitmapImage.
We can also cancel the download operation midway using the CancelAsync() on the WebClient object. The 'IsBusy' helps us determine if a WebRequest is in progress.
Note 1: One event that we have not covered in this article is the DownloadProgressChanged which can be used to track the progress of the operation. We will cover this event in a seperate article.
Note 2: If the images are stored in the local database of your machine, they will be displayed almost instantly. So if you want to test out the Cancel operation, then while fetching the image, add System.Threading.Thread.Sleep(3000) to delay the image fetch operation by 3 seconds
Well that's pretty much it. When you run the application, you will see a screen similar to the following:
Silverlight WebClient
I hope you liked the article and I thank you for viewing it.
If you liked the article,  Subscribe to my RSS Feed.

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of DotNetCurry, DNC Magazine for Developers, SQLServerCurry and DevCurry. He has also authored a couple of books 51 Recipes using jQuery with ASP.NET Controls and The Absolutely Awesome jQuery CookBook.

Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.

Get in touch with him on Twitter @suprotimagarwal or at LinkedIn



Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Jemm on Saturday, October 25, 2008 12:29 PM
superb!
Comment posted by Mero on Tuesday, December 23, 2008 9:32 PM
TahNk you very mmuch
it`s very very very useful article
Comment posted by saad khan on Monday, January 12, 2009 12:54 PM
plz help me in this,
i am getting ImageError #4001
Comment posted by saad khan on Monday, January 12, 2009 1:04 PM
plz help me in this,
i am getting ImageError #4001
Comment posted by Shreedhar on Thursday, June 18, 2009 4:28 AM
This does not work when relative URL's are used.
Comment posted by avirag on Thursday, July 2, 2009 3:43 AM
hi sir.....this is one of the Great thing.....and this thing will help me a lot.....but sir can u plz tell me that...how to store and fetch flash videos from database in silverlight.........i'll b very thankful 2 u 4 this.........Anurag
Comment posted by N M Reddy on Sunday, July 5, 2009 3:24 PM
thank you.. excellent post..
working againsit convertors also..
Comment posted by Raghavendra on Thursday, February 18, 2010 2:42 AM
what i have to do if i have multiple images to display for example say i have to fetch all the employees photos whose birtday is today
Comment posted by vinay on Wednesday, May 12, 2010 2:04 AM
I am getting error  could you please solve this..                                                                                                            when I am convertingthe image Convert byte array to Bitmap (byte[] to Bitmap) and getting parameter is not valid
Comment posted by amar on Thursday, August 4, 2011 1:30 AM
what i have to do , if i want to store the WP7captured image in to the sql server via web services i.e SOAP services