This short walk-through is intended for those who work with WebApi and want to perform file download using Knockout or JQuery.
While working on a project that uses Knockout.js for front end scripting and Asp.Net Web API as back-end service layer, we had to implement file downloading functionality using Ajax.
Lets Code
[HttpGet] //Returns FileStream if file exists
public HttpResponseMessage DownloadDocument(string fileUrl)
{
try
{
Stream stream = FileHelper.GetFilesStream(fileUrl);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK)
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition.FileName = "fileNameOfYourChoice";
return result;
}
catch (NotFoundException exception)
{
Request.CreateErrorResponse(HttpStatusCode.NotFound, "File Not Found");
}
catch (Exception exception)
{
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, exception.Message);
}
}
This method in Api returns a FileStream, sets ContentDisposition and ContentType to tell browser the type of content is a file and browser popups save file dialog. GetFileStream method is defined in a Helper class that just converts a file into filestream
public class FileHelper
{
public static Stream GetFilesStream(string fileUrl)
{
if (File.Exists(fileUrl))
{
return new FileStream(fileUrl, FileMode.Open);
}
throw new NotFoundException("File not found");
}
}
Knockout Devs
Knockout developers have to create a view and a viewModel. The viewModel will expose a caller for API while the view will simply have an anchor tag which will have its click event bound to viewModel’s funtion.
ViewModel will have the following caller function
this.downloadDocument = function(attachment) {
var resourceUri = '/api/Documents/DownloadDocument?fileUrl = ' + attachment.fileUrl;
window.href.location = resourceUri;
};
While the view’s anchor tag will look like
<a href = "" data-bind= "click: $parent.downloadDocument" > Download </a>
JQuery Devs
<a href="'/api/Documents/DownloadDocuments? fileUrl = location\\my_file.asm" />