Resizing / caching JPEG images on Azure - c#

I have a website written in .NET 4.5 / MVC 4 that allows users to upload images, among other things. These images can be displayed throughout the site in a variety of sizes. Currently, the way this works is as follows:
The image is uploaded and re-sized in memory to a max width of 640px (the largest the site will display).
The resized image is saved to disk at /assets/photos/source/{id}-{timestamphash}.jpg.
When a request for the image in various sizes comes through, I get the filename by combining {id}-{hash} where {hash} is the hash of a combination of ids, height, width and some other information I need to get the image.
If that image exists in /assets/photos/cache, I simply return it, otherwise I create it in memory using the source image and then save it to the cache directory.
I like this approach because it happens quickly and it all happens in-memory or via disk retrieval.
I'd like to eventually move my site to Azure. How would a workflow like this happen in Azure given that all of my images would be stored as blobs? Is it still efficient to use a re-sizing/caching strategy like this or are there other alternatives? Wouldn't you incur network latency as the image is uploaded to Azure from the server where today, it just gets saved to disk which is obviously a lot faster?
Just looking for some direction on how to migrate a workflow like this to something workable and scalable with Azure.

Given your comment above, why not create a background task that resizes to all acceptable sizes on upload, storing each one into the Azure blob storage. You are correct that if you resize on request, you would suffer some latency and lag as you would need to download the source image, resize, then upload to blob storage, then redirect the user to your blob storage url. Given the 'cheapness' of blob storage, I would submit that paying a few dimes more for extra storage would outweight the potential slowness of the scenario above.
Pseudo Code Below:
[HttpPost]
public ActionResult FileUpload(HttpPostedBaseFile file){
if(ValidateFile(file)){
//fire off a background tasks that resizes and stores each file size to the azure
//blog storage. You could use a naming scheme such as id_size.imageTypeExtension
}
}
Now, when asked for a file, you could still use your same routine, but instead of returning a file result, you would return a redirect result
public ActionResult GetImage(string hash){
//do stuff to get image details
return Redirect("http://yourAzureBlobStorageDomain.com/Assets/Images/Cache/" + imageDetails")
}
This is cool because you don't need to download the image to your web server and then serve it, but simply redirect the request directly to the blob storage! This would have the affect that an image tag such as below
<img src="#Url.RouteUrl("GetImage", "Images" new {hash = hash})"/> would hit your web application, forcing a redirect to the actual image location in blob storage.
You are correct that you do not want to store anything on the Azure web role permanently as the web roles can be moved around at any time, losing any locally stored data.
This is just a simple way to sort of keep your code base the way it is now with minimal changes. You could modify this to behave more like what you have now in that you could query the blob storage if an image exists, if it does, redirect, if it does not then generate, store and redirect, but I believe you would find you will have more issues with the latency at this point given you would need to download the source image, do your stuff and then reupload the image before instructing the user's browser where to go find it.
However, this would be something for you to decide if it was worth the extra time it would take to resize on demand vs the cost of storing multiple sizes of each image. As a side note, we have not noticed a significant latency issue when using blob storage from our web/worker roles. Obviously it is higher than retrieval from disks, but it has not really posed a significant increase that we have been able to see.

Related

How to insert images into database using asp.net core mvc 6?

I'm trying to create a website. But i don't know how to upload photos into database. All information is outdated
If the size of your images are small, then you can convert it to base64, and store in your DB.
If the size is very larger, then you will face some issue.
The correct way to save pictures and Images
If the images are static resouce, and you can store it under wwwroot. Due to it will not often update, you can save it here.
If the images are create by web user, you also can follow the first suggestion, and create folder like wwwroot/userdata/userid/, and the path like wwwroot/userdata/userid/xx.jpg. The main disadvantage is that it is not conducive to maintenance.
The disadvantage is that the published files under wwwroot will become larger and larger, and the pressure on the web server will also increase, when many users access operations.
The best choice you can store images to storage account or other third party service.
In this way, our database only needs to save the path. Conducive to the maintenance of images data. There will be no stress on the web server during access and operation.

How to add images in db?

Currently working in an intern project, where i am required to add an image when adding an employee in my table.
we are using angularJS in front end and asp.net core 3.1 in backend, we have sql database using SSMS, i couldnt get it how to upload images, my senior told me to store the path in db, if i am to store the path in db, where will my images be uploaded, i did upload the images making an api on wwwroot folder, but they marked it as a bad practice? So can any of you guide me? Thankyou in advance :)
Steve's Comment is useful. You can upload image to the new folder under the wwwroot. You can refer the blog fisrt, it create a Resources folder, and it also use angular.
In general, we still do not recommend storing pictures under wwwroot. Regardless of whether you create a subfolder such as Sources.
Reason:
As the business increases, or over time, the contents under the folder will definitely increase. Even if the hard disk space at the deployment site is large, it will cause subsequent maintenance problems.
Specifically, the picture file may be accidentally deleted and cannot be recovered subsequently. If the picture file ends up taking up a lot of space, it will run out of hard disk space.
The Best Practice:
Upload the image to the cloud drive, something like: azure storage. And save the path to your database. It will save your disk space and it will also relieve your server stress, and more safety.
Additional tips:
If you just store a very small avatar file, we can convert it to base64 string format and store it in the database. In the absence of cloud services, some tiny images can be realized in this way.
However, this is not suitable for growing business scenarios, because it will cause the database footprint to become larger, which is not conducive to synchronization or backup. As well as poor large files, it may cause problems with the loading of files.

