0

Was trying to download an mp3 file in a browser through the API that I created. But instead of receiving an mp3 file. I keep getting JSON format response. I had referred from answer in return-file-in-asp-net-core-web-api, but still, I can't download the mp3 file. Is there any mistake that I've overlooked, please kindly help?

This is my downloading method from UI

void DownloadRecording(RecordingHistory voicehistory)
{
      try
      {
          using (var client = new WebClient())
          {
              client.DownloadFile("https://2d489fd863a2.ngrok.io/api/download/" + voicehistory.RecordingId + ".mp3", voicehistory.RecordingId + ".mp3");
          }

      }
      catch { }
}

This is my api function for downloading mp3 from server

 [HttpGet("download/{recordingFile}")]
 public async Task<IActionResult> DownloadVoiceRecording(string recordingFile)
 {
      string filePath = Directory.GetCurrentDirectory() + @"\audio\Processed\" + recordingFile;
      var memory = new MemoryStream();
      using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
      {
           await stream.CopyToAsync(memory);
      }
      memory.Position = 0;
      var types = GetMimeTypes();
      var ext = Path.GetExtension(filePath).ToLowerInvariant();

      return File(filePath, types[ext], recordingFile);
      }

      private Dictionary<string, string> GetMimeTypes()
      {
          return new Dictionary<string, string>
          {
              {".mp3", "audio/mpeg"},
              {".wav","audio/wav" }
          };
      }

This is the response I get from browser and Postman

{
    "Version": "2.0.0.0",
    "StatusCode": 200,
    "Message": "Status 200 OK",
    "Result":"��@� ... ... /// A lot of random symbol here
}
J.J
  • 13
  • 1
  • 6

2 Answers2

0

Because the first parameter of the return value File is a type of Stream, memory needs to be passed in.

[HttpGet("download/{recordingFile}")]
    public async Task<IActionResult> DownloadVoiceRecording(string recordingFile)
    {
        
        string filePath = Directory.GetCurrentDirectory() + @"\audio\Processed\" + recordingFile;
        var memory = new MemoryStream();
        using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            await stream.CopyToAsync(memory);
        }
        memory.Position = 0;
        var types = GetMimeTypes();
        var ext = Path.GetExtension(filePath).ToLowerInvariant();
        return File(memory, types[ext], recordingFile);
    }
Karney.
  • 4,803
  • 2
  • 7
  • 11
  • Hi Karney, I think I've already passed in the stream using CopyToAsync(memory). Or do you mean to read the Stream from WebClient? – J.J Nov 16 '20 at 14:57
  • Yes, it returns the stream through `File`, not a string. – Karney. Nov 17 '20 at 01:13
  • oh, I know what you mean. I've tested the way you suggested. But it still returns me the JSON format instead of the file, thank you for the help btw. I'm using Blazor, so I'm thinking to check the API configuration in the blazor. – J.J Nov 18 '20 at 01:07
  • May be due to blazor`s data type? – Karney. Nov 18 '20 at 01:21
  • It was due to Blazor has a API Response wrapper, I had to put my API into exception so it wont change my content into JSON. :D Thank for your help! – J.J Nov 18 '20 at 01:32
0

I'm using Blazor for this. It turns out that there was an API response wrapper in Blazor APIReponse middleware. I had to put my API into an exception so it won't turn into JSON when I access it. It works finally.

Below is the APIReponse wrapper in Blazor.

var formattedRequest = await FormatRequest(request);
                    var originalBodyStream = httpContext.Response.Body;

                    using (var responseBody = new MemoryStream())
                    {
                        try
                        {
                            string responseBodyContent = null;

                            var response = httpContext.Response;

                            if (new string[] { "/api/localization", "/api/data", "/api/externalauth", "/api/download" }.Any(e => request.Path.StartsWithSegments(new PathString(e.ToLower()))))
                                await _next.Invoke(httpContext);
                            else
                            {
                                response.Body = responseBody;

                                await _next.Invoke(httpContext);

                                //wrap response in ApiResponse
                                if (httpContext.Response.StatusCode == Status200OK)
                                {
                                    responseBodyContent = await FormatResponse(response);
                                    await HandleSuccessRequestAsync(httpContext, responseBodyContent, Status200OK);
                                }
                                else
                                    await HandleNotSuccessRequestAsync(httpContext, httpContext.Response.StatusCode);
                            }
J.J
  • 13
  • 1
  • 6