MVC 6 WebAPI returns serialized HttpResponseMessage instead of file stream

I am trying to get my ASP.Net 5 MVC 6 WebAPI project to output a file in response to an HttpGET request.

A file from the Azure Files share, but can be any stream containing a binary file.

It seems to me that MVC serializes the response object and returns the received JSON, rather than returning the response object itself.

Here is my controller method:

[HttpGet] [Route("GetFile")] public HttpResponseMessage GetFile(string Username, string Password, string FullName) { var client = new AzureFilesClient.AzureFilesClient(Username, Password); Stream azureFileStream = client.GetFileStream(FullName).Result; var fileName = Path.GetFileName(FullName); using (HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)) { response.Content = new StreamContent(azureFileStream); response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileName }; return response; } } 

The GetFileStream method on AzureFilesClient is present here, although the stream source can be any content from the binary:

  public async Task<Stream> GetFileStream(string fileName) { var uri = new Uri(share.Uri + "/" + fileName); var file = new CloudFile(uri, credentials); using (var stream = new MemoryStream()) { await file.DownloadToStreamAsync(stream); stream.Seek(0, SeekOrigin.Begin); return stream; } } 

Edit: Here is a sample JSON response:

 { "Version": { "Major": 1, "Minor": 1, "Build": -1, "Revision": -1, "MajorRevision": -1, "MinorRevision": -1 }, "Content": { "Headers": [ { "Key": "Content-Type", "Value": [ "application/octet-stream" ] }, { "Key": "Content-Disposition", "Value": [ "attachmentx; filename=\"samplefile.docx\"" ] } ] }, "StatusCode": 200, "ReasonPhrase": "OK", "Headers": [], "RequestMessage": null, "IsSuccessStatusCode": true } 
+6
source share
1 answer

After a combination of documentation to read, as well as some trial and error, the problems were resolved.

The laser part was made using the nuGet package "WindowsAzure.Storage" (4.4.1-preview)

First, the output received by JSON was serialized. This required that the result of the user action be returned.

 using Microsoft.AspNet.Mvc; using System.IO; using System.Threading.Tasks; public class FileResultFromStream : ActionResult { public FileResultFromStream(string fileDownloadName, Stream fileStream, string contentType) { FileDownloadName = fileDownloadName; FileStream = fileStream; ContentType = contentType; } public string ContentType { get; private set; } public string FileDownloadName { get; private set; } public Stream FileStream { get; private set; } public async override Task ExecuteResultAsync(ActionContext context) { var response = context.HttpContext.Response; response.ContentType = ContentType; context.HttpContext.Response.Headers.Add("Content-Disposition", new[] { "attachment; filename=" + FileDownloadName }); await FileStream.CopyToAsync(context.HttpContext.Response.Body); } } 

Now to get binary data transferred from an Azure share (or any other source of an asynchronous stream)

 using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.File; using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; public async Task<Stream> GetFileStreamAsync(string fileName) { var uri = new Uri(share.Uri + "/" + fileName); var file = new CloudFile(uri, credentials); // Note: Do not wrap the stream variable in a Using, since it will close the stream too soon. var stream = new MemoryStream(); await file.DownloadToStreamAsync(stream); stream.Seek(0, SeekOrigin.Begin); return stream; } 

And finally, the controller code. Pay attention to the use of the IActionResult interface.

  [HttpGet] [Route("GetFile")] public async Task<IActionResult> GetFile(string username, string password, string fullName) { var client = new AzureFilesClient.AzureFilesClient(username, password); Stream stream = await client.GetFileStreamAsync(fullName); string fileName = Path.GetFileName(fullName); return new CustomActionResults.FileResultFromStream(fileName, stream, "application/msword"); } 

Note. This example is used only in Word files. You might want to examine the dynamic parameter ContentType instead of the static type.

+6
source

Source: https://habr.com/ru/post/987208/


All Articles