Advanced Base64 image extension in ASP.NET MVC

Advanced base64 image rendering in a Razor in ASP.NET MVC

  • Share

Serializing images to base64 string is well known technique to reduce requests per page. Each image on the page produces a separate request while page is loading. In case you have a lot of images on your page, this may cause slow lading.

Good practice is also to reference all images in your CSS file, but for now we are going to focus on loading serialized base64 image in the document directly.

Since loading image is an IO operation and it will affect performances we will also cache the serialized result and create dependency on the file.

This is basically a helper, so we can keep all static s we can call it from any place in our Razor.

namespace Mvc.Razor.Helpers
{
    public static class Extensions
    {
        public static MvcHtmlString Base64Image(this HtmlHelper htmlHelper, String path, IDictionary<String, String> attributes = null)
        {
            var context = HttpContext.Current;
            var builder = new TagBuilder("img");
            var physicalPath = htmlHelper.ViewContext.RequestContext.HttpContext.Server.MapPath(path);
            String cacheKey = path;
            String cachedContent = context.Cache.Get(cacheKey) as String;

            if (attributes != null && attributes.Any())
            {
                foreach (var attribute in attributes)
                {
                    builder.Attributes.Add(attribute.Key, attribute.Value);
                }
            }

                if (cachedContent == null)
                {
                    if (File.Exists(physicalPath))
                    {
                        using (var fileStream = new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))//No lock on a file
                        {
                            String srcTemplate = "data:image/{0};base64,{1}";
                            String fileExtension = Path.GetExtension(physicalPath);
                            byte[] buffer = new byte[fileStream.Length];

                            fileStream.Read(buffer, 0, (int)fileStream.Length);

                            if (fileExtension.StartsWith("."))
                            {
                                fileExtension = fileExtension.Substring(1).ToLower();
                            }
                            cachedContent = string.Format(srcTemplate,fileExtension, Convert.ToBase64String(buffer));
                            context.Cache.Insert(cacheKey, cachedContent, new System.Web.Caching.CacheDependency(physicalPath), DateTime.MaxValue, TimeSpan.FromHours(1));
                        }
                    }
                }
            
            builder.Attributes["src"] = cachedContent;

            return MvcHtmlString.Create(builder.ToString());
        }
}
}
    

To use this helper you will have to reference it in your Web.Config which is in your Views folder as following:

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="Mvc.Razor.Helpers" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
    

After altering Views web.config, we are ready to use the extension in our Razor views:

@Html.Base64Image("~/Content/logo_aspmvc.png")
    

I also added an optional dictionary parameter, so that you can add any attribute to the output tag.

@Html.Base64Image("~/Content/logo_aspmvc.png", new Dictionary<String, String>() { { "Title","ASP.NET MVC Logo" } })
    
  • Share

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.

Comments for this article

comments powered by Disqus