ASP.NET WEB API: Consuming Binary Contents (Images)

Posted by: Mahesh Sabnis , on 4/21/2015, in Category ASP.NET
Views: 104197
Abstract: Implement a simple ASP.NET WEB API containing the action method returning byte array (image) through HttpResponseMessage object

HTTP is simple and ubiquitous in nature and almost any platform has a HTTP Library. ASP.NET Web API is a web framework built on top of the .NET framework and can be used to build or consume HTTP services. Since Web API implements the HTTP specification, it is a great fit in the overall picture of modern web applications.

The capability of consuming HTTP requests from a broad range of clients, including desktop, browsers and mobile devices is a major feature of WEB API. Most of the client applications perform JSON data read write operations from and to with WEB API. But what if a client expects data other than JSON format from WEB API? For instance consider that we are using a HTML client with jQuery. This client wishes to make a call to WEB API and read images (binary data) from the server side. Question here is how do we implement this in Web API?

 

The WEB API framework makes use of HttpRequestMessage and HttpResponseMessage objects. The HttpResponseMessage object can be customized and can be used to define the format of the data to be sent. The HttpResponseMessage object can be set with the Content property where we can set the content for the response message. This object allows to define response header content type with MediaTypeHeaderValue object. The MediaTypeHeaderValue, can be used to define media type value e.g. octet-stream, image/jpeg, etc.

In the following article, we will implement a simple ASP.NET WEB API containing the action method returning byte array through HttpResponseMessage object.

Step 1: Open the Free Visual Studio 2013 Community Edition (or any VS 2013/2015 edition of your choice) and create a new Empty WEB API project of the name ‘WebAPI_BinaryContent’. In this project add a new folder of the name images. Add some images in this folder.

Step 2: In the Models folder add the following class file to represent an organized storage for files.

public class FilesInfo
{
    public string FileName { get; set; }
}

Step 3: In this project, add an empty WEB API controller of the name ByteArrayAPIController. In this controller, add the following code:

using WebAPI_BinaryContent.Models;


namespace WebAPI_BinaryContent.Controllers
{
    /// <summary>
    /// Controller used to return Byte Array to the Requester
    /// </summary>
    
    public class ByteArrayAPIController : ApiController
    {
        string rootPath;

        public ByteArrayAPIController()
        {
            //The Path of the Image store on the server side
            rootPath = HostingEnvironment.MapPath("~/images/");
        }

        /// <summary>
        /// Return all files to the client
        /// </summary>
        /// <returns></returns>

        [Route("Files")]
        public List<FilesInfo> GetFiles()
        {
            List<FilesInfo> files = new List<FilesInfo>();

            foreach (var item in Directory.GetFiles(rootPath))
            {
                FileInfo f = new FileInfo(item);
                files.Add(new FilesInfo(){FileName=f.Name});  
            }
            return files;
           
        }

        /// <summary>
        /// Return the image as Byte Array through the HttpResponseMessage object  
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="ext"></param>
        /// <returns></returns>
        [Route("Bytes/{fileName}/{ext}")]
        public HttpResponseMessage Get(string fileName,string ext)
        {
            //S1: Construct File Path
            var filePath = Path.Combine(rootPath, fileName+"."+ext);
            if (!File.Exists(filePath)) //Not found then throw Exception
                throw new HttpResponseException(HttpStatusCode.NotFound);

            HttpResponseMessage Response = new HttpResponseMessage(HttpStatusCode.OK);

            //S2:Read File as Byte Array
            byte[] fileData = File.ReadAllBytes(filePath);

            if (fileData==null) 
                throw new HttpResponseException(HttpStatusCode.NotFound);
            //S3:Set Response contents and MediaTypeHeaderValue
            Response.Content = new ByteArrayContent(fileData);
            Response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
             
            return Response;
        }
    }
}

