Upload image to ASP.NET Web API 2

By | January 31, 2016

Introduction

This post will provide detail on uploading image from a web application (ASP.NET MVC5 web application) to a web service (ASP.NET WebAPI2). We will use Visual Studio 2012 (.NET framework 4.5) to build web application and web service.

Web Application

Web application is written using Microsoft ASP.NET MVC5 and Razor views. The below given code snippets will display controller and view. It will also display model that is shared between web application and web service.

Code

Model: SchoolFileUploadModel

This model class is shared between web application and web service.

using Core.Common.Mapping;
using Growth.Domain.Entities;
using System;
namespace Growth.Model
{
    public class SchoolFileUploadModel
    {
        public int Id { get; set; }
        public byte[] Image { get; set; }
        public string ImageName { get; set; }
        public string ContentType { get; set; }
        public int ContentSize { get; set; }
        public string Code { get; set; }
        public string Comments { get; set; }
        public int? CreatedBy { get; set; }
        public int? ModifiedBy { get; set; }
        public DateTime? DateCreated { get; set; }
        public DateTime? DateModified { get; set; }
    }
}

Controller: LibraryController

We have used BSON (Binary JSON) in the accept header of the HttpClient. This is used to pass byte array data along with other model attributes in Web API call.

using Growth.Model;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Mvc;
namespace Growth.WebApplication.Controllers
{
    public class LibraryController : BaseController
    {
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Upload(HttpPostedFileBase uploadedFile)
        {
            if (ModelState.IsValid)
            {
                if (uploadedFile != null && uploadedFile.ContentLength > 0)
                {
                    var schoolFileUploadModel = new SchoolFileUploadModel
                    {
                        ImageName = Path.GetFileName(uploadedFile.FileName),
                        ContentType = uploadedFile.ContentType,
                        ContentSize = uploadedFile.ContentLength
                    };
                    using (var reader = new BinaryReader(uploadedFile.InputStream))
                    {
                        schoolFileUploadModel.Image = reader.ReadBytes(uploadedFile.ContentLength);
                    }
                    // Set the Accept header for BSON.
                    Client.DefaultRequestHeaders.Accept.Clear();
                    Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));
                    // POST using the BSON formatter.
                    MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
                    var response = Client.PostAsync<SchoolFileUploadModel>("Picture/Upload", schoolFileUploadModel, bsonFormatter);
                    response.Result.EnsureSuccessStatusCode();
                }
            }
            //TODO: set correct return
            return View();
        }
        // GET
        public ActionResult Index()
        {
            var responseString = "Upload";
            return View(responseString);
        }
    }
}

Controller: BaseController

using Growth.WebApplication.Common;
using Growth.WebApplication.Models;
using Growth.WebApplication.Util;
using System.Net.Http;
using System.Web.Mvc;
namespace Growth.WebApplication.Controllers
{
    public class BaseController : Controller
    {
        public HttpClient Client {
            get
            {
                var accessTokenModel = Session.GetValue<AccessTokenModel>(WebAppConstants.SESSION_ACCESS_TOKEN);
                if (accessTokenModel != null)
                {
                    return GetClient(accessTokenModel.Token);
                }
                else
                {
                    return GetClient();
                }
            }
        }
        /// <summary>
        /// Get client with authorization header
        /// </summary>
        /// <param name="accessToken"></param>
        /// <returns></returns>
        public static HttpClient GetClient(string accessToken = "")
        {
            var client = new HttpClient()
            {
                BaseAddress = new Uri(string.Format("{0}{1}", ConfigurationManager.AppSettings["BaseAddressUri"], WebAppConstants.REL_API_URL))
            };
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            if (!string.IsNullOrEmpty(accessToken))
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            return client;
        }
    }
}

View : Upload

@model Growth.Model.SchoolFileUploadModel
@{
    ViewBag.Title = "Upload";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Upload</h2>
@using (Html.BeginForm("Upload", "Library", null, FormMethod.Post, new {enctype = "multipart/form-data"}))
{
    @Html.AntiForgeryToken()
  <div class="form-horizontal">
   <h4>Student</h4>
   <hr/>
   @Html.ValidationSummary(true, "", new { @class = "text-danger" })
   <div class="form-group">@Html.Label("Avatar", new {@class = "control-label col-md-2"})
      <div class="col-md-10"><input type="file" id="Avatar" name="uploadedFile" /></div>
   </div>
   <div class="form-group">
     <div class="col-md-offset-2 col-md-10">
          <input type="submit" value="Create" class="btn btn-default" />
     </div>
   </div>
  </div>
}

Web Service

Web Service is written using Microsoft ASP.NET WebAPI2. The below given code snippets will display controller.

Code

Controller: UploadController

using AutoMapper;
using Core.Business;
using Growth.Business.Facade;
using Growth.Domain.Entities;
using Growth.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace Growth.WebService.Controllers
{
    public class UploadController : ApiController
    {
        private readonly IGrowthFacade _facade;
        #region Constructor
        public UploadController()
        {
            _facade = new GrowthFacade();
        }
        public UploadController(IGrowthFacade facade)
        {
            _facade = facade as GrowthFacade;
        }
        #endregion Constructor
        #region Public Methods
        ///
<summary>
        /// Upload Picture
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("api/Picture/Upload")]
        public HttpResponseMessage UploadPicture([FromBody] SchoolFileUploadModel model)
        {
            try
            {
                var entity = Mapper.Map<SchoolFileUploadModel, SchoolImage>(model);
                var response = _facade.CreateSchoolImage(entity);
                if (response.Status == ResultStatus.Success)
                {
                    var result = Mapper.Map<SchoolImage, SchoolFileUploadModel>(response.Data);
                    return Request.CreateResponse(HttpStatusCode.Created, result);
                }
                else
                {
                    return Request.CreateResponse(HttpStatusCode.BadRequest, model.ToString());
                }
            }
            catch (Exception ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
            }
        }
        #endregion Public Methods
    }
}

Config: WebApiConfig

Web API config is modified to add BSON media type formatter.

 public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            mapRoutes(config);
        }
        private static HttpConfiguration mapRoutes(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            //Binary JSON Formatter
            config.Formatters.Add(new BsonMediaTypeFormatter());
            return config;
        }