Sitecore automate code generation using TDS T4 text template

adminSitecore1 Comment

Sitecore developers who are unaware of TDS code generation could be saving significant time and effort as well as reducing runtime errors (to compile time errors) and other type-safe coding benefits. Many developers are manually writing Field Name, Template Ids, Field Ids etc.

As an example, template contains fields like Title, Text etc. Most of the time developers are using class or constants and write code something like…

public class MyWebPage
{
    public const string Title = "Title";
    public const string Text = "Text";
    public const string MetaKeywords = "MetaKeywords";
}

or some developers like to use Sitecore ID instead of name (which helps if in future they need to change field name) and write like…

public class MyWebPage
{
    public static Sitecore.Data.ID Title = new Sitecore.Data.ID("{89C903FC-8788-4B41-B187-5C4405E31660}");
    public static Sitecore.Data.ID Text = new Sitecore.Data.ID("{89C903FC-8788-4B41-B187-5C4405E31661}");
    public static Sitecore.Data.ID MetaKeywords = new Sitecore.Data.ID("{89C903FC-8788-4B41-B187-5C4405E31662}");
}

The above example is a very short and basic example. Also, code is written for only three fields, which can be used in multiple places. As an example, this would be used in rendering where developers use strongly type object instead of string.

Now think, if you have a few modules like a carousel, image gallery, event, news and so on, and pages like home page, event page, news page, gallery page etc., then you may end up spending many hours writing these types of classes. Also, when a developer needs to add or remove fields then maintenance can be a huge issue.

Using TDS Code Generation

Using TDS code generation with T4 templates; this problem can be solved and the developer can automate that. This process takes only a few minutes, which saves productive hours that will reduce project development cost. Not only that, the product will be robust and because of automated processes there is less chance of human error.

The following are steps you need to take:

  • Create and set TDS project into your solution
  • Get Sitecore items from Sitecore into TDS project
  • Within TDS project properties make the following changes
    • Select Code Generation tab
    • Checked Enable Code Generation
    • Select Target Project
    • Set code generate target file
    • Provide name space in project properties window if you want; otherwise you can specify namespace on item level
    • Transform file (which I have added for your reference Header.tt & Template.tt)
    • Within TDS project sitecore item and than properties
      • In this example I am only using templates code generation so in this example I am selecting Templates and than open properties window
      • Put appropriate namespace and select code generation template (this way you can select different template where required) for example one for Sitecore templates, another one for Sitecore content items and so on.
  • Save the project and every time TDS project updated, new code will be generated as per provided template

Screenshots for your reference

Project Properties

Project Properties

Sitecore items within TDS project

Sitecore items within TDS project

Sitecore item properties

Sitecore item properties

Sitecore item properties Values

Sitecore item properties Values

Below are the template and generated code for your reference only:

Header.tt

<#@ template language="C#" #>
<#
// The Header Template is used to generate code that goes at the top of the generated code file. This template is executed only once.
// it will typically generate #using statements or add other one time only elements to the generated file.

//Parameters passed to Template for code generation

//   Model: The ProjectHeder object contains information about the TDS project generating the code and the project where the
//          generated code will reside.
#>
<#@ parameter name="Model" type="HedgehogDevelopment.SitecoreProject.VSIP.CodeGeneration.Models.ProjectHeader" #>
<#
// 	DefaultNamespace: The DefaultNamespace parameter contains the default namespace of the project where the generated
//					  code file resides.
#>
<#@ parameter name="DefaultNamespace" type="System.String" #>
using System;
using System.Web;
using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Mvc.Presentation;
using System.Collections.Generic;

Template.tt

<#@ template language="C#" debug="true" hostSpecific="true" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="HedgehogDevelopment.SitecoreProject.VSIP.CodeGeneration.Models" #>
<#@ parameter name="Model" type="HedgehogDevelopment.SitecoreProject.VSIP.CodeGeneration.Models.SitecoreItem" #>

