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.
Requirement:
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="">
Solution:
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)
{
return;
}
}
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;
}
}
}
}
}
Will be happy to hear, how other tech masters resolved this type of issues?
This is awesome. This is how blobs should be served!
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.
Frederik