ASP.NET MVC: Display Images Directly From The ViewModel Into Your Views

Some time ago, I wrote a custom control for ASP.NET that could display an image directly from the database without a file-based image source. Because of the way that ASP.NET MVC works, it is not feasible to use this technique. However, now that modern browsers all support the "data" protocol for displaying images, there is an easy alternative.

Rather than provide a complete downloadable solution, I'll simply reproduce the appropriate code here, as it is really quite simple.

Let's say we have a Razor View that displays a list of the Northwind database Employees. The ViewModel class would look like this:

  public class EmployeesViewModel
    {
         public List<Employee> Employees { get; set; }
    }

And the Employee Class:

  public class Employee : Entity
    {
         public virtual int EmployeeID     {get;set;}
     public virtual string LastName  {get;set;}
    public virtual string  FirstName   {get;set;}
     public virtual string Title  {get;set;}
    public virtual string TitleOfCourtesy   {get;set;}
     public virtual DateTime BirthDate   {get;set;}
    public virtual DateTime HireDate   {get;set;}
    public virtual string Address   {get;set;}
    public virtual string City   {get;set;}
    public virtual string Region   {get;set;}
    public virtual string PostalCode   {get;set;}
    public virtual string  Country   {get;set;}
     public virtual string HomePhone  {get;set;}
    public virtual string Extension   {get;set;}
    public virtual byte[] Photo   {get;set;}
    public virtual string Notes   {get;set;}
    public virtual int ReportsTo {get;set;}
    public virtual string PhotoPath   {get;set;}
    }


    Finally the simplified EmployeeController class:

     public class EmployeeController : Controller
    {

         public ActionResult Index()
        {
            EmployeesViewModel model = new EmployeesViewModel();
            model.Employees = ServiceLocator.Current.GetInstance<IEmployeeRepository>().GetAll().ToList();
             return View(model);
        }
    }


  Now here's the trick in the actual View:

@using MVCSharpArch.Domain
@model MVCSharpArch.Web.Controllers.ViewModels.EmployeesViewModel
   @{
ViewBag.Title = "Employees";
Layout = "~/Views/Shared/_Layout.cshtml";
     }

<h2>Employees</h2>

  @using (Html.BeginForm("Edit", "Employee", FormMethod.Post))
  {
      @Html.AntiForgeryToken()
      <table class="table">
          @foreach (var emp in Model.Employees)
           {
               <tr id="emp@emp.Id)">
                   <td>@emp.Id</td>
                   <td>@emp.FirstName</td>
                   <td>@emp.LastName </td>
                    @{ byte[] photo = emp.Photo;
                        string imageSrc = null;
                       if (photo != null)
                       {
                           MemoryStream ms = new MemoryStream();
                           ms.Write(photo, 78, photo.Length - 78); // strip out 78 byte OLE header (don't need to do this for normal images)
                           string imageBase64 = Convert.ToBase64String(ms.ToArray() );
                           imageSrc = string.Format("data:image/gif;base64,{0}", imageBase64);
                       }
                     }
                    <td><img src="@imageSrc" alt="Employee Photo" border="0" /></td>
                   <td>@emp.Address</td>
                   <td>@emp.City</td>
                   <td>@emp.Region</td>
                   <td>@emp.Country</td>  
               </tr>
          }
       </table>
  }

You can see that when I get to display the photo, which is a byte array property of the Employee object, I check for null, write the bytes into a MemoryStream, chopping off the 78 byte OLE header (Yes the images in SQL Server Northwind are the original Access images).

Then I convert the byte array to a Base64 encoded string, and create the image "src" value:

  imageSrc = string.Format("data:image/gif;base64,{0}", imageBase64);

  The result displays the images inline using the "data" protocol which is now supported by all major browsers, with no requirement for separate HTTP requests for the images. This of course increases the size of your page because of the presence of all those Base64 strings, but for small images, it's pretty efficient:




  No fancy controls or Html Helpers required! Incidentally, the fuzzy quality of the images above has nothing to do with the technique, it's just that they are very old, low-resolution images. I wonder what happened to Nancy Davolio....

By Peter Bromberg   Popularity  (12921 Views)