Stephan Lonntorp
Nov 18, 2016
visibility 4176
star star star star star star
(2 votes)

Ensuring image extension for content URLs

When using an image resizing component, like we do in the Focal Point plugin, it's really important that the file extension is there. If it's not, the resizing engine won't kick in for the request, and that enormous image is sent straight to your mobile users, and they will forever hate your guts.

I've implemented a solution using the new (in CMS 10) IUrlSegmentCreator events, and a regular InitializationModule. Code below. It uses the first registered extension for your media type as the default extension for the URL segment. This works for me, since I have separate Media types for all image files, like JpegImage, PngImage etc, to be able to more granularly control their usage, through the AllowedTypes attribute. If you have a single MediaData for all your images, I recommend altering the extension mapping to maybe use the MimeType property and get an appropriate extension based on that. 

/*using System;
using System.IO;
using System.Linq;

using EPiServer;
using EPiServer.Core;
using EPiServer.Framework;
using EPiServer.Framework.DataAnnotations;
using EPiServer.Framework.Initialization;
using EPiServer.Web;
*/

[InitializableModule, ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
	public class ImageDataInitialization : IInitializableModule {
		private bool eventsAttached;
		public void Initialize(InitializationEngine context) {
			if(!this.eventsAttached) {
				var creator = context.Locate.Advanced.GetInstance<IUrlSegmentCreator>();
				creator.Created += CreatedMediaSegment;
				this.eventsAttached = true;
			}
		}
		private static void CreatedMediaSegment(object sender, UrlSegmentEventArgs e) {
			var content = e.Content as ImageData;
			if(content != null) {
				var extension = Path.GetExtension(content.RouteSegment);
				if(string.IsNullOrWhiteSpace(extension)) {
					var type = content.GetOriginalType();
					var fileExtension = GetExtensionForType(type);
					if(!string.IsNullOrWhiteSpace(fileExtension)) {
						content.RouteSegment = content.RouteSegment + "." + fileExtension;
					}
				}
			}
		}
		private static string GetExtensionForType(Type contentType) {
			var mediaDescriptorAttribute = contentType?.GetCustomAttributes(typeof(MediaDescriptorAttribute), false).OfType<MediaDescriptorAttribute>().FirstOrDefault();
			return mediaDescriptorAttribute?.Extensions?.FirstOrDefault();
		}
		public void Uninitialize(InitializationEngine context) {
			var creator = context.Locate.Advanced.GetInstance<IUrlSegmentCreator>();
			creator.Created -= CreatedMediaSegment;
			this.eventsAttached = false;
		}
	}
Nov 18, 2016

Comments

valdis
valdis Nov 22, 2016 09:55 PM

I'm not fan of hacks, but theoretically if you happen to have project with extension less images (which is weird) in it, you can tell IR to kick-in. See Nathanael answer.

http://stackoverflow.com/questions/14387595/imageresizer-and-image-files-without-an-extension

Stephan Lonntorp
Stephan Lonntorp Nov 22, 2016 10:27 PM

Thanks, but that seems like a can of worms. I cannot know all paths that csn, or cannot, contain an image. I think I'll stick with this approach. :)

error Please login to comment.
Latest blogs
The Silent Success: When Your Optimizely SaaS CMS Config Push Succeeds with "0" Changes

  Picture this frustratingly common scenario in headless, code-first development with Optimizely SaaS CMS: You’ve defined a brilliant new element,...

Vipin Banka | Jul 13, 2026

Architecting an Enterprise-Grade Development Pipeline in Optimizely SaaS CMS

Most enterprise teams show up to Optimizely SaaS CMS with a clear roadmap for their release pipeline: DEV → QA → Stage → Prod. Four logical...

Vipin Banka | Jul 12, 2026

Bynder DAM Connector for Optimizely SaaS CMS: Improved Metadata Property Synchronization

While working with the Bynder DAM Connector for Optimizely SaaS CMS , one of the key areas I explored was how Bynder asset metadata is synchronized...

Vipin Banka | Jul 11, 2026

Optimizely DXP: Every Supported Culture, One Searchable Page

Quick one for anyone building multi-language sites on Optimizely DXP. I put together a reference tool listing all 806 supported cultures. More...

Adnan Zameer | Jul 10, 2026 |

A day in the life of an Optimizely OMVP: London Meetup 2026

On 2nd July 2026 the Optimizely London Developer Meetup returned to The Lightwell, and the running theme across the evening was less about individu...

Graham Carr | Jul 10, 2026

Optimizely’s Summer ’26 Roadmap: The CMS Is Starting to Look Less Like a Publishing Tool and More Like Marketing Infrastructure

Optimizely’s Summer ’26 Product Roadmap event was not just a list of product updates. At least, that is not the part I found most interesting. The...

Augusto Davalos | Jul 9, 2026