This blog is presented as a part of C# Advent 2023. Follow the link to check out the rest of the excellent C# and .NET content coming out as 2 blogs per day between December 1 - 25.
Have you ever built an application that needed to generate and display thumbnail images? Thumbnail images for any type of image: PNG, JPG, GIF, HEIC, HEIF, SVG… And not just thumbnails for image files but for PDFs, documents, and other random files that users may throw at it? Unless you are building a very custom implementation, this is a perfect opportunity to outsource complexity to a service that specializes in what you need.
Architecture Overview
For this article, we’ll be demonstrating asynchronous thumbnail generation using Azure Functions, Azure Blob Storage (to store the source images and thumbnails), Azure Event Grid (for Blob upload event triggers), Cosmos DB (to store image metadata), and CloudConvert for our external thumbnail generation service.
CloudConvert offers a free tier with a daily file conversion limit and paid tiers with the option to purchase credits in bulk or as part of a monthly subscription.
The following diagram gives an overview of the flow:

Step 1: Get the source file
This first step will cover getting the source image or file ready to be converted to a thumbnail. The typical flow we follow includes:
- The application or user saves the file/photo to Azure Blob Storage
- Configure an Azure Event Grid System Topic to trigger when a new blob is created. When triggered, it will call an Azure Function.
- The Azure Function will be notified that a new blob is created. Here we can save metadata to a database (such as Cosmos DB).
Step 2: Call the CloudConvert API
Now our Azure Function can call the CloudConvert API to start the thumbnail generation. CloudConvert offers APIs and a .NET SDK to simplify this process. There are many options for uploading the file to CloudConvert, but the easiest option that moves all of the upload work to the API is to use the Azure Blob Import step. With a SAS Token, CloudConvert will fetch the file you specify, convert it, and then it can save the final thumbnail back to your Blob Storage using the path you specify.
Here is a code snippet for an example CloudConvertAPI.CreateJobAsync() call that will import the file, create the thumbnail, and save the thumbnail back to our blob storage:
jobResponse = await _cloudConvert.CreateJobAsync(new JobCreateRequest
{
Tasks = new
{
import_blob = new ImportAzureBlobCreateRequest
{
Storage_Account = _azureOptions.StorageAccountName,
Sas_Token = _azureOptions.StorageSasToken,
Container = container,
Blob = blob
},
create_thumbnail = new ThumbnailCreateRequest
{
Input = "import_blob",
Input_Format = inputFormat,
Output_Format = ThumbnailOutputFormat.png,
Filename = thumbnailFilename,
Width = 256,
Height = 256,
Fit = ThumbnailFit.max
},
export_blob = new ExportAzureBlobCreateRequest
{
Input = "create_thumbnail",
Storage_Account = _azureOptions.StorageAccountName,
Sas_Token = _azureOptions.StorageSasToken,
Container = container
}
},
Tag = "jobBuilder"
});
Step 3: Handle the completed thumbnail image
If you use a flow similar to the code above, CloudConvert will save the generated thumbnail in your Azure Blob Storage container. We can use the following steps to respond to the new thumbnail image:
- Configure a new Azure Event Grid System Topic or use the same topic as from Step 1 to trigger when a new blob is created. This will trigger when the new thumbnail image is saved.
- If needed, you can update your database with the thumbnail metadata and path.
- Since this whole process is asynchronous, we need to notify any clients that the thumbnail is ready (if the clients need to respond to the thumbnail being created).
- For mobile clients, we can use Azure Notification Hub to push a silent notification to a mobile app to notify it that the thumbnail has been generated.
- For web clients, we can use SignalR to notify the client that the thumbnail has been generated.
Conclusion
Writing your own code to handle every possible file type to generate thumbnails is a complex and error-prone process. If it fits your needs, you can use an existing service and the solution is more about configuring services along with code to connect each part of the flow. Depending on your use case, it may be well worth the small incremental cost of each thumbnail generation rather than building the whole thing yourself.
If you need help with a similar project or deciding what architecture is right for your project, contact Trailhead and we can guide you through it.


