Wednesday 18 September 2013

Updated way to include Kendo dependencies

Hello everyone, 
After spending some time doing performance testing on the MVC project it occurred to me that the quantity of data being downloaded on every request is extremely high. The reason behind this is mainly the Kendo scripts and CSS stylesheets. They were simply placed on the master layout (by me, yes, shame on me I know) therefore they were being loaded on every request. This is really not-so-bad since such data are being cached client-side and then retrieved from the cache, still it causes really bad performace on the first load and above all, makes the website displeasant to devices using mobile traffic.
Enough said: If you have used Kendo in any of your pages, the references don´t get loaded automatically any more. You need to add them yourself; to relieve you from the hard work, I have implemented a Html helper, which you can use as follows:

 @{  
    Html.Enablekendo(); // If you need only Kendo CSS     
    Html.EnableKendo(KendoComponent.Tabstrip); // If you need to use the Tabstrip component, this includes CSS and all other references  
    Html.EnableKendo(KendoComponent.Tabstrip, KendoComponent.DropDownList); // If you need to use more than one components on the same page  
 }  

The helper code is below:
 public static void EnableKendo(this HtmlHelper Helper, params KendoComponent[] components){  
       Helper.ViewBag.KendoCSS = 1;  
       if (!components.Contains(KendoComponent.Grid))  
         Helper.ViewBag.KendoCore = 1;  
       foreach (var component in components)  
       {  
         switch (component)  
         {  
           case KendoComponent.TabStrip:  
             Helper.ViewBag.KendoTabStrip = 1;  
             break;  
           case KendoComponent.DropDownList:  
             Helper.ViewBag.KendoDropDownList = 1;  
             break;  
           case KendoComponent.Editor:  
             Helper.ViewBag.KendoEditor = 1;  
             break;  
           case KendoComponent.Grid:  
             Helper.ViewBag.KendoGrid = 1;  
             break;  
           case KendoComponent.TreeView:  
             Helper.ViewBag.KendoTreeView = 1;  
             break;  
           case KendoComponent.Upload:  
             Helper.ViewBag.KendoUpload = 1;  
             break;  
           case KendoComponent.Window:  
             Helper.ViewBag.KendoWindow = 1;  
             break;  
         }  
       }  
 }  

Of course you also need to define the KendoComponent Enumeration:
 public enum KendoComponent {  
     All, TabStrip, Grid, DataSource, DropDownList, DatePicker, Editor, ToolTip, TreeView, Upload, Validator, Window, CSS  
 }  

There is a _RenderKendo partial view being called in the layout that checks for  the corresponding viewbag values and includes the matching bundle: The code in the partial view is:

 @if (ViewBag.KendoCSS == 1)  
 {  
   @Styles.Render("~/Content/kendo/2012.3.1114/css.min");  
 }  
 @if (ViewBag.KendoCore == 1)  
 {  
   @Scripts.Render("~/bundles/kendocore");  
 }  
 @if (ViewBag.KendoTabStrip == 1)  
 {  
   @Scripts.Render("~/bundles/kendotabstrip");  
 }  
 @if (ViewBag.KendoDropDownList == 1)  
 {  
   @Scripts.Render("~/bundles/kendodropdownlist");  
 }  
 @if (ViewBag.KendoEditor == 1)  
 {  
   @Scripts.Render("~/bundles/kendoeditor");  
 }  
 @if (ViewBag.KendoGrid == 1)  
 {  
   @Scripts.Render("~/bundles/kendogrid");  
 }  
 @if (ViewBag.KendoTreeView == 1)  
 {  
   @Scripts.Render("~/bundles/kendotreeview");  
 }  
 @if (ViewBag.KendoUpload == 1)  
 {  
   @Scripts.Render("~/bundles/kendoupload");  
 }  
 @if (ViewBag.KendoWindow == 1)  
 {  
   @Scripts.Render("~/bundles/kendowindow");  
 }  

Finally, we need the Bundles. Inside the BundleConfig file of MVC we put the corresponding css and javascript files 
together, according to this link. An example would be:

 string kendoPath = "~/Scripts/kendo/2013.1.621/";  
 bundles.Add(new ScriptBundle("~/bundles/kendotreeview").Include(  
         kendoPath + "kendo.userevents.js",  
         kendoPath + "kendo.data.js",  
         kendoPath + "kendo.fx.js",  
         kendoPath + "kendo.treeview.js"  
         ));  

An example for CSS StyleBundle would be:
 bundles.Add(new StyleBundle("~/Content/kendo/2012.3.1114/css.min").Include(  
        "~" + Media.GetUrl(ContentType.Kendo, "2012.3.1114/kendo.dataviz.min.css"),  
        "~" + Media.GetUrl(ContentType.Kendo, "2012.3.1114/kendo.common.min.css"),  
        "~" + Media.GetUrl(ContentType.Kendo, "2012.3.1114/kendo.uniform.min.css")  
         ));  

Keep in mind that especially for css files that reference images inside them, the path of the StyleBundle must match the actual path of the CSS file “and then some”, meaning that ~/Content/kendo/2012.3.1114/ actually exists, but 
css.min shall playthe role of the wrapper. The dot is essential there, not mandatory of course, it is just my way for 
making it work, everything else has failed dramatically…
Remember: Don’t use minified versions of scripts or CSS files in Bundles, or you are in trouble.After all, this is 
another scope of bundling, it also takes care of the minifying of data. You have been warned.
 
P.S. I kept on failing trying to build a correct bundle for the Kendo Datagrid. I finally ended up with this:


 bundles.Add(new ScriptBundle("~/bundles/kendogrid").Include(  
         kendoPath + "kendo.web.js",  
         kendoPath + "kendo.aspnetmvc.js"  
         ));    

Finally, the class for the Media Helper:
 public class Media  
   {  
     /// <summary>  
     /// Instantiates the corresponding UrlHelper to provide access to extension methods for getting media.  
     /// </summary>  
     public static string GetUrl(ContentType type, string filename = "")  
     {  
       String rootPath = System.Configuration.ConfigurationManager.AppSettings[type.ToString()];  
       String absolutePath = Path.Combine(rootPath, filename);  
       return absolutePath;  
     }  
 }  
Don´t forget to insert a key for Kendo in your web.config!

  <appSettings>  
   <add key="Kendo" value="/Content/Kendo/" />  
  </appSettings>  

Also, always remember that the jquery.unobtrusive-ajax.js file must come AFTER the Kendo javascripts. This 
applies in general, but especially to the Datagrid.

I hope this saves someone from trouble.

No comments:

Post a Comment