Image Retrieval using ASP.NET MVC 4.0 WebAPI with HttpResponseMessage

Posted by: Mahesh Sabnis , on 1/20/2013, in Category ASP.NET MVC
Views: 14704
Abstract: This article demonstrates how to use ASP.NET WebAPI to retrieve images from a database server

Recently during a discussion on WebAPI capabilities, I was asked about the HttpResponseMessage message class and its messaging features, particularly on sending an Image as a response. We all know that an action method exposed via WebAPI can be consumed directly in jQuery using AJAX. Since a JSON response is returned by default in a WebAPI,  the question that arises is how to send the image in the response object.

I worked on this scenario and this article is the outcome of it. For simplicity, we assume images are stored in the SQL Server database in the form of Binary objects, (they can just be images on a file server, or blob container on cloud etc) too.

 

The overall idea is that the binary data from the database server is converted into the images and then this needs to be passed using HttpResponseMessage object.

To implement the scenario, the following objects are used:

  • Bitmap - The objects encapsulate a GDI+ bitmap. This consist of pixel data for graphics image.
  • FileStream and MemoryStream - Objects used to manage file on the server and pass to the caller using HttpResponseMessage content.
  • Image - Class provides functionality for managing Images.
  • ByteArrayContent - Class representing the Http content based byte array sent as a response.

The most important part here is how to specify the HttpResponseMessage header format for images. This is achieved by the MediaTypeHeaderValue class.

For this implementation, I have used a SQL Server database with the following table:

sql-server-table

The table contains Employee images using ‘image’ Data Type of the SQL server database. (Note: When you test the source code in the article, you should have a table on your database server with images in it.)

Step 1: Open VS 2012 and create a new ASP.NET MVC 4.0 project. Name it as ‘MVC40_WebAPI_ImageReader’. In this project, add a new ADO.NET EF mapping of the above table in the Models folder. After completing the wizard, the table mapping will be as shown below:

image-employee

Build the project.

Step 2: In the Controller folder, right click and add a new API controller, name it as ‘EmployeeController’. Import the following namespaces in the class:

using MVC40_WebAPI_ImageReader.Models;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Hosting;
using System.Web.Http;

Step 3: Define an instance of the ADO.NET EF and add the GetImage() method in the class. This method accepts the Id for EmpNo and queries the Employees records. Once the Employee record is found, the binary data for the Employee Image is extracted and the Bitmap is created. This bitmap is then saved on the server using Stream and then Image object is read from the stream. This Image is then saved into the MemoryStream which is then sent as a ByteContentArray as a content of the HttpResponseMessage object. The class implementation is as shown below (the steps are also outlined in the comments):

namespace MVC40_WebAPI_ImageReader.Controllers
{
public class EmployeeController : ApiController
{
  //ADO.NET EF object
  CompanyEntities objContext;
  public EmployeeController()
  {
   objContext = new CompanyEntities();
  }
 
  /// <summary>
  /// Method for
  /// 1. Read the ByteArray from Sql Server Database
  /// 2. Convert the Byte Array into Bitmap.
  /// 3. Save the file on the server using FileStream object.
  /// 4. Get the Image object from FileStream
  /// 5. Save the Image object into MemoryStream
  /// 6. The MemoryStream is passed into the HttpResponse in Http Content based byte Array using ByteArrayContent object
  /// </summary>
  /// <param name="Id"></param>
  /// <returns></returns>
  public HttpResponseMessage GetImage(int Id)
  {
   HttpResponseMessage response = new HttpResponseMessage();


   //1
   var Emp = (from e in objContext.ImageEmployees
                       where e.EmpNo == Id
                       select e).First();

 

 

   //2
   TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(Bitmap));
   Bitmap bmp = (Bitmap)typeConverter.ConvertFrom(Emp.EmpImage);


           
   //3
   var Fs = new FileStream(HostingEnvironment.MapPath("~/Images") + @"\I" + Id.ToString() + ".png", FileMode.Create);
   bmp.Save(Fs,ImageFormat.Png);
   bmp.Dispose();


   //4
   Image img = Image.FromStream(Fs);
   Fs.Close();
   Fs.Dispose();


   //5
   MemoryStream ms = new MemoryStream();
   img.Save(ms, ImageFormat.Png);


   //6
   response.Content = new ByteArrayContent(ms.ToArray());
   ms.Close();
   ms.Dispose();
            
   response.Content.Headers.ContentType = new     MediaTypeHeaderValue("image/png");
           response.StatusCode = HttpStatusCode.OK;

            return response;
  }
}
}

Step 4: In the controller, add a new empty controller and name it as ‘ImageEmployeeController’. You will have an Index method. Generate a new Index view and add the following HTML markup in it:

 

<table>
<tr>
  <td>Enter EmpNo </td>
  <td>
   <input type="text" id="txteno" />
  </td>
  <td>
   <input type="button" id="btngetemp" value="Get Employee" />
  </td>
</tr>
<tr>
  <td>
   <img id="emimage" src="" height="100" width="100"/>
  </td>
</tr>
</table>

Add the following script in the view:

<script type="text/javascript">
$(document).ready(function () {
  $("#btngetemp").click(function () {
   var EmpNo = $("#txteno").val();
  $("#emimage").attr("src", "http://localhost:4208/api/Employee/" + EmpNo);
});
});
</script>

The above script specifies that the ‘src’ attribute is added with the URL of the WebAPI. This executes the API method and sends the response as image format as ‘image/png’ and displays the image in the img tag.

Step 5: Run the application and enter EmpNo in the TextBox. After clicking on the button, the result will be as shown below:

mvc-web-api

Conclusion

The above approach is very useful when images needs to be fetched form various location like FileServer, CloudBlob etc.

Give me a +1 if you think it was a good article. Thanks!
Recommended Articles
Mahesh is having 10 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet




Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by Darrel Miller on Sunday, January 20, 2013 10:17 AM
Why not pass the byte array from step 1 into the ByteArrayContent in step 6 and skip steps 2-5?
Comment posted by Suprotim Agarwal on Tuesday, January 22, 2013 3:55 AM
I like Darrel's suggestion. Sounds like the right way to do this.

@Mahesh Sabnis, any particular reason of not using the ByteArray coming from the Database directly into the ByteArrayContent? One reason I can think of is if you want to manipulate the image after retrieving - eg: adding watermark.
Comment posted by Jeremy S on Thursday, February 07, 2013 4:23 AM
The real question is why you have images in the db in the first place.

A *slightly* more practical example would get the image from disk, or an Amazon S3 bucket, since that's where everyone seems to store stuff nowadays.
Comment posted by newpostalcode on Thursday, February 28, 2013 6:12 AM
every country have different postal code or zip code therefore u can search postal code i our site.

http://www.newpostalcode.com/
Comment posted by Dmitry G on Monday, March 04, 2013 3:14 PM
Code style is really bad, deprecated image column type is used. Did not continue reading
Comment posted by Dmitry G on Monday, March 04, 2013 3:16 PM
Yuck, code does very silly things also. Huge dislike for this article
Comment posted by grreshma on Monday, April 08, 2013 11:54 PM
How to display an image after upload button click before saving to DB in asp.net mvc2

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel