A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Stephan Lonntorp
Nov 18, 2016
  1549
(0 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

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026

Scheduled job for deleting content types and all related content

In my previous blog post which was about getting an overview of your sites content https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/1/sche...

Per Nergård (MVP) | Jan 30, 2026

Working With Applications in Optimizely CMS 13

💡 Note:  The following content has been written based on Optimizely CMS 13 Preview 2 and may not accurately reflect the final release version. As...

Mark Stott | Jan 30, 2026

Experimentation at Speed Using Optimizely Opal and Web Experimentation

If you are working in experimentation, you will know that speed matters. The quicker you can go from idea to implementation, the faster you can...

Minesh Shah (Netcel) | Jan 30, 2026