Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Upload Image to .NET Core 2.1 API

0.00/5 (No votes)
17 Aug 2018 1  
This article is on how to upload and retrieve images from your .NET core 2.1 API.

Introduction

This article is on how to upload and retrieve images from your .NET Core 2.1 API. The images can be accessed using the image name which is displayed on the browser.

I have also uploaded the code on Github. Hope you find this guide useful.

Background

  • I used postman to make POST requests, any alternative should be fine
  • .NET Core 2.1 compatible Visual Studio
  • An idea about dependency injection
  • A good knowledge about Task<> and async methods
  • Some idea about API controllers (I have explained on a very high level which is enough to understand what is going on)

Code

First up, let’s create a new ASP .NET Core Web application and select API project and call it ImageUploader.

Project Structure

Below is the project structure that I have used to create the project. I will be explaining what each of the files do:

The Handler folder has a ImageHandler.cs which is used by the ImageController to call the image writing component of the program by injecting the handler into the controller.

The ImageWriter is a .NET Core 2.1 class library project which takes care of writing and the image to the disk. We write the image in wwwroot/images folder which I have created.

The WriterHelper.cs is a helper class used by the ImageWriter to validate whether a given file is an image file.

Code

I would like to start with the WriterHelper.cs below which is the code to validate the uploaded file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ImageWriter.Helper
{
    public class WriterHelper
    {
        public enum ImageFormat
        {
            bmp,
            jpeg,
            gif,
            tiff,
            png,
            unknown
        }

        public static ImageFormat GetImageFormat(byte[] bytes)
        {
            var bmp = Encoding.ASCII.GetBytes("BM");     // BMP
            var gif = Encoding.ASCII.GetBytes("GIF");    // GIF
            var png = new byte[] { 137, 80, 78, 71 };              // PNG
            var tiff = new byte[] { 73, 73, 42 };                  // TIFF
            var tiff2 = new byte[] { 77, 77, 42 };                 // TIFF
            var jpeg = new byte[] { 255, 216, 255, 224 };          // jpeg
            var jpeg2 = new byte[] { 255, 216, 255, 225 };         // jpeg canon

            if (bmp.SequenceEqual(bytes.Take(bmp.Length)))
                return ImageFormat.bmp;

            if (gif.SequenceEqual(bytes.Take(gif.Length)))
                return ImageFormat.gif;

            if (png.SequenceEqual(bytes.Take(png.Length)))
                return ImageFormat.png;

            if (tiff.SequenceEqual(bytes.Take(tiff.Length)))
                return ImageFormat.tiff;

            if (tiff2.SequenceEqual(bytes.Take(tiff2.Length)))
                return ImageFormat.tiff;

            if (jpeg.SequenceEqual(bytes.Take(jpeg.Length)))
                return ImageFormat.jpeg;

            if (jpeg2.SequenceEqual(bytes.Take(jpeg2.Length)))
                return ImageFormat.jpeg;

            return ImageFormat.unknown;
        }
    }
}

Now, it’s time to set up the actual ImageWriter.cs but before that, let’s populate the IImageWriter.cs interface so we can inject it in our handlers.

using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace ImageWriter.Interface
{
    public interface IImageWriter
    {
        Task<string> UploadImage(IFormFile file);
    }
}

And now the ImageWriter.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using ImageWriter.Helper;
using ImageWriter.Interface;
using Microsoft.AspNetCore.Http;

namespace ImageWriter.Classes
{
    public class ImageWriter : IImageWriter
    {
        public async Task<string> UploadImage(IFormFile file)
        {
            if (CheckIfImageFile(file))
            {
                return await WriteFile(file);
            }

            return "Invalid image file";
        }

        /// <summary>
        /// Method to check if file is image file
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        private bool CheckIfImageFile(IFormFile file)
        {
            byte[] fileBytes;
            using (var ms = new MemoryStream())
            {
                file.CopyTo(ms);
                fileBytes = ms.ToArray();
            }

            return WriterHelper.GetImageFormat(fileBytes) != WriterHelper.ImageFormat.unknown;
        }

        /// <summary>
        /// Method to write file onto the disk
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public async Task<string> WriteFile(IFormFile file)
        {
            string fileName;
            try
            {
                var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
                fileName = Guid.NewGuid().ToString() + extension; //Create a new Name 
                                                              //for the file due to security reasons.
                var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot\\images", fileName);

                using (var bits = new FileStream(path, FileMode.Create))
                {
                    await file.CopyToAsync(bits);
                }
            }
            catch (Exception e)
            {
                return e.Message;
            }

            return fileName;
        }
    }
}

The main logic here is to first check the file. If it is an image file, we write it with a new name for security reasons and return the name back to the user (we can also use a persistent storage to map the file name to the new name for later retrieval). If file is invalid, we return an error message.

With the main functionalities being done, let’s head over to the handler where we direct the incoming requests to an appropriate method.

using System.Threading.Tasks;
using ImageWriter.Interface;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace ImageUploader.Handler
{
    public interface IImageHandler
    {
        Task<IActionResult> UploadImage(IFormFile file);
    }

    public class ImageHandler : IImageHandler
    {
        private readonly IImageWriter _imageWriter;
        public ImageHandler(IImageWriter imageWriter)
        {
            _imageWriter = imageWriter;
        }

        public async Task<IActionResult> UploadImage(IFormFile file)
        {
            var result = await _imageWriter.UploadImage(file);
            return new ObjectResult(result);
        }
    }
}

Here, ImageWriter is injected into the handler.

Time to configure the controller:

using System.Threading.Tasks;
using ImageUploader.Handler;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace ImageUploader.Controllers
{
    [Route("api/image")]
    public class ImagesController : Controller
    {
        private readonly IImageHandler _imageHandler;

        public ImagesController(IImageHandler imageHandler)
        {
            _imageHandler = imageHandler;
        }

        /// <summary>
        /// Uplaods an image to the server.
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public async Task<IActionResult> UploadImage(IFormFile file)
        {
            return await _imageHandler.UploadImage(file);
        }
    }
}

Finally, we have to configure the Startup.cs to inform the application to use wwwroot/images folder. We can do that by adding a simple one line of code in our Configure method.

We can also make reference to files outside the wwwroot folder by specifying the path of the inside of the commented area of the above screenshot. In the screenshot above, the commented configuration would use a folder called StaticFiles inside the main project.

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            //Use this to set path of files outside the wwwroot folder
            //app.UseStaticFiles(new StaticFileOptions
            //{
            //    FileProvider = new PhysicalFileProvider(
            //        Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")),
            //    RequestPath = "/StaticFiles"
            //});

            app.UseStaticFiles(); //letting the application know that we need access to wwwroot folder.

            app.UseHttpsRedirection();
            app.UseMvc();
        }

Finally, we add the dependency injection for the ImageHandler and ImageWriter in our ConfigureServices method.

// This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddTransient<IImageHandler, ImageHandler>();
            services.AddTransient<ImageWriter.Interface.IImageWriter, 
                                  ImageWriter.Classes.ImageWriter>();
        }

Result

Let’s fire it up and send an image file using postman:

Make sure you set the key to file and value to a valid image file. Also ensure that the request is a POST request. As we can see from the above screenshot, we got the name of the uploaded file. Let’s check if it is actually inside the images folder:

Now how do we retrieve it? It is very simple, all we have to do is call the http://ipaddress:port/images/filename.

There you have it! An API to upload and retrieve images. You can use the above link to directly embed images into HTML <img src =””> tags.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here