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.
You can see downloading of files when you run the URLs.