ASP.NET C# Web API with SQL Server – Upload Multiple Images to Folder
Table of Contents
Overview
The Web API in this example records the title and uploads files to a folder. The title is added as a new record to a table labeled “Products”. After the title is saved, the Product ID is then stored along with Image size, mime type, new filename, and path to the “ProductImages” table. The API will create sub folders under Content/images at the root directory. This can easily be redirected to a file share or storage bucket of your choice.
You can get the source files for the API along with Angular or React as the front end.
ASP.NET Web API GitHub Repo here.
Angular & ASP.NET Web API GitHub Repo here.
React & ASP.NET Web API GitHub Repo here.
Before you can run the API
Try running the following command in the Package Manager Console
use nuget locals all -clear
OR
dotnet nuget locals all --clear
Also may need to update the installed Nuget Packages.
Then Cloning this repo will require you to install the nuget packages. Try an update to get everything installed

MS SQL SERVER TABLES
This part is optional. The API uses a local MDF file so you can just skip over this.
Create the following tables.
CREATE TABLE [dbo].[Product](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Title] [varchar](50) NULL,
[Description] [varchar](200) NULL,
CONSTRAINT [PK__Product__3214EC0790EB3E64] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[ProductImages](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[ImagePath] [varchar](200) NULL,
[FileName] [varchar](50) NULL,
[MimeType] [varchar](40) NULL,
[FileSize] [bigint] NULL,
[DateCreated] [date] NULL,
CONSTRAINT [PK__ProductI__3214EC0792997772] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ASP.NET WEB API
Create a new ASP.NET C# Web API.
Add the Product and Product Images tables with Entity Framework. The example uses a local MDF file with the Products and ProductImages tables.
Your own local instance of MS SQL Server
Right click on the Models folder and add a new item

First get the MS SQL Server name from the properties in SSMS (SQL Server Management System).


Create Models
Create a new class the following under a new folder labeled “FormModels”. Class is labeled “ProductImageResults.cs”

“ProductImageResults.cs” will be used in a class to send the Product records and the images for each record.

ProductImageResult.cs
public class ProductImageResult
{
public int Id { get; set; }
public string Title { get; set; }
public ICollection<ProductImage> Images { get; set; }
}
Controller
Define a class of Products with each record having a list of Product Images. Goal is to get everything with a single API call.
public class ProductData
{
public ICollection<ProductImageResult> record { get; set; }
public ProductData()
{
this.record = new List<ProductImageResult>();
}
}
This will return a JSON object with an array of URLs for each Product Title.
{ Title: "Some Title", Images: ['1/xxxx-xxxx-xxxx-xxxx.jpg', '2/xxxx-xxxx-xxxx-xxxx.jpg'...] }
Controller Action – Get a list of all Products and the Product Images.
[HttpGet]
[Route("get")]
public object getDBImageList()
{
try
{
using (MultiFileUploadDBEntities db = new MultiFileUploadDBEntities())
{
var ProductJSONObj = new ProductData { };
var queryResults = db.Products.ToList();
foreach (var item in queryResults)
{
ProductImageResult record = new ProductImageResult();
record.Id = item.Id;
record.Title = item.Title;
var ProdImages = db.ProductImages.Where(col => col.ProductId == item.Id).ToArray();
record.Images = ProdImages;
ProductJSONObj.record.Add(record);
}
return new { status = StatusCodes.OK.code, msg = StatusCodes.OK.msg, data = ProductJSONObj };
}
}
catch (System.Exception e)
{
return new { status = StatusCodes.NotFound.code, msg = e.InnerException, data = 0 };
}
}
Controller Action – Add a new Product record
This action has to be asynchronous since it is working with files. Angular or React will have to use a promise to post the form and images to the API.
[HttpPost]
[Route("add")]
public async Task<IHttpActionResult> 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("~/Content");
var provider = new MultipartFormDataStreamProvider(root);
DateTime today = DateTime.Today;
try
{
using (MultiFileUploadDBEntitiesdb = new MultiFileUploadDBEntities())
{
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
var uniqueFileName = "";
NameValueCollection formdata = provider.FormData;
Product ProductForm = new Product();
ProductForm.Title = formdata["Title"];
db.Products.Add(ProductForm);
db.SaveChanges();
foreach (MultipartFileData file in provider.FileData)
{
// Get File Size
byte[] documentData = File.ReadAllBytes(file.LocalFileName);
long fileSize = documentData.Length;
// Get File Name
var fileName = file.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
string mimeType = file.Headers.ContentType.MediaType;
ProductImage ProductImageForm = new ProductImage();
Guid g = Guid.NewGuid();
// Get Mimetype
var fileType = "jpg";
switch(mimeType)
{
case "image/jpeg": fileType = "jpg"; break;
case "image/jpg": fileType = "jpg"; break;
case "image/png": fileType = "png"; break;
case "image/bmp": fileType = "bmp"; break;
case "image/gif": fileType = "gif"; break;
default: fileType = "jpg"; break;
}
var parentId = ProductForm.Id.ToString();
var newFilename = g.ToString() + "." + fileType;
var path = ProductForm.Id.ToString() + "/" + newFilename;
string subPath = root + "\\images\\" + parentId; // Your code goes here
bool exists = Directory.Exists(subPath);
if (!exists)
Directory.CreateDirectory(subPath);
var localFileName = file.LocalFileName;
var filepath = Path.Combine(root, uniqueFileName);
File.Move(localFileName, subPath + "\\" + newFilename);
ProductImageForm.FileName = newFilename;
ProductImageForm.ProductId = ProductForm.Id;
ProductImageForm.ImagePath = path;
ProductImageForm.FileSize = fileSize;
ProductImageForm.MimeType = mimeType;
ProductImageForm.DateCreated = today;
db.ProductImages.Add(ProductImageForm);
db.SaveChanges();
}
return Ok("Successfully Added Record and Images");
}
}
catch (System.Exception e)
{
return BadRequest(e.Message);
}
}
Controller Action – Delete a single Product and all the Product Images for that record.
This is an all in one delete removes the records in the ProductImages table in addition to deleting the files from the directory. Once the images have been deleted, then the parent record is removed. This is the order you want to see if there are constraints on the tables to prevent deleting from the parent table if there are records in the child table.
[HttpDelete]
[Route("remove/{id}")]
public object renoveProduct(int id)
{
try
{
var ctx = HttpContext.Current;
var root = ctx.Server.MapPath("~/Content");
var provider = new MultipartFormDataStreamProvider(root);
using (MultiFileUploadDBEntitiesdb = new MultiFileUploadDBEntities())
{
var product = db.Products.Find(id);
var images = db.ProductImages.Where(col => col.ProductId == id).ToArray();
// Remove Each File
for (int i = 0; i < images.Length; i++)
{
var filepath = root + "\\images\\" + images[i].ImagePath;
FileInfo file = new FileInfo(filepath);
if (file.Exists)//check file exsit or not
{
file.Delete();
}
var imageRecord = db.ProductImages.Find(images[i].Id);
db.ProductImages.Remove(imageRecord);
}
// Remove the Directory
var dirpath = root + "\\images\\" + product.Id;
Directory.Delete(dirpath);
// Remove the parent record
db.Products.Remove(product);
db.SaveChanges();
return Ok("Successfully Deleted Record and Images");
}
}
catch (System.Exception e)
{
return BadRequest(e.Message);
}
}
You must be logged in to post a comment.