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 Required file into Bytes
Initially, we have to convert the file into bytes using File Class (which is from System.IO)
-
- var dataBytes = File.ReadAllBytes(reqBook);
Adding bytes to MemoryStream
Now, create an instance of MemoryStream by passing the byte form of the file.
-
- 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 HeadersWe 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();
-
-
- var dataBytes = File.ReadAllBytes(reqBook);
-
- 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();
-
- var dataBytes = File.ReadAllBytes(reqBook);
-
- 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.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.
- 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.