The above class performs the following operations:

  • The constructor reads the folder where all binary files are stored.
  • The GetFiles() action method reads all files from the server side binary file from the images folder and stores in the List of the FilesInfo class created in Step 2.
  • The Get() action method accepts two string parameters. These parameters are FileName and Extension respectively. This action method performs the following steps:
    • S1: Constructs the file path from the input parameters and verifies the file exists on the server. If file does not exist, an exception is thrown.
    • S2: Reads the file as byte array.
    • S3: Sets the byte array as HttpResponseMessage content using ByteArrayContent object. This step sets the Header Content type as MediaTypeHeaderValue with octet-stream.
  • In this ApiController class, both actions are applied with the Attribute Routing using RouteAttribute class.
    • GetFiles() is applied with [Route(“Files”)].
    • Get() is applied with [Route(“Bytes/{fileName}/{ext}”)]

 

Step 4: In the Controllers folder, add a new Empty MVC controller of the name ‘TestController’. This will add a controller class with Index() action method and RouteConfig.cs file in App_Start folder. Scaffold an empty view from this action method. Note that since we have created Empty WEB API project, we need to register the MVC Routing in the Global.asax as shown in the following code: (highlighted)

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

One important point here, is that in the RouteConfig.cs file the route expression will not have {controller} parameter. We need to add this parameter explicitly.

Step 5: In the project add jQuery, Knockout and Bootstrap libraries. In the Index.cshtml add the following JavaScript and HTML

@{
    ViewBag.Title = "Index";
}

<h2>List of Files</h2>

<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-2.1.3.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/knockout-3.3.0.js"></script>

<table class="table table-bordered table-striped table-condensed">
    <tr>
        <td>
            <table class="table table-bordered table-striped table-condensed">
                <thead>
                    <tr>
                        <td>File Name</td>
                    </tr>
                </thead>
                <tbody data-bind="foreach:Files">
                    <tr data-bind="click:$root.selectFile">
                        <td>
                            <span data-bind="text:FileName"></span>
                        </td>
                    </tr>
                </tbody>
            </table>
        </td>
        <td>
            <img data-bind="attr:{'src':imagePath}" class="img-rounded" style="height:400px;width:400px"/>
        </td>
    </tr>
</table>

 

<script type="text/javascript">
    //The View Model
    var vm = function () {

        var self = this;
        
        self.Files = ko.observableArray([]);
        self.Message = ko.observable("");
        self.imagePath = ko.observable("");


        loadFiles();

        //Function to Load all files
        function loadFiles() {
            $.ajax({
                url: "http://localhost:35806/Files",
                type:"GET"
            }).done(function (resp) {
                self.Files(resp);
            }).error(function (err) {
                self.Message("Error " + err.status);
            });
        }

        //Function gets execeuted when 

        self.selectFile = function (fileName) {
            var names = fileName.FileName.split('.');
            self.imagePath("http://localhost:35806/Bytes/" + names[0] + "/" + names[1]);
        }

    };
    ko.applyBindings(new vm());
</script>

The above JavaScript defines knockout.js view model. The loadFiles() function makes an Ajax call to WEB API to load all the files. These files will be displayed in the HTML table. The selectFile() function will be executed when any row from the table showing files, is clicked. The file name will be split into name and its extensions, and will then be passed to WEB API. As the response from the WEB API, the byte array in the image form will be displayed in HTML image.

Run the application and the list of files will be displayed as following:

aspnet-webapi-formats

Click on any file name and the following result will be displayed:

webapi-binary

Conclusion: ASP.NET WEB API can have more effective uses for various types of response formats by customizing the HttpResponseMessage object.

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @maheshdotnet or connect with him on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Lyubomyr Vyhovskyy on Wednesday, April 29, 2015 3:05 AM
Good article.
It would be nice to see how to handle all this when your WebApi is secured (need to use Bearer token) and hosted on different origin than the client (CORS requests).
Comment posted by Wakil on Wednesday, May 6, 2015 12:42 AM
Hi its fantastic article. I have learned a lot from many of your articles. Thank you again and keep up the good work