Display Image From Byte Array in ASP.NET MVC

Recently I came across a requirement where a business unit wants to advertise contents with images on a website but they don’t own or govern the website where contents would be displayed. Let me put the requirements in technical terms! People own and manage the images don’t (and will not) have access to website and people in charge of managing website don’t (and will not) have direct access to images. So, how would the website get to display the images?

The answer is partnership or collaboration! One of the architectural option is to publish the images in CDN and share image metadata with the team manages the website. CDN is secure but by its distributed nature it comes with some sort of risk and we are not ready to accept the risk given the sensitivity of the contents. We are architect and we get paid for thinking! How about creating an image webservice that would retrieve images from Database or File server and output the image as byte array? This way website can simply call the webservice (RESTful API) and display the image as byte array. There is no need to persist images unless you want to maximize the performance. Guess what? You are about to adopt SOA Design Pattern!

This application demonstrates how to display images in browser those are retrieved from DB or file server as byte array. Both the Web Controller and Api Controller are used in the same project for demo purpose. You would separate those layers in real-world application.

Seeing is believing, let see it in action (live demo on my Azure Portal): http://azure.aspnet4you.com

Looking for Swagger Api Documentations? It’s here

Solution Architecture:

app-architecture

 

 

 

 

 

 

 

 

 

Let’s see the makeup of the project. I did not use ready-to-go template to avoid including unnecessary dependencies. All the files, folders and packages are added manually as needed.

project-explorer

 

 

 

 

 

 

 

 

 

 

You can download the entire source codes but I wanted to connect the dots from browser to website to webapi to file server.  You can use DB or File server to store the images in production application. I used file for simplicity.

Views/Home/Index.cshtml:


@inherits System.Web.Mvc.WebViewPage<ASPNET4YOU.MVC5.Models.ImageModel>

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Welcome to ASP.NET MVC</title>
<style>
h1 {
color: blue;
font-family: verdana;
font-size: 150%;
}

p {
color: red;
font-family: courier;
font-size: 160%;
}

table {
border-collapse: collapse;
}

table, th, td {
border: 1px solid black;
background-color:chartreuse
}
</style>
</head>
<body>
<div>
<h1>
Welcome to ASP.NET MVC!
</h1>
<br />
<p style="width: 780px">
This application demonstrates how to display images in browser those are retrieved from DB or file server as byte array. Both the Web Controller and Api Controller are used in the same project for demo purpose. You would separate those layers in real-world application.
</p>

<br />
</div>

<div style="">
<h1>It's fun loading image from DB on the fly!</h1>
<table border="1">
<tbody>
<tr>
<th>Model Property</th>
<th>Model Value</th>
</tr>
<tr>
<td>Image Id:</td>
<td>@Model.Id</td>
</tr>
<tr>
<td>Image Name:</td>
<td>@Model.Name</td>
</tr>
<tr>
<td>Image ContentType:</td>
<td>@Model.ContentType</td>
</tr>
<tr>
<td>Image Size (bytes):</td>
<td>@Model.Data.Length</td>
</tr>
</tbody>
</table>
</div>

<div>
<br />
<img src='@Url.Action("ShowCSharpBanner", "Home")' />
</div>

<div>
<br />
<h1>Application Architecture</h1>
<br />
<img src='@Url.Action("ShowAppArchitecture", "Home")' />
</div>

</body>
</html>

Controllers/HomeController.cs:

This is the Website controller that calls API controller to get the image as byte array. We are going to use ViewModel since this is MVC project.


using ASPNET4YOU.MVC5.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Mvc;

namespace ASPNET4YOU.MVC5.Controllers
{
public class HomeController : Controller
{
HttpClient client;
string url = ConfigurationManager.AppSettings.Get("apiBaseUrl");
string img01 = ConfigurationManager.AppSettings.Get("img01");
string img02 = ConfigurationManager.AppSettings.Get("img02");

public HomeController()
{
client = new HttpClient();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}

public async Task<ActionResult> Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";

ImageModel imgModel = null;
HttpResponseMessage responseMessage = await client.GetAsync($"{url}/GetImage/{img01}");
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
imgModel = JsonConvert.DeserializeObject<ImageModel>(responseData);
}

return View(imgModel);
}

public ActionResult About()
{
return View();
}

public async Task<ActionResult> ShowCSharpBanner()
{
ImageModel imgModel = null;
HttpResponseMessage responseMessage = await client.GetAsync($"{url}/GetImage/{img01}");
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
imgModel = JsonConvert.DeserializeObject<ImageModel>(responseData);
}

return File(imgModel.Data, imgModel.ContentType);
}

public async Task<ActionResult> ShowAppArchitecture()
{
ImageModel imgModel = null;
HttpResponseMessage responseMessage = await client.GetAsync($"{url}/GetImage/{img02}");
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
imgModel = JsonConvert.DeserializeObject<ImageModel>(responseData);
}

return File(imgModel.Data, imgModel.ContentType);
}
}
}

Controllers/ImageController.cs:

This is our API controller serves the image as byte array.


using ASPNET4YOU.MVC5.Models;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace ASPNET4YOU.MVC5.Controllers
{
public class ImageController : ApiController
{
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}

[HttpGet]
public Movie GetMovie()
{
return new Movie() { ID = 1, Price = 5.00M, Title = "Fantastic!", ReleaseDate = DateTime.Now, Genre = "PG3" };
}
[HttpGet]
public ImageModel GetImage(string id)
{
ImageModel imgModel = new ImageModel();
imgModel.Id = 1;
imgModel.Name = id;
imgModel.ContentType = "img/jpg";
imgModel.Data = imageToByteArray(id);
return imgModel;
}

private byte[] imageToByteArray(string imageName)
{
string imgext = ConfigurationManager.AppSettings.Get("imgext");
string filePath = $"{AppDomain.CurrentDomain.SetupInformation.ApplicationBase}images\\{imageName}.{imgext}";
System.Drawing.Image image = System.Drawing.Bitmap.FromFile(filePath);
using (var ms = new MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
}
}
}

You can download the Visual Studio project: DynamicImageRenderer.zip.

Code compilation dependencies:

  • VS 2015 Update 3
  • IIS Express
  • .Net 4.5 (or above). Want to run under local IIS? Turn on the feature in control panel under Internet Information Services. You don’t need to turn on the feature if you are running under IIS Express.
  • All the packages are part of this download but you can import from nuget.org.