3

I need the user to be able to download png images from my site. When the mthod runs it completes without errors but no image is downloaded. I do not need the user to see a pop-up dialog thought it is certainly helpful. This is what I have right now:

public async Task<IActionResult> DownloadImage(string filename)
        {
            var path = Path.GetFullPath("./wwwroot/images/school-assets/" + filename);
           MemoryStream memory = new MemoryStream();
            using (FileStream stream = new FileStream(path, FileMode.Open))
            {
                await stream.CopyToAsync(memory);
            }
            memory.Position = 0;
            return File(memory, "image/png", "download");
        }

This method is called by an ajax call in the view that looks like this


        $.ajax({
            url: "./MyHome/DownloadImage",
            type: "Get",
            data: {filename : filename},
            success: function (file) {
            },
            error: function (request, status, error) {
                console.log(request.responseText);
            }
        });
    }

Edit: If i console.log file in the success portion i see a string of bytes so I know it is creating the file but not letting the user get to i. I have tried content disposition and creating a physical file result as suggested.

Caleb
  • 572
  • 1
  • 7
  • 25

5 Answers5

2

For File, you need to provide the file name with file extension, otherwise, the downloaded file will not be able to open.

Try something like

public async Task<IActionResult> DownloadImage(string filename)
{
    var path = Path.GetFullPath("./wwwroot/images/school-assets/" + filename);
    MemoryStream memory = new MemoryStream();
    using (FileStream stream = new FileStream(path, FileMode.Open))
    {
        await stream.CopyToAsync(memory);
    }
    memory.Position = 0;
    return File(memory, "image/png", Path.GetFileName(path));
}
Edward
  • 28,296
  • 11
  • 76
  • 121
  • I have made this using an ajax call in the view. When it runs I can print out the result into the console and see the string of bytes but no image dialog pops up to download it. HEre is the ajax example. ``` function DownloadImage(filename) { $.ajax({ url: "./MyHome/DownloadImage", type: "Get", data: {filename : filename}, success: function (file) { }, error: function (request, status, error) { console.log(request.responseText); } }); } ``` – Caleb Aug 06 '19 at 13:09
  • @Caleb If you want to download file by ajax, you need to implement the click event, try to refer [Download excel file with .Net core 2 and EPPlus](https://stackoverflow.com/questions/55231215/download-excel-file-with-net-core-2-and-epplus/55234666#55234666) – Edward Aug 07 '19 at 01:40
  • Thanks, will try this out when i get to work. Will give you the answer if it works – Caleb Aug 07 '19 at 12:47
1

You need to set the content dispositon type to enable direct downloading of the file :

public IActionResult OnGetPng()
{
    var bytes = System.IO.File.ReadAllBytes("test.png");

    var cd = new System.Net.Mime.ContentDisposition
    {
        FileName = "test.png",
        Inline = false
    };

    Response.Headers.Add("Content-Disposition", cd.ToString());
    Response.Headers.Add("X-Content-Type-Options", "nosniff");

    return File(bytes, "image/png");

}

If you prefer you can also make use of the PhysicalFileResult type which takes care of your stream and return FileResult from your controller. In that case your code looks like this:

   var fn = Path.Combine(env.WebRootPath, "test.png");

   var contentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");

   Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();

   return new PhysicalFileResult(fn, "image/jpeg");

To get access to the WebRootPath you have to inject IHostingEnvironment env into your constructor.

Postlagerkarte
  • 6,600
  • 5
  • 33
  • 52
0

@Caleb sir from below code you can download png file.

Download png file from folder

[HttpGet]
        public FileStreamResult DownloadPngFile(string fileName)
        {            
            var stream = new FileStream(Directory.GetCurrentDirectory() + "\\wwwroot\\images\\school-assets\\" + fileName, FileMode.Open);
            return new FileStreamResult(stream, "image/png");
        }

Download png file from database

   [HttpGet]
            public FileStreamResult DownloadPngFileFromDataBase(string id)
            {
                var _fileUpload = _db.ImageFileUpload.SingleOrDefault(aa => aa.fileid == id);         
                // _fileUpload.FileContent column type is byte
                MemoryStream ms = new MemoryStream(_fileUpload.FileContent);
                return new FileStreamResult(ms, "image/png");
            }

For more info please also see this question and answer. Download Pdf file in asp.net core (accepted answer) and one more extra link Download files in asp.net core

Nripendra Ojha
  • 379
  • 2
  • 14
0

This code can save photos from URL addresses in the server folder.

private readonly Lazy<HttpClient> _client;

In constructor:

_client = new Lazy<HttpClient>(() => clientFactory.CreateClient());

That is better to use lazy loading in a way the server will not spend additional resources to create HttpClient immediately.

public async Task<string> SavePhotoInFolder(string url)
        {
            string photoPath = $"/Photos/{Guid.NewGuid()}.jpeg";

            using (var request = new HttpRequestMessage(HttpMethod.Get, url))
            using (
                Stream contentStream = await (await _client.Value.SendAsync(request)).Content.ReadAsStreamAsync(),
                stream = new FileStream($"{_appEnvironment.WebRootPath}{photoPath}", FileMode.Create))
            {
                
                await contentStream.CopyToAsync(stream);
            }

            return photoPath;
        }
-1

You can use HttpClient

  using (var client = new HttpClient())
           {  
              try
              {
                using var result = await client.GetAsync($"http://{url}"); 
                if (result.IsSuccessStatusCode)
                {                        
                    return await result.Content.ReadAsByteArrayAsync();
                }

              }
             catch(Exception ex)
              {
                  Console.WriteLine(ex.InnerException);
              }
        } 
Omid Rahimi
  • 457
  • 4
  • 7