I am building a website using ASP.NET MVC4 to upload/display images and found a few ways of how to display images, chiefly the below -
1) Store the image as a file locally on the server and use a relative path to display it on the page.
//ImageFile is a property which holds a path to the image in the model
<img src="@item.ImageFile" />
When the page is rendered, this becomes a path like - <img src="/Content/Images/Jellyfish.jpg" />
2) Store the image as a byte array and retrive it using a controller action -
//Use a controller action (GetImg) to get the URL of the image
<img src="@Url.Action("GetImg", "ViewPhotos", new { id = item.ID })" alt="Image" />
When the page is rendered, this becomes a path like - <img src="/ViewPhotos/GetImg/4" alt="Image" />
3) Store the image as a byte array and retrive it in the view directly -
//Directly re-construct the image in the view from the byte array (Image property of the model)
<img src="@String.Format("data:image/jpg;base64,{0}", Convert.ToBase64String(item.Image))" />
When the page is rendered, this becomes a path like - <img src="data:image/jpg;base64,/9j/4AAQSkZJRgABAgEA....<long string> .../>
My questions are -
1) What is the difference between 1 and 2 ?
1 directly provides the path to file and 2 provides a URL to it. Are they the same in the background or is one approach better than the other?
I have checked here and it says that - Url.Action will construct the path to the action, returning a url, not the results of executing the action. So when are are results retrieved?
2) Does it makes a performance impact when 3 is used against 1 or 2?
3) Which approach should be used when image sizes are small (less than 1MB) or large ?
Happy if you can point to me any links which can be of help as well. Thanks.
Code -
//Model
public class Photo
{
public int ID { get; set; }
public string ImageFile { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
}
//Controller
public FileContentResult GetImg(int id)
{
byte[] byteArray = db.Photos.Find(id).Image;
if (byteArray != null)
{
return new FileContentResult(byteArray, "image/jpeg");
}
else
{
return null;
}
}
//View (approach 2)
@model IEnumerable<MyPhotoLibrary.Models.Photo>
@foreach (var item in Model) {
<tr>
<td>
<img src="@Url.Action("GetImg", "ViewPhotos", new { id = item.ID })" alt="Image" />
</td>
</tr>
}
//View (this is approach 3)
@model IEnumerable<MyPhotoLibrary.Models.Photo>
@foreach (var item in Model) {
<tr>
<td>
<img src="@String.Format("data:image/jpg;base64,{0}", Convert.ToBase64String(item.Image))" />
</td>
</tr>
}
In ASP.NET MVC, ViewModel is a class that contains the fields which are represented in the strongly-typed view. It is used to pass data from controller to strongly-typed view.
I looked this up myself recently, and came across the Microsoft research paper To BLOB Or Not To BLOB, which compares the performance of storing files (such as images) as binary data in a database to that of a conventional filesystem.
The findings, roughly summarised:
Other differences between the options:
Option 1 requires your application to have read permissions on whichever folder the images are in, and if the images are being uploaded or edited by users, then the application will need write permissions on that folder as well. This may be tricky if you're on shared hosting (especially on cheap or free hosting plans) or if your sysadmin is particularly paranoid.
Option 2 requires more calls from client to server to get all the data; this may look like a bad thing but it does break up the pageload into chunks which might actually help - the page (without images) will load on the first call, and then the images will be requested separately, If one of them takes a while, or has some sort of error, then the rest of the page should be unaffected, which is nice. As jgauffin pointed out in the comments, this option allows you to set up caching for the images, so browsers can save bandwith by only re-downloading them when they've changed.
Option 3 requires the client to load the whole lot in one, which may take a while. It also shifts the processing of the byte array onto the client, which may be a problem on low-powered clients like smartphones or low-end netbooks. If your images are large it may be better to use the server's CPU power to actually handle the conversion from byte array to image file. As jgauffin notes in the comments, this also doesn't play nicely with caching - if any part of the view's HTML changes, browsers will have to download the images again
Also, this may not be relevant to your specific situation but having the images loaded by a separate call lets you do other things in those actions, like writing to debug logs or doing some other housekeeping behind the scenes.
1) will have less processing on the server-side, as there will be less function calls. if you want to render the output of the action - you need to call HTML helper method Html.RenderAction or Html.Action more on the differences here
2) the difference between 2 and 3 is that when you input the byte array directly, you have less round trips to the server (DNS look-ups and such), but more data to download in a single request. Some browsers, may download content in parallel (5-8 parallel downloads per domain), so if you use 3, you loose in terms of page loading speed. more on paralel downloads here and here
and that leads us to 3) if you have small images, 3 is the way to go, as the client will request less resources, and the page will load faster, but if you have large images, you should use 1.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With