1

I have a project that requires the multiple images to be stored in the wwwroot folder. The image references are saved in the database. So I've written a function that retrieves the image references, and loops through the images that are saved in the wwwroot folder.

So far, I am only able to retrieve the very first image in the folder. Unfortunately the other images are not being returned.

Below is the code:

  [HttpGet("images")]
        public IActionResult GetImages()
        {
            var results = _context.ImageTable.Select(i => i.ImageNames).ToList();

            foreach (var result in results)
            {
                var folderPath = Path.Combine(_hostingEnvironment.WebRootPath, "imagesFolder", $"{result}.png");

                var file= System.IO.File.ReadAllBytes(folderPath);

                return File(file, "image/jpg");
            }
            return NotFound("No Images");
        }


So what I'm expecting are all the images saved in the wwwroot folder to be displayed.
ArunPratap
  • 4,816
  • 7
  • 25
  • 43
Chris H.
  • 151
  • 3
  • 17
  • Usually 1 http request for 1 image except your client knows how to handle multiple images. I don't think you are working on a special client to do this, so returns 1 image per request. – shingo Apr 27 '19 at 06:16
  • I'm not sure I understand what you said. What I have is a list of image results which I'm iterating. I think it has to do with the return File which is within the foreach loop. That being said, I need a solution to help with my problem. – Chris H. Apr 27 '19 at 07:05
  • check this out: https://stackoverflow.com/questions/2953254/cgetting-all-image-files-in-folder – MoFarid Apr 27 '19 at 09:24
  • What are you trying to achieve here? Using `File` will return the actual contents of the file. Perhaps you want to render a list of images which are available with a link to the image file? – Henk Mollema Apr 27 '19 at 09:39
  • @HenkMollema Thank you for writing. What I'm trying to achieve is to render the images coming from the wwwroot folder. In my DB, the images are referenced as img01, img02, img03 etc. So in the method, I'm retrieving all images and attempting to display all of them in a browser. Hope that makes sense. – Chris H. Apr 27 '19 at 17:33
  • @MuhFred ugh...non of that helped me. I'm clueless right about now. All I want is to display all the images from the wwwroot folder. Right now I'm only getting 1 image. – Chris H. Apr 27 '19 at 18:58
  • OK let me ask a more simple question: **How do you receive these images?** If you just want to show them in a common browser, eg. with `` tag, and I've said in the previous comment: the browser can receive only 1 image per request. – shingo Apr 28 '19 at 02:54
  • @shingo the end result is to display them in a browser. I'm serving this to An angular application. Is there a better way to display all images at once from the wwwroot folder? – Chris H. Apr 28 '19 at 03:27
  • No in general, because the browser doesn't have a built-in feature, you need do more work if you want to show them **at once**. eg. Merge the images into one on server, or request the binary data then parse and create the images with javascript on the client. – shingo Apr 28 '19 at 03:46
  • @ChrisH. Since you want to display all the images in a browser, why not return a list of urls that makes the browser load the images automatically? – itminus Apr 29 '19 at 05:25
  • @itminus that is a good idea. However, I'm not sure how to go about doing that. How would I create url links for images stored in my wwwroot folder? – Chris H. Apr 29 '19 at 14:45

1 Answers1

1

Apprach 1 : Return an array of urls and use javascript to create a serial of img within browser:

public class HomeController : Controller
{
    private IHostingEnvironment _env;

    // inject a hosting env so that we can get the wwwroot path
    public HomeController(IHostingEnvironment env){
        this._env = env;
    }
    public IActionResult GetImages()
    {
        // get the real path of wwwroot/imagesFolder
        var rootDir = this._env.WebRootPath;
        // the extensions allowed to show
        var filters = new String[] { ".jpg", ".jpeg", ".png", ".gif", ".tiff", ".bmp", ".svg" };
        // set the base url = "/"
        var baseUrl = "/";


        var imgUrls = Directory.EnumerateFiles(rootDir,"*.*",SearchOption.AllDirectories)
            .Where( fileName => filters.Any(filter => fileName.EndsWith(filter)))
            .Select( fileName => Path.GetRelativePath( rootDir, fileName) ) // get relative path
            .Select ( fileName => Path.Combine(baseUrl, fileName))          // prepend the baseUrl
            .Select( fileName => fileName.Replace("\\","/"))                // replace "\" with "/"
            ;
        return new JsonResult(imgUrls);
    }
}

This will return something as below:

[
"/imagesFolder/avatar.jpg",
"/imagesFolder/avatar.png",
"/imagesFolder/subFolder/suit-portrait-preparation-wedding-copy.jpg",
"/imagesFolder/subFolder/woman-street-walking-girl.jpg",
"/imagesFolder/subFolder/subFoler2/pexels-photo-copy1.jpg",
"/imagesFolder/subFolder/subFoler2/road-fashion-vintage-bag-copy.jpg"
]

What you need is to send an ajax request to this action method and then create related <img src={url}> with these urls. Here's a working sample that uses plain javascript:

<script>
    var xhr = new XMLHttpRequest();
    xhr.onload=function(e){
        var urls=JSON.parse(e.target.responseText);
        for(var i = 0 ;i<urls.length;i++){
            var img = document.createElement("img");
            img.src = urls[i];
            document.body.appendChild(img);
        }
    };
    xhr.open("get","/home/getimages");
    xhr.send();
</script>

Approach 2 : Use Razor to render the view on server side:

Change the action method to return a View Result:

    public IActionResult GetImages()
    {
        // ...
        return new JsonResult(imgUrls);
        return View(imgUrls);
    }

Here' the GetImages.cshtml:

@model IEnumerable<string>

<ul>
    @foreach (var url in Model)
    {
        <li><img src="@url" alt="@System.IO.Path.GetFileName(url)"/></li>
    }
</ul>

Both should work.

itminus
  • 23,772
  • 2
  • 53
  • 88