Saving images locally yet unreadable

I have a program in c# that downloads images from a web service.
The download usually takes time so I want to save the images locally so I would only need to download each image once. The problem with that is when the images saves the user of the program can see the image in the files and change it.
Is there a way to save the image in the program, yet keep it from users to see and change in the folder?
EDIT: solution used:
Encrypting the images and their names when I save them, and only access them this way. (decrypting when after reading them).
What is your intent? Anything your program has access to do, your user does as well. If you're just trying to prevent people from accidentally mucking with your images, then save off a SHA1 or similar hash of the file and store it separately. When you need an image, check the SHA1 and redownload if it doesn't match. This will prevent casual tampering, but still isn't 100% effective against malicious changes.

Efficient way to upload files

I have a aspx webpage where there's an option to upload multiple files.These files have to be stored in the database in BLOB format.
What will be the most efficient manner to store these files? There's no constraint on the size or number of file to be uploaded.
Should I upload the files one by one whenever the user clicks the file upload button or
upload them once simultaneously when the whole form gets submitted on save button. Please keep in mind, this is to used by multiple users about ~1000 at a time
Considering that it is a BLOB data, I would consider to use some No-SQL database (MongoDB, RavenDB), where you save just "document" with data, so it's easier to manage in these kind of situations. But you will need more disk space in this case.
What about upload: I would go one after one, as in case if connection drops, at least some of the files are delivered.
On the server side, would look on Redis like in memory cache that always ready to accept user "session" (a sequence of declared quantity of files), and one time all of them delivered, or connection failure the content of that session is saved on the disk.
Just general overview what can be done to give you some hints.
set file upload control multiple attribute to 'multiple' and in the code behind get request user submitted files, then loop through their memory stream and store them in your db as byte arrays
Given the limitations of your scenario (where the images must be stored in (I assume) a single SQL Database) I would look into uploading the images one by one, and I would investigate if the SQL Server Transient Fault Handling with the Exponential back-off strategy could help to try and handle the 'queued' uploads.
Without more details I can't really say.

Image resizing on the fly in asp.net

For simplicity lets say that I have a web page that needs to display thumbnails of images. The images locations are stored in a database(the images are stored on Amazon S3). Is it possible to have my web server scale down the large image before it is delivered to the client? This way I don't have to store thumbnails of every image and the client can download a smaller file.
Every tutorial on this topic over-simplifies the situation and nearly all of them leak memory. It's a long read, but you should know about the 29 image resizing pitfalls so you can avoid them.
I wrote a library to do server-side dynamic image resizing safely. It's not something that can be done properly in 1 tutorial or even 10. You can solve 80% of the bugs, but not 100%. And when you're doing something this resource-intensive, you can't tolerate bugs or memory leaks.
The core library is free and open-source, but the Amazon S3 plugin is part of the Performance edition, which has a $249 license fee. The Performance Edition comes with source, examples, and documentation for S3, MS SQL, Azure, MongoDB GridFS, and CloudFront integration, as well as terabyte-scale disk caching and memcaching.
From the statistics I have access to, it appears that imageresizing.net is the most widely-used library of its kind. It runs at least 5 social networks and is used with image collections as large as 20TB. Most large sites use the S3 plugin, as local storage (or even a SAN) isn't very scalable.
Sure, no problem. There's plenty of resources on the web that show how to dish up an image from a database. So I won't duplicate that here.
Once you've loaded the image, you can easily shrink it using .NET. There is an example at the following URL. It doesn't do exactly what you are doing, but it does generate thumbnails of an image.
http://blackbeltcoder.com/Articles/graphics/creating-website-thumbnails-in-asp-net
Using WebImage class that comes in System.Web.Helpers.WebImage you can achieve this.
You can use this great kid to output resized images on the fly.
Sample code:
public void GetPhotoThumbnail(int realtyId, int width, int height)
{
// Loading photos’ info from database for specific Realty...
var photos = DocumentSession.Query<File>().Where(f => f.RealtyId == realtyId);
if (photos.Any())
{
var photo = photos.First();
new WebImage(photo.Path)
.Resize(width, height, false, true) // Resizing the image to 100x100 px on the fly...
.Crop(1, 1) // Cropping it to remove 1px border at top and left sides (bug in WebImage)
.Write();
}
// Loading a default photo for realties that don't have a Photo
new WebImage(HostingEnvironment.MapPath(#"~/Content/images/no-photo100x100.png")).Write();
}
More about it here: Resize image on the fly with ASP.NET MVC
Here's a great tutorial that shows how to work with WebImage directly from the ASP.NET site:
Working with Images in an ASP.NET Web Pages (Razor) Site
Yes.
You make a ASP.Net page that does Response.Clear(), sets Content-Type-header in Response and sends the binary data of the image (also through Response). The image can be resized on-the-fly, but I'd recommend caching it for some time on disk or so. Then you reference the image from HTML as <img src="http://server/yourimagepage.aspx">. For storing image in memory before sending you can use MemStream.
I have sample code but not in front of me right now, sorry. :)

Categories

Resources