How to Return Files From Web API

Prerequisite

  • Basic C# coding knowledge
  • Minimum knowledge of Web API
  • Understanding for the REST service

When we are working with REST service, it is very important to understand how to send files. In this article, we are going to discuss how to return files (PDF/Word/Excel) from Web API service.

I am going to explain a step by step process to transfer a file over Http REST service.

Let’s assume we have a requirement to send a file based on the file type provided to the service request. For example, when we send the file type as PDF, service will return PDF file if we send Doc, service will return Word document. (I have taken this sample to cover all types of files).

We cannot send the file from its original state. To send the file to REST service, we have to follow the below steps.

Convert the Required file into Bytes

Initially, we have to convert the file into bytes using File Class (which is from System.IO)

//converting Pdf file into bytes array  
var dataBytes = File.ReadAllBytes(reqBook);

Adding bytes to MemoryStream

Now, create an instance of MemoryStream by passing the byte form of the file.

//adding bytes to memory stream   
var dataStream = new MemoryStream(dataBytes);  

Adding MemoryStream object to the HttpResponseMessage Content

The final step is to add the MemoryStream object to the HttpResponseMessage Content as follows.

httpResponseMessage.Content = new StreamContent(bookStuff); 

Other Mandatory Changes for HttpResponseMessage Headers

We are returning a file here so, to make the client understand the content of the service, we have to modify the following HttpResponseMessage header properties.

  • ContentDisposition
  • FileName
  • ContentType

Following code is used to implement the above 3 fields. 

httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");  
httpResponseMessage.Content.Headers.ContentDisposition.FileName = PdfFileName;  
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); 

We need to talk about the ContentType here. I have used application/octet-stream, whereas in some places, we can see application/pdf, but why I have used it? In a simple way, I can say that when we are sending a file to the REST service and we don’t know the file type but it is a trusted one, in these situations, we have to use application/octet-stream.

Complete Code in a single shot

I have written with IHttpActionResult and HttpResponseMessage action results.

public class EbookController : ApiController  
{  
    string bookPath_Pdf = @"C:\MyWorkSpace\SelfDev\UserAPI\UserAPI\Books\sample.pdf";  
    string bookPath_xls = @"C:\MyWorkSpace\SelfDev\UserAPI\UserAPI\Books\sample.xls";  
    string bookPath_doc = @"C:\MyWorkSpace\SelfDev\UserAPI\UserAPI\Books\sample.doc";  
    string bookPath_zip = @"C:\MyWorkSpace\SelfDev\UserAPI\UserAPI\Books\sample.zip";  

    [HttpGet]  
    [Route("Ebook/GetBookFor/{format}")]  
    public IHttpActionResult GetbookFor(string format)  
    {  
        string reqBook = format.ToLower() == "pdf" ? bookPath_Pdf : (format.ToLower() == "xls" ? bookPath_xls : (format.ToLower() == "doc" ? bookPath_doc : bookPath_zip));  
        string bookName = "sample." + format.ToLower();  

        //converting Pdf file into bytes array  
        var dataBytes = File.ReadAllBytes(reqBook);  
        //adding bytes to memory stream   
        var dataStream = new MemoryStream(dataBytes);  
        return new eBookResult(dataStream, Request, bookName);  
    }  
    [HttpGet]  
    [Route("Ebook/GetBookForHRM/{format}")]  
    public HttpResponseMessage GetBookForHRM(string format)  
    {  
        string reqBook = format.ToLower() == "pdf" ? bookPath_Pdf : (format.ToLower() == "xls" ? bookPath_xls : (format.ToLower() == "doc" ? bookPath_doc : bookPath_zip));  
        string bookName = "sample." + format.ToLower();  
        //converting Pdf file into bytes array  
        var dataBytes = File.ReadAllBytes(reqBook);  
        //adding bytes to memory stream   
        var dataStream = new MemoryStream(dataBytes);  

        HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);  
        httpResponseMessage.Content = new StreamContent(dataStream);  
        httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");  
        httpResponseMessage.Content.Headers.ContentDisposition.FileName = bookName;  
        httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");  

        return httpResponseMessage;  
    }  
}  

public class eBookResult : IHttpActionResult  
{  
    MemoryStream bookStuff;  
    string PdfFileName;  
    HttpRequestMessage httpRequestMessage;  
    HttpResponseMessage httpResponseMessage;  
    public eBookResult(MemoryStream data, HttpRequestMessage request, string filename)  
    {  
        bookStuff = data;  
        httpRequestMessage = request;  
        PdfFileName = filename;  
    }  
    public System.Threading.Tasks.Task<HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken)  
    {  
        httpResponseMessage = httpRequestMessage.CreateResponse(HttpStatusCode.OK);  
        httpResponseMessage.Content = new StreamContent(bookStuff);  
        //httpResponseMessage.Content = new ByteArrayContent(bookStuff.ToArray());  
        httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");  
        httpResponseMessage.Content.Headers.ContentDisposition.FileName = PdfFileName;  
        httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");  

        return System.Threading.Tasks.Task.FromResult(httpResponseMessage);  
    }  
}

Result

I ran the project and tried to download all the books in all formats with the following URLs (your IP may change when you run the code on your system).

  • http://localhost:59217/api/Ebook/GetBookFor?format=pdf
  • http://localhost:59217/api/Ebook/GetBookFor?format=doc
  • http://localhost:59217/api/Ebook/GetBookFor?format=xls
  • http://localhost:59217/api/Ebook/GetBookFor?format=zip

Initially, I have sent the PDF format value to the service and got the PDF file in response.

Later, I requested the Word document.

How to execute the attached source code (Please go through this section if you want to practice this article with the attached project)

I have attached only required files with the actual folder structure (due to the size of the project).

Please follow the below steps to create the file transferrable Web API service.

  • Download the attached project.
  • Open Visual Studio and create New Web API project.
  • Create Book folder at root level in the project.
  • Add any sample pdf, word, excel, zip (name them as sample) files into it.

    C#
     
  • Create a new API controller and Copy the content of EbookController from the downloaded project into it.
  • Please change the books path strings in newly created Controllers.
  • Add the following code to WebAPIConfig.cs 
    config.Routes.MapHttpRoute(
       name: "FileServiceRoute”,  
       routeTemplate: “api / {controller}/{action}/ {id}”,
       defaults: new {id = RouteParameter.Optional}
    ); 
  • Rebuild the project and run.
  • Run any of the above URLs with your project IP

You can see downloading of files when you run the URLs.


Similar Articles