0

I have a Web Api controller, that gets file. (Server)

[HttpGet]
    [Route("api/FileDownloading/download")]
    public HttpResponseMessage GetDocuments()
    {
        var result = new HttpResponseMessage(HttpStatusCode.OK);

        var fileName = "QRimage2.jpg";
        var filePath = HttpContext.Current.Server.MapPath("");
        var fileBytes = File.ReadAllBytes(@"c:\\TMP\\QRimage2.jpg");
        MemoryStream fileMemStream = new MemoryStream(fileBytes);

        result.Content = new StreamContent(fileMemStream);

        var headers = result.Content.Headers;

        headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");

        headers.ContentDisposition.FileName = fileName;

        headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

        headers.ContentLength = fileMemStream.Length;

        return result;
    }

And Xamarin Android client, that downloading the file using the controller (http://localhost:6100/api/FileDownloading/download)

public void DownloadFile(string url, string folder)
    {
        string pathToNewFolder = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, folder);
        Directory.CreateDirectory(pathToNewFolder);

        try
        {
            WebClient webClient = new WebClient();
            webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
            string pathToNewFile = Path.Combine(pathToNewFolder, Path.GetFileName(url));
            webClient.DownloadFileAsync(new Uri(url), null);
        }
        catch (Exception ex)
        {
            if (OnFileDownloaded != null)
                OnFileDownloaded.Invoke(this, new DownloadEventArgs(false));
        }
    }

Everithing works fine, but on my Android device in file explorer i have file with "download" file name instead of "QRimage2.jpg". How can I get actual file name using this controller?

2 Answers 2

1

You will need use the web response to read the content disposition. So, we can't use DownloadFileAsync directly.

public async Task<string> DownloadFileAsync(string url, string folder)
{
    var request = WebRequest.Create(url);
    var response = await request.GetResponseAsync().ConfigureAwait(false);
    var fileName = string.Empty;

    if (response.Headers["Content-Disposition"] != null)
    {
        var contentDisposition = new System.Net.Mime.ContentDisposition(response.Headers["Content-Disposition"]);

        if (contentDisposition.DispositionType == "attachment")
        {
            fileName = contentDisposition.FileName;
        }
    }

    if (string.IsNullOrEmpty(fileName))
    {
        throw new ArgumentException("Cannot be null or empty.", nameof(fileName));
    }

    var filePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, folder, fileName);

    using (var contentStream = response.GetResponseStream())
    {
        using (var fileStream = File.Create(filePath))
        {
            await contentStream.CopyToAsync(fileStream).ConfigureAwait(false);
        }
    }

    return filePath;
}
Sign up to request clarification or add additional context in comments.

Comments

0

Is this always going to be a jpg? If so I'd change the MediaTypeHeaderValue to image/jpeg - By doing that you are telling the browser the exact type of file, instead of a generic file. I'm thinking this is the issue since you are telling the Android Browser it's just a generic binary file.

Do I need Content-Type: application/octet-stream for file download?

1 Comment

It can be any type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.