<#  if (Model.GetType() == typeof(SitecoreTemplate)) {
        var template = Model as SitecoreTemplate; 
        var className = ClassName(Model.Name);
#>

namespace <#= FormatNamespace(Model.Namespace) #>
{   
    public partial class <#= className #> 
    {
        public static readonly ID TemplateId = new ID("{<#= Model.ID.ToString() #>}");	
	
        <# if (template.BaseTemplates.Any()) {#>
        #region base templates
        <# foreach (var baseTemplate in template.BaseTemplates)
        {
                var memberName = PrivateMemberName(baseTemplate.Name);
                var propertyName = ClassName(baseTemplate.Name);
                
		#>

        private <#= baseTemplate.Namespace + "." + propertyName #> <#= memberName #>;
        
        public <#= baseTemplate.Namespace + "." + propertyName #> <#= propertyName #>
        {
            get
            {
                return <#= memberName #> ?? (<#= memberName #> = new <#= baseTemplate.Namespace + "." + propertyName #>(InnerItem));
            }
        }
        <#} #>
        #endregion    
        <#} #>

        
<#  if (template.Fields.Any() || template.BaseTemplates.Any()) { #>
        #region <#= className #> field ids
        public struct FieldIds    
		{
			<#  foreach (var field in template.Fields) { #>
				public static readonly ID <#= TitleCase(field.Name) #> = new ID("{<#= field.ID.ToString() #>}");
			<#  } #>

			<# foreach (var baseTemplate in template.BaseTemplates)
			{
				foreach(var field in baseTemplate.Fields) { #>
					public static readonly ID <#= TitleCase(field.Name) #> = new ID("{<#= field.ID.ToString() #>}");
				<# }
			} #>
		}
        #endregion       
<#  } #>
	}

}
<#    } #>

<#+
 
public string ClassName(string name)
{
    return TitleCase(name);
}

public string FieldName(string name)
{
    return name.Replace("_", " ");
}

public string PrivateMemberName(string name)
{
    var formattedName = TitleCase(name);

    return "_" + Char.ToLowerInvariant(formattedName[0]) + formattedName.Substring(1);
}
 
public string TitleCase(string name)
{
    name = Regex.Replace(name, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
    name = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(name);
    name = Regex.Replace(name, @"[^a-zA-Z0-9]", String.Empty);
    name = Regex.Replace(name, @"(^[0-9])", "Z$1");
     
    return name;
}

public string FormatNamespace(string input)
{
	return input.Replace(".sitecore.templates", ".Templates").Replace(" ", string.Empty);
}

#>

AutoGenerateCode.cs

using System;
using System.Web;
using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Mvc.Presentation;
using System.Collections.Generic;

namespace Blogs.Sitecore.UI.BlogWebsite
{   
    public partial class SampleItem 
    {
        public static readonly ID TemplateId = new ID("{d24dac19-2303-42d5-8636-40b61646cac5}");	
	    
        #region SampleItem field ids
        public struct FieldIds    
	{
	   public static readonly ID Text = new ID("{c7cb5dc7-46b2-423d-87db-85a40e8e825d}");
           public static readonly ID Title = new ID("{08cc1a3f-8a5c-4f19-af68-a0317d802d21}");		
	}
        #endregion       
    }
}

You can extend .tt files as per your requirements. For example, if you want ItemPath and ItemName you should add code like:

public static string ItemName { get { return  "<#=Model.Name#>"; } }
public static string ItemPath { get { return  "<#=Model.Path#>"; } }

Please note the above example is very basic but you can automate a lot of others including Sitecore content items, which will reduce your significant development hours for writing ViewModel class that you can use in presentation.

I hope that helps but please feel free to let me know if you have any query or question.

 

One Comment on “Sitecore automate code generation using TDS T4 text template”

Leave a Reply

Your email address will not be published. Required fields are marked *