K Khan
Dec 10, 2014
(5 votes)

Using Blobs and CDN both effectively

We have a requirement where Editors can upload images on cloud and use those from website.

We implemented a blob provider to let editors upload and use their images on cloud (cloudinary.com) http://world.episerver.com/code/K-Khan-/Cloudinary-Implementation-in-Blob/

But there were few issues with this implementation, as on presenting the images on website in OpenRead function of provider, we have to download this images in Memory. To read image in memory. That means extra bandwidth usage and using server resources unnecessary. Another option was to redirect to CDN in provider. That means a 302 status and a Error in log files (http://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=113925). With redirection we have another issue that In Online centre Catalog module was not able to prepare thumbnails.

To deal with these issues we solved it by translating images from globalassets/image.jpg to direct CDN url http://res.cdn.com/account/1537157355371237123.jpg and for Editors we kept the original implementation. This can be useful in many other cases also.

Change <img src="/globalassets/logo.png" alt="" class="" itemprop="logo"> to url in cdn <img src=http://res.cloudinary.com/example.png alt="" class="" itemprop="">

I got the help of Johan's solution in some forum post he advised. In initialization module overload ContentRoute.CreatedVirtualPath

ContentRoute.CreatedVirtualPath += this.ReplaceWithCloudUrl;
CatalogRouteHelper.MapDefaultHierarchialRouter(RouteTable.Routes, true);

public void ReplaceWithCloudUrl(object source, UrlBuilderEventArgs eventArgs)
            var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();

            ////Check if routed content is a IBinaryStorable with a Cloudinary Blob, if so replace url with cdn blob uri      
            object contentReferenceObject;
            if (eventArgs.RouteValues.TryGetValue(RoutingConstants.NodeKey, out contentReferenceObject))
                ContentReference routedContentLink = contentReferenceObject as ContentReference;
                if (!ContentReference.IsNullOrEmpty(routedContentLink))
                    var binaryContent = contentLoader.Get<IContent>(routedContentLink) as IBinaryStorable;
                    if (binaryContent != null)
                        ////Check that Everyone has Read access before switching to external url
                        ISecurable securable = binaryContent as ISecurable;
                        if (securable != null)
                            if ((securable.GetSecurityDescriptor().GetAccessLevel(PrincipalInfo.AnonymousPrincipal) & AccessLevel.Read) != AccessLevel.Read)

                        var cloudinaryBlob = binaryContent.BinaryData as CloudinaryFileBlob;
                        var httpContext = System.Web.HttpContext.Current.GetRequestContext().HttpContext;
                        if (cloudinaryBlob != null && (!httpContext.Request.Path.ToLower().Contains(SiteConstants.EditingUrlPart.AppSetting())))
                            imagePath = //CDN Image Path that Blob;
                            UrlBuilder cdnUrlBuilder = new UrlBuilder(imagePath);
                            eventArgs.UrlBuilder.Uri = cdnUrlBuilder.Uri;

Dec 10, 2014


K Khan
K Khan Dec 10, 2014 06:57 PM

Will be happy to hear, how other tech masters resolved this type of issues?

Dec 10, 2014 08:40 PM

This is awesome. This is how blobs should be served!

Frederik Vig
Frederik Vig Dec 10, 2014 09:39 PM

We´ve done similar, but instead we´ve used the IIS extension URL Rewrite to rewrite ouput URLs to the CDN version. The CDN adds the image cached, if it didn´t have the image it would contact EPiServer and get the right image, then put it in it´s cache and serve it to the end user. Like a reverse proxy basically.


Please login to comment.
Latest blogs
Optimizely SendGrid SMTP host is deprecated

SendGrid is a services for sending email that is included in Optimizely DXP. Previously smtp.episerver.net was the recommended SMTP server to use,...

Tomas Hensrud Gulla | Dec 4, 2022 | Syndicated blog

Hosting Optimizely CMS 12 on Docker Engine

Since Optimizely CMS can now be deployed as a Docker container, here is a demonstration of building, running and scaling an Optimizely CMS 12 site ...

Stefan Holm Olsen | Dec 4, 2022 | Syndicated blog

How to use CacheTagHelper with content areas in Optimizely CMS 12

I might be going out on a limb here - if you have a better solution, feel very free to share it!  Upgrading your Optimizely web application from .N...

Andreas J | Dec 2, 2022

The 1001st Piece in your 1000 Piece Puzzle: .NET Default Interface Functions

I was recently working with a client who wanted a reasonably large subsystem added to Optimizely that would add automated management to their...

Greg J | Nov 28, 2022 | Syndicated blog