ASP.NET Web API – Upload & Retrieve Images from MS SQL Database

Table of Contents
Overview
This is an example to create a table to store user profile images inside a column labeled ImageData of type image. Then build 2 API actions to add and retrieve the Image and Meta Data.
First create the table in MS SQL with SSMS.
CREATE TABLE [dbo].[UserImages](
[ImageId] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NULL,
[Label] varchar NULL,
[Size] [int] NULL,
[Url] varchar NULL,
[MimeType] nchar NULL,
[BinaryData] varbinary NULL,
[ImageData] [image] NULL,
[IsActive] [bit] NULL,
[DateUploaded] [date] NULL,
CONSTRAINT [PK_Images] PRIMARY KEY CLUSTERED
(
[ImageId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Storing the image
Import the following
using System;
using System.Collections.Specialized;
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;
using System.Web.Http;
using System.Web.Http.Cors;
Create a Controller
Remember to enable CORS if you plan to use a client side application such as React, Angular, or Vue.
namespace YOURAPPNAME.Controllers
{
[EnableCors(origins: "", headers: "", methods: "*")]
[RoutePrefix("api/images")]
public class UserImageController : ApiController
{
Upload Action
Now add the action to upload a file to the Database. The action should be asynchronous using Async Task
[HttpPost]
[Route("addtodb")]
public async Task addImageToDatabase()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var ctx = HttpContext.Current;
var root = ctx.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
DateTime today = DateTime.Today;
Get the Mime Types with a Switch Statement.
NOTE: The folder you pick must exist on the server the API is deployed to. In this example APP_DATA is used but it will not exist on the server. You can use “~/Content” instead or add a folder to the app after it’s deployed. Make sure the folder ahs read write access.
string catStr = formdata["MimeType"];
switch (catStr)
{
case "image/jpg":
uniqueFileName = $@"{Guid.NewGuid()}.jpg";
break;
case "image/jpeg":
uniqueFileName = $@"{Guid.NewGuid()}.jpg";
break;
case "image/gif":
uniqueFileName = $@"{Guid.NewGuid()}.gif";
break;
case "image/png":
uniqueFileName = $@"{Guid.NewGuid()}.png";
break;
case "image/tiff":
uniqueFileName = $@"{Guid.NewGuid()}.tif";
break;
case "image/webp":
uniqueFileName = $@"{Guid.NewGuid()}.webp";
break;
case "image/apng":
uniqueFileName = $@"{Guid.NewGuid()}.apng";
break;
}
Entity Frameworks
For the database with EF (Entity Frameworks) part of the action
UserImage ProfileForm = new UserImage(); ProfileForm.UserId = int.Parse(formdata["UserId"]); ProfileForm.IsActive = true; ProfileForm.IsActive = true; ProfileForm.Label = formdata["Label"]; ProfileForm.DateCreated = today;
Parsing the File Array
For the file portion of the action loops thru all files attached to the request and gets and put the binary, size, and MimeType into their respective fields.
foreach (MultipartFileData file in provider.FileData)
{
var fileName = file.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
string mimeType = MimeMapping.GetMimeMapping(fileName);
byte[] documentData = File.ReadAllBytes(file.LocalFileName); ProfileForm.ImageData = documentData;
ProfileForm.MimeType = mimeType;
ProfileForm.Size = documentData.Length;
}
All Together
[HttpPost]
[Route("addtodb")]
public async Task addImageToDatabase()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var ctx = HttpContext.Current;
var root = ctx.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
DateTime today = DateTime.Today;
try {
using (portfolioEntities db = new portfolioEntities()) {
// Read the form data. await Request.Content.ReadAsMultipartAsync(provider);
var uniqueFileName = ""; NameValueCollection formdata = provider.FormData;
UserImage ProfileForm = new UserImage();
ProfileForm.UserId = int.Parse(formdata["UserId"]); ProfileForm.IsActive = true;
ProfileForm.IsActive = true;
ProfileForm.Label = formdata["Label"];
ProfileForm.DateCreated = today;
foreach (MultipartFileData file in provider.FileData)
{
var fileName = file.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
string mimeType = MimeMapping.GetMimeMapping(fileName);
byte[] documentData = File.ReadAllBytes(file.LocalFileName); ProfileForm.ImageData = documentData;
ProfileForm.MimeType = mimeType;
ProfileForm.Size = documentData.Length;
}
db.UserImages.Add(ProfileForm);
db.SaveChanges();
return Ok("Successfully Added Image To Database");
}
} catch (System.Exception e)
{
return BadRequest(e.Message); }
}
Using Postman call the API Action as follows with your LocalHost Address. Remember use the POST method

From SSMS you can check the new entries for the UserImages table. Please ignore the extra fields.

Getting the image
Now create another action called getdbimage and allow an ID to be passed as a parameter to get a single image record. This is simple get from the database with Entity Framework using a Where clause to get the images for a User with UserId.
[HttpGet]
[Route("getdbimagelist")]
public object getDBImageList()
{
try
{
using (DemoEntities db = new DemoEntities())
{
var queryResults = db.UserImages.ToList();
return new { status = StatusCodes.OK.code, msg = StatusCodes.OK.msg, data = queryResults };
}
}
catch (System.Exception e)
{
return new { status = StatusCodes.NotFound.code, msg = e.InnerException, data = 0 };
}
}
Using Postman GET request. Remember this is a GET request

You must be logged in to post a comment.