Download Binary from WebApi2 As File. Server Side

asp.net asp.net-web-api2 binaryfiles c# entity-framework-6

Question

I've looked a couple of answers on here but still having an issue.
One system is saving a binary byte[] into SQL 2014 with Entity Framework 6.

I have a "name" of the record (not the file) but I want to serve up the binary data as a downloadable file via the webapi2. I have it somewhat working but on the browser it shows the ID as the file name and says can't download file. It is prompting to download but then it can't.

Right now for PoC I'm hard coding the mime type to word docs. What am I doing wrong and how should I refactor this to also provide a file name.

I'm saving the document using Office Apps, Task Pane:

https://msdn.microsoft.com/en-us/library/office/jj715284.aspx

FileType: "Compressed" = Returns the entire document (.pptx or .docx) in Office Open XML (OOXML) format as a byte array.

Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
            function (result) {
                if (result.status === Office.AsyncResultStatus.Succeeded) {
                    vm.data.data = result.value;
                    //I call a angularJs service which post..
                   //return $http.post('https://stapi.local:8443/api/activities', vm.data);

                } else {

                }
            }
        );

Then I try to let a user download the document with the following.

WebAPI2 Controller:

[HttpGet, Route("api/activityObjectFile/{id}/{name}")]
        public HttpResponseMessage GetDataFile(int id)
        {
            var fileByte = _activityService.GetFile(id);
            HttpResponseMessage response = new HttpResponseMessage { Content = new StreamContent(new MemoryStream(fileByte))};
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/msword");
            response.Content.Headers.ContentLength = fileByte.Length;
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment filename=test.docx");

            return response;
        }

Class Service Library:

public Byte[] GetFile(int id)
        {
            var existingActivityObjectFile = _repo.QueryAll<ActivityObject>().Where(a => a.Id == id).Select(a => a.BinaryData).First();

            return existingActivityObjectFile;
        }

Client Url:

<a href="http://stapi.local/api/activityObjectFile/14">Download</a>
1
1
8/4/2015 8:23:34 PM

Popular Answer

This should get you going for now:

var response = new HttpResponseMessage(HttpStatusCode.OK) 
{ 
   Content = new StreamContent(new MemoryStream(fileByte))        
};
response.Content
        .Headers
        .Add("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") 
{ 
   FileName = "test.docx" 
};
return response;

As for suggestions for refactoring, you could use my method.

I have an implementation of the IHttpActionResult that I return, it looks like this:

public class DocumentAttachmentResult : IHttpActionResult {
    private readonly string fileName;
    private readonly string mimeType;
    private readonly byte[] blob;

    public DocumentAttachmentResult(string fileName, string mimeType, byte[] blob) {
        this.fileName = fileName;
        this.mimeType = mimeType;
        this.blob = blob;
    }

    private HttpResponseMessage Execute() {
        var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(new MemoryStream(this.blob)) };
        response.Content.Headers.Add("Content-Type", this.mimeType);
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = this.fileName };
        return response;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
        return Task.FromResult(this.Execute());
    }
}

And my controller action looks like this:

    [HttpGet]
    [Route("attachments/{id:guid}/download")]
    public IHttpActionResult DownloadAttachment(Guid id) {
        var attachment = this.repository.FindById(id);
        if (attachment == null) {
            return this.NotFound();
        }
        return new DocumentAttachmentResult(attachment.Name, attachment.FileType.MimeType, attachment.BinaryBlob);
    }

I store the file name, mime type and binary in SQL server have it modeled as one entity called Attachment. The mime type and file is captured when I upload a file using another action on my WebApi controller.

1
8/4/2015 7:19:21 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow