After several iterations I have come up with a workable solution, although I'm still not convinced its the best solution.
Originally I followed Anton's suggestion and just set the image url accordingly within my controller action. This was simple enough with the following code:
products.ForEach(p =>
{
p.Images[0].Url = _mediaService.GetImageUrl(p.Images[0], 200);
});
However, I soon found that this approach did not give me the flexibility I needed. Often I will need to display images of different sizes and I don't want to use properties of my model for this such as Product.FullSizeImageUrl, Product.ThumbnailImageUrl.
As far as "Product" is concerned it only knows about the images that were originally uploaded. It doesn't need to know about how we manipulate and display them, or whether we are caching them in Amazon S3.
In web forms I might use a user control to display product details and then use a repeater control to display images, setting the image urls programatically in code behind.
I found that the use of RenderAction in ASP.NET MVC gave me similar flexibility:
Controller Action:
[ChildActionOnly]
public ActionResult CatalogImage(CatalogImage image, int targetSize)
{
image.Url = _mediaService.GetImageUrl(image, targetSize);
return PartialView(image);
}
Media Service:
public MediaCacheLocation CacheLocation { get; set; }
public string GetImageUrl(CatalogImage image, int targetSize)
{
string imageUrl;
// check image exists
// if not exist, load original image from store (fs or db)
// resize and cache to relevant cache location
switch (this.CacheLocation) {
case MediaCacheLocation.FileSystem:
imageUrl = GetFileSystemImageUrl(image, targetSize);
break;
case MediaCacheLocation.AmazonS3:
imageUrl = GetAmazonS3ImageUrl(image, targetSize);
break;
default:
imageUrl = GetDefaultImageUrl();
break;
}
return imageUrl;
}
Html helper:
public static void RenderCatalogImage(this HtmlHelper helper, CatalogImage src, int size) {
helper.RenderAction("CatalogImage", "Catalog", new { image = src, targetSize = size });
}
Usage:
<%Html.RenderCatalogImage(Model.Images[0], 200); %>
This now gives me the flexibility I require and will support both caching the resized images to disk or saving to Amazon S3.
Could do with some url utility methods to ensure that the generated image URL supports SSL / virtual folders - I am currently using VirtualPathUtility.
Thanks
Ben