Tridion Razor Templating Mediator Version 1.0.1 Alexander Klock alex@tahzoo.com Read Me! You should fully test the Razor Mediator features that you use extensively before deploying it to a live production environment. Please send me an e-mail with any issues and bugs found so that I may fix them as soon as possible. Table of Contents Introduction .................................................................................................................................................. 3 Limitations of Dreamweaver Templates ................................................................................................... 3 The Power of the Razor Mediator............................................................................................................. 3 Installation .................................................................................................................................................... 4 Requirements............................................................................................................................................ 4 Install (Running the Installer) .................................................................................................................... 4 Uninstall .................................................................................................................................................... 5 Advanced Configuration ........................................................................................................................... 5 CacheTime Attribute ............................................................................................................................. 5 ExtractBinaries Attribute....................................................................................................................... 5 Namespaces .......................................................................................................................................... 5 Assemblies ............................................................................................................................................ 6 Razor Templating Usage and Samples .......................................................................................................... 6 Usage......................................................................................................................................................... 6 Simple Page Template............................................................................................................................... 7 Simple Component Presentation .............................................................................................................. 7 Dynamic Item Fields .................................................................................................................................. 7 Checking ItemFields For Values ............................................................................................................ 8 Handling Embedded Fields ....................................................................................................................... 9 Handling Component Links ....................................................................................................................... 9 Model Class ItemField Shortcuts............................................................................................................. 10 Important Note on Dynamic Objects .................................................................................................. 10 The DynamicPackage Object ................................................................................................................... 11 Accessing the Tridion Package and Engine Objects ................................................................................ 11 Accessing the Page Object from a Component Template ...................................................................... 11 Razor Syntax / DWT Comparison ................................................................................................................ 11 Razor Mediator Templating and API Reference ......................................................................................... 13 From The Tridion Razor Template Base .................................................................................................. 13 ModelUtilities.......................................................................................................................................... 15 ComponentPresentationModel .............................................................................................................. 16 PublicationModel .................................................................................................................................... 17 AbstractRepositoryLocalObject .............................................................................................................. 18 ComponentModel ................................................................................................................................... 19 FolderModel............................................................................................................................................ 19 PageModel .............................................................................................................................................. 20 StructureGroupModel............................................................................................................................. 21 Future of the Razor Mediator ..................................................................................................................... 22 Planned ................................................................................................................................................... 22 Bugs / Feature Requests ......................................................................................................................... 22 Introduction The Razor Template Engine has been introduced into the .NET community with much success, and you’ll especially find it common in almost every ASP.NET MVC project you come across now. If you are not familiar with .NET and the Razor Templating syntax, then perhaps you have heard of Velocity? Razor has been compared to Java’s Velocity template engine. But why is it so popular? Razor allows an easy to use syntax (pretty much C# syntax) for template scripting, but with a clean easy to read look and feel (so no, we’re not taking a step back into the days of VBScript templates!). Limitations of Dreamweaver Templates Although Tridion comes with Dreamweaver Templating out of the box, and this is what’s widely used amongst the Tridion projects out there, anyone who’s worked with this templating style fully understands the limitations (and frustrations) that DWT’s has to offer. Below is an incomplete list of some of the drawbacks and limitations to working with DWT’s. 1.) ComponentLink Fields. You just can’t access the fields of a Component from a ComponentLink field in DWT. You end up either having a TBB that pushes these values to the package, or by using a Dreamweaver Custom Function (like Nuno’s Dreamweaver Get Extensions, which is a must in my opinion when working with DWTs). 2.) TemplateRepeatIndex. You can only get this value of the TemplateRepeat loop that you are working with (ie, can’t get the outer TemplateRepeatIndex value). 3.) Nested Repeat Regions. Because of the above problem, accessing fields from an outer repeat region is impossible without the help of custom functions or TBBs. 4.) Else Statement. Yep, there is no else statement. You have to write TemplateIf multiple times using negation. (Though there is a ternary expression you can use when outputting variables.) 5.) Whitespace. Although not too big of an issue, it does bother some the amount of whitespace that DWTs output. 6.) Flexibility. With DWT there is none. If you want to have Date formatting for example, you have to write code (TBB or Custom Function) to handle it for you. The Power of the Razor Mediator With Razor Templating, all of the above limitations are covered. You actually have the power of .NET within your Razor Templates. Using the base Tridion Razor Template and utilities that comes with the Razor Mediator, you’ll have quick and easy access to most of your Template Package items and fields right at your fingertips. Because you are now able to do more and write less, the templating process can be done quicker than ever before. Razor is a strongly typed, case sensitive, scripting language. For example, for a Tridion DateField, you can format the date right from the template using <span>@Fields.NewsDate.ToString(“MM/dd/yyyy”)</span>. For a Tridion KeywordField, you have access to all of the Tridion keyword fields like <span>@Fields.SomeKeywordField.Title</span>. Want to capitalize your header field? <span>@Fields.Header.ToUpper()</span>. What about accessing fields of Component Links? <div>@Fields.SomeComponentLink.FieldName</div>. You can even go as deep as you want with Component Links. <div>@Fields.SomeComponentLink.AnotherComponentLink.FieldName</div>. You can also add your own scriptlet like helper functions right to your templates if you so desired. Some of the Tridion types have also been wrapped by Model classes that provide easier functionality of accessing certain data, like Fields and Metadata (dynamic access that always returns the correct type in your templates). For these Model classes, you can always access the underlying Tridion Object through the TridionObject property. For example, @Component.TridionObject.HasUsingItems(). The Component is of type ComponentModel (the special wrapper class), while the TridionObject property actually returns the Tridion Component instance. Most of the Model class’ ToString() method writes out the wrapped Tridion item’s Title property, with the exception of the ComponentModel, which will write out the Component’s Tcm Uri. Installation Requirements Tridion 2011 and .NET 4.0 is required on the Tridion CMS server for usage of the Razor Mediator. .NET 4.0 should have already been installed during the Tridion installation process. Install (Running the Installer) The Razor Mediator uses the Tridion Mediator architecture, so it will not break any of your existing work. Installation is simple, just run the RazorMediatorInstaller.msi installer file on the Tridion CMS Server. The installer will add System.Web.Razor.dll and Tridion.Extensions.Mediators.Razor.dll to the GAC. It will also automatically make a backup of the Tridion.ContentManager.config configuration file (with timestamp), and then make the necessary automatic changes to the configuration (includes registering the Razor Template type, adding the Mediator, and adding a custom configuration section for razor.mediator). Once the installation has completed, you will need to restart the Tridion Content Manager COM+ package, the Tridion Publisher service, and Template Builder if it’s open. You do not have to restart the box. As a recap, the steps are: 1.) Double click the RazorMediatorInstaller.msi. 2.) Follow the steps of the Installer. 3.) Once installed, restart the Tridion Content Manager COM+ Package, the Tridion Publisher service, and Template Builder (if it’s open). Uninstall If for any reason you need to uninstall, just uninstall it like you would a program (selecting Uninstall from the context menu of RazorMediatorInstaller.msi, or by going to Control Panel and removing the program named “Razor Templating Mediator”) . It’ll remove the DLL’s from the GAC and remove the Razor Mediator sections from the Tridion.ContentManager.config file. A time stamped backup of the Tridion.ContentManager.config will also be automatically created for you, just in case you want to keep some of the advanced custom configuration for the Razor Mediator handy. Advanced Configuration The Tridion.ContentManager.config file, after installation, will contain a configurable section for the Razor Mediator for further customization of your templates, such as adding references to other libraries to your templates, and including namespace imports globally to all of your templates. Below is a sample of what this section can look like. <razor.mediator cacheTime=”600” extractBinaries=”true”> <namespaces> <add namespace=”System.Linq” /> <add namespace=”Tridion.ContentManagement” /> </namespaces> <assemblies> <add assembly=”RazorSample.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=60ad7434f03dfcdc” /> <add assembly=”C:\Program Files\Razor\Tests\Test.Sample.dll” /> </assemblies> </razor.mediator> CacheTime Attribute Razor Templates are compiled in memory before they are executed. Due to this, normally the first time a Razor Template runs will take the longest. For performance, templates are cached after being compiled. This prevents a template from being compiled each and every time it is run. The cacheTime attribute represents the time in seconds that a template will live in the cache before being expired. ExtractBinaries Attribute The Razor Mediator, after template execution, can extract binaries from the output and add them to the package. This is somewhat comparable to the way DWT’s are handled in 2011. If you are handling binary extraction yourself via a Template Building Block, you can set this value to false. Namespaces The <namespaces> element contains a global way to import namespaces into every one of your templates. Rather than manually adding @using System.Linq into the top of every template, you could just add <add namespace=”System.Linq” /> instead. Assemblies The <assemblies> element is the way for you to reference other libraries to be usable by your templates. For adding elements contained within the GAC, you can just simple reference the fully qualified GAC name. For example, if you wanted to use items from SomeLibrary.Blah, you can simply add <add assembly=”SomeLibrary.Blah, Version=2.1.0.0, Culture=neutral, However, if you are referencing an item that is not contained in the GAC, you must add the absolute physical path to the DLL, ie: <add namespace=”C:\Program Files\Razor\Tests\Test.Sample.dll” />. PublicKeyToken=ab09ae83cdf90a23” />. For non-GAC assemblies, because the Razor Templates are compiled in memory, the assemblies get loaded via an AssemblyResolver event on demand. However, the performance of doing this is more costly, and will add to your template execution time, so when possible, use items from the GAC. Razor Templating Usage and Samples The following sections contain samples and usage. In the samples you might see various ways to access items from the template. Usage Once the Razor Mediator is installed, creating Razor Templates works the same way as creating Dreamweaver Templates. 1.) Create a New Template Building Block. 2.) Give your TBB a name. I normally add a suffix of “RCT” for Razor Component Templates or “RPT” for Razor Page Templates, but naming convention is of course completely up to you. 3.) Select the “Source” tab. 4.) For Template Type, select “RazorTemplate”. 5.) In the text area, add your Razor syntax 6.) Select “Save and Close” when finished. 7.) Add your Razor TBB to a Compound Template (just as you would if it were a DWT). Simple Page Template <html> <head> <title>@Page.Title</title> <meta name=”keywords” value=”@Page.Metadata.Keywords” /> </head> <body class=”@Page.Metadata.BodyClass”> <h1>Page Title: @Page.Title (@Page.ID)</h1> <h2>Publication Title: @Publication.Title (@Publication.ID)</h2> <div> Getting some keywords from a Publication MetaData Field: <ul> @foreach (var keyword in Publication.MetaData.SomeKeywordFields) { <li>@keyword.Title (@keyword.Id)</li> } </ul> </div> <h3>Test Templates:</h3> @foreach (var cp in ComponentPresentations) { if (cp.Template.Title == “Test Template”) { <div>You have full access to @cp.Component.Title w/ all of its fields like @cp.Component.Fields.AFieldName</div> <div>@cp.RenderComponentPresentation()</div> } } <h3>You could have also done it like:</h3> @foreach (var cp in GetComponentPresentationsByTemplate(“Test Template”)) { <div>Another component for template @cp.Template.Title:</div> <div>@cp.RenderComponentPresentation()</div> } </body> </html> Simple Component Presentation <div class=”news-article”> <img src=”@Fields.HeaderImage.ID” alt=”@Fields.HeaderImage.AltText” /> @* Note that Fields is just a shortcut to Component.Fields *@ <h2>@Fields.Header</h2> <h5>@Fields.NewsDate.ToString(“dd/MM/yy hh:mm”)</h5> <div class=”body-text”> @Fields.BodyText </div> </div> Dynamic Item Fields The Model wrapper classes use a special DynamicItemFields class to represent both Fields and Metadata for Tridion items. The DynamicItemFields class allows you to call field names (case insensitive!) directly in dot notation, and get a Type back based on the field type. The template writer will have to know which Type he/she is getting back to know what further functionality or properties the template designer can call. Field Type Returned Type Example TextField String DateField DateTime KeywordField Keyword EmbeddedSchemaField DynamicItemFields (See Handling Embedded Fields) ComponentModel (wrapped Component object) ComponentLinkField ExternalLinkField String NumberField Note: Multivalued Fields Double Returns a List<Type>. For example, a multi-valued ComponentLinkField will return type of List<ComponentModel>. @Fields.ATextField @Fields.ATextField.Length @Fields.ATextField.ToUpper() @Fields.ADateField.Year @Fields.ADateField.ToString(“MMMM”) @Fields.ADateField.ToUniversalTime() @Fields.AKeyword @Fields.AKeyword.Id @Fields.AKeyword.Key @Fields.AnEmbeddedField.EmbeddedFieldName @Fields.AnEmbeddedField.ADateField.Month @Fields.ACompLinkField.Title @Fields.ACompLinkField.Fields.Header @Fields.ACompLinkField.Metadata.Author @Fields.AnExternalLink @MetaData.AnotherExternalLink @MetaData.ANumberField @foreach (var keyword in Field.SomeKeywords) { <li>@keyword.Key ( @keyword.Id )</li> } @foreach (var c in Field.SomeCompLinks) { <li>@c.Title : @c.Fields.SubHeader</li> } Remember, the DynamicItemFields is case insensitive, so the below samples will work: @Fields.Header @Fields.header Checking ItemFields For Values The DynamicItemFields class will return null if no property name exists in the ItemFields, or if no value was input for single-valued fields. This will work even if no MetaData Schema has been provided for a Tridion Item. Below are examples of checking: @if (Fields.SubHeader != null) { <h2>@Fields.SubHeader</h2> } <title>@(Fields.SubHeader ?? Page.Title)</title> If you are not familiar with the above syntax, it could also be written like the example below. You have the complete C# 4.0 syntax at your command. <title>@(Fields.SubHeader != null ? Fields.SubHeader : Page.Title)</title> Remember, multi-valued fields will always return a List<T> type (as long as the key exists), so for multivalued fields that have a key specified, you can check against the count. @if (Fields.SomeMultiValuedField.Count > 0) { <p>We Have Item! Total: @Fields.SomeMultiValuedField.Count</p> } If you just want to check to see if a key even exists in the ItemFields or not, you can call the HasField(string fieldname) method. @if (Fields.HasField(“SubHeader”)) { <div>ItemField ‘SubHeader’ Exists and Has Value of: @Fields.SubHeader</div> } The HasField method can be useful when your template is working with different schemas and you want to make sure a specific field exists. Handling Embedded Fields As mentioned in the chart above, field types of EmbeddedSchemaField will return a DynamicItemFields object. The syntax works pretty much like working with embedded schema fields within a Dreamweaver Template. @Component.Fields.TheEmbeddedSchemaField.AFieldName If the embedded schema field contains another embedded schema field, you can just continue the nesting. @Component.Metadata.TheEmbeddedSchemaField.AnotherEmbeddedField.SomeDate If the embedded field is a multi-valued field, you can just loop over it with a foreach loop. The below example is if the two levels of embedded schema fields in the above sample were mutli-valued. @foreach (var field in Metadata.TheEmbeddedSchemaFields) { <div>@field.AFieldName</div> @foreach (var innerField in field.AnotherEmbeddedFields) { <span>@innerField.SomeDate</span> } } You can also use for loops. @for (int i = 0; i < Metadata.EmbeddedSchemaFields.Count; i++) { <div>@Metadata.EmbeddedSchemaFields[i].AFieldName</div> } Handling Component Links Component Links work similar to Embedded Fields. The below samples show the full syntax of retrieving values from a Component Link field. (See the section on shortcuts for a quicker syntax.) @Component.Fields.CompLink.Fields.FieldName If the component in the Component Link field contains another component link, you can just continue the nesting. @Component.Metadata.CompLink.Fields.AotherCompLink.Fields.AnotherFieldName If the component link field is a multi-valued field, you can just loop over it with a foreach loop. The below example is if the two levels of component link fields were multi-valued. @foreach (var c in Metadata.CompLinks) { <div>@c.Fields.AFieldName</div> @foreach (var innerComp in c.Fields.MoreCompLinks) { <span>@innerComp.Fields.AnotherFieldName</span> } } You can also use for loops. @for (int i = 0; i < Fields.CompLinks; i++) { <div>@Fields.CompLinks[i].Fields.AFieldName</div> <div>@Fields.CompLinks[i].AFieldName</div> @* This shortcut would work too *@ } Model Class ItemField Shortcuts The Model class wrappers contains shortcuts for accessing Fields and/or Metadata. You can access an itemfield directly, as long as a property of that name doesn’t already exist. For example, the following is equivalent: @Component.Fields.SomeFieldName @Component.SomeFieldName @Component.MetaData.AnotherField @Component.AnotherField For ComponentModels, the shortcut access to item fields will check the Fields first, and then the Metadata. Note that if the ItemField name has the same name as a property of the class, the property is returned and not the value of the ItemField. For example: @Component.Fields.Title @Component.Title The above example will not return the same value. The first will access an ItemField with the name of “Title”, while the second example will return the Component’s Title. Important Note on Dynamic Objects It is important to know that the shortcut properties will only work if a keyword is “dynamic”. For example, to be able to use the ItemField shortcuts for ComponentModel’s while looping a collection of ComponentLink fields, you must do the following: @foreach (dynamic c in Fields.SomeComponentLinks) { <text>The header is @c.Header</text> @* this is a shortcut for @c.Fields.Header *@ } The following will cause an Exception to be thrown: @foreach (var c in Fields.SomeComponentLinks) { <text>The header is @c.Header</text> @* THIS WILL BREAK *@ } @foreach (ComponentModel c in Fields.SomeComponentLinks) { <text>The header is @c.Header</text> @* THIS WILL ALSO BREAK *@ } The shortcut syntax is especially useful when accessing items in for loops. @Fields.CompLinks[i].Fields.FieldName @Fields.CompLinks[i].FieldName @* Shortcut syntax *@ @Fields.CompLinks[i].Fields.MoreLinks[x].Fields.FieldName @Fields.CompLinks[i].MoreLinks[x].FieldName @* Shortcut syntax *@ The DynamicPackage Object NOTE this functionality has not been tested. Please report issues if found. From the base template, you can directly access the Package property. Note that this is not the Tridion package instance, but rather a dynamic wrapper of that instance. Like the DynamicItemFields, the DynamicPackage allows you to use Dot Notation to access items in the Package. For example, if you had a C# TBB that pushes out a string item named “foo_bar”, you can access that string directly by: @Package.foo_bar The return type of a property of the DynamicPackage item is dynamic. ContentType Return Type Component ComponentArray ComponentPresentationArray Everything Else ComponentModel List<ComponentModel> List<ComponentPresentationModel> String Accessing the Tridion Package and Engine Objects If you need to access the Tridion Package and Engine objects from your Razor Templates, you can use the TridionHelper property. @TridionHelper.Engine @TridionHelper.Package Accessing the Page Object from a Component Template The @Page variable will work not only in a Page template, but a Component Template as well. If the Page object cannot be found (ie a Dynamic Component Presentation or previewing a CT) @Page will return null. Because of that, if you are trying to access the Page object from a CT, you should first check if the value is not null. Otherwise you might run into a null reference exception (“Object reference not set to an instance of an object.”) when trying to access the Page’s fields. @if (Page != null) { <h3>@Page.MetaData.PageSubHeader</h3> } Razor Syntax / DWT Comparison Syntax / Sample Razor DWT Code Block @{ N/A, you can’t create or set variables from a DWT. This can be a good thing depending on your approach as to what should be contained within this type of template building block. int x = 123; string y = “because.”; var greeting = “Hello”; } Expression Combining Text and Markup <div>@greeting</div> <span>@Component.Title</span> @foreach (var cp in ComponentPresentations) { <h1>Page: @Page.Title</h1> <span>@@Component.Title@@</span> <!-- TemplateBeginRepeat name=”Components” --> <h2>Component: @cp.Component.Title</h2> <h3>Template: @cp.Template.Title</h3> <div> @cp.RenderComponentPresentation() </div> } If / Else Statements @if (Component.Schema.Title.Equals(“News Article”)) { <div>Do some stuff…</div> } else { <div>Do some other stuff…</div> } Mixing Code and Plain Text @if (someVariable) { <text>Plain Text is @someVariable</text> } Escaping the @ sign Comments <span>In Razor, you use double @@ to escape the @@ symbol.</span> Accessing Component Link Fields Nested Nested Component Link Fields Formatting DateFields Adding Using Statements for Use in your Template Adding Functions Within Your Template Adding Helper Functions Within Your Template <h1>Page: @@Page.Title@@</h1> <h2>Component: @@Component.Title@@</h2> <h3>Template: @@ComponentTemplate.Title@@</h3> <div> @@RenderComponentPresentation()@@ </div> <!-- TemplateEndRepeat --> <!-- TemplateBeginIf cond=”Component.Schema.Title = ‘News Article’” --> <div>Do some stuff…</div> <!-- TemplateEndIf --> <!-- TemplateBeginIf cond=”Component.Schema.Title != ‘News Article’” --> <div>Do some other stuff…</div> <!-- TemplateEndIf --> <!-- TemplateBeginIf cond=”someVariable” --> Plain Text is @@someVariable@@ <!-- TemplateEndIf --> @* This is a comment *@ @* So is this here. *@ @foreach (var cLink in Component.Fields.SomeCLinks) { <div>ID: @cLink.ID</div> <div>Title: @cLink.Title</div> <div>Fields:<br /> @cLink.Fields.SomeField @cLink.Fields.AnotherField </div> } @foreach (var p in Component.Fields.Products) { <h3>@p.Fields.Header</h3> <div>@HtmlEncode(p.Fields.Summary)</div> <ul> @foreach (var link in p.Fields.Links) { <li class=”@link.Fields.LinkClass”>@link.Fields.LinkHeader</li> } </ul> } <p>The News Date is @Component.Fields.NewsDateField.ToString(“MMM d”)</p> <p>This would always show the date this was published: @DateTime.Now.ToString(“MMM dd, yyyy”)</p> @using System.Text @using Tridion.ContentManagement @functions { public string Test(string name) { return “Hello “ + name + “!”; } } <div>@Test(“Administrator”)</div> @helper Test(string name) { <div>Hello @name!</div> } <div>@Test(“Administrator”)</div> You can’t access a component link field directly in a DWT. Not without the help of a TBB or custom function (like the Get Extensions). You wouldn’t be able to get fields out like this from your DWT. You’d have to write some TBB or Custom Functions to aid you in this task. Notice how easy it is to grab items from an outer loop. Unable to directly. Again, you’d have to use a TBB to push the values out, or use custom DW functions. With Razor, you have full access to .NET code. N/A Dreamweaver Custom Function. Dreamweaver Custom Function. Note that a Helper function returns Razor Syntax, unlike the above @functions declaration. Razor Mediator Templating and API Reference Variable and templating reference with samples. From The Tridion Razor Template Base The following is callable directly from your templates, as they are properties and methods of the TridionRazorTemplate base. TemplatingLogger Log Gets the Tridion TemplatingLogger instance. @Log.Debug(“This is a debug statement”) ComponentModel Component Gets the Component in the package. A name “Component” item must exist in the package (Component Template). @Component.Title DynamicItemFields Fields Shortcut to @Component.Fields @Fields.FieldName FolderModel Folder Shortcut for @Component.Folder. Must have access to the Component. @if (!Folder.IsRoot) { <div>Parent Folder Title is: @Folder.Parent.Title</div> } DynamicItemFields MetaData / DynamicItemFields Metadata Shortcut to @Component.MetaData <span>@Metadata.FieldName is the same as @MetaData.FieldName is the same as @Component.Metadata.FieldName</span> ModelUtilities Models Gets the ModelUtilities helper class, which allows you to get Model wrappers from your template. @Models.GetComponent(“tcm:23-233”).Fields.SubjectHeader @Models.GetPage(“tcm:23-555-64”).MetaData.FieldName DynamicPackage Package Gets the DynamicPackage item. See “The DynamicPackage Object” section for more reference. @Package.Output PageModel Page Gets the template’s Page. NOTE: This will work in a Page Template OR a Component Template. To work in a CT, the CT must be a component presentation on a page. Using the Page property from a CT can cause problems for dynamic component presentations and previewing CTs. As mentioned in an earlier section, if accessing the Page from a CT, you should check to see if its null first. <div>@Page.FileName</div> PublicationModel Publication Gets the current context Publication of the template. <span>The root folder’s title is: @Publication.RootFolder.Title</span> String RenderMode Gets the RenderMode. “Publish”, “PreviewDynamic”, and “PreviewStatic”. @if (RenderMode.Equals(“Publish”)) { <span>This is a way to render this only when publishing and not previewing.</span> } StructureGroupModel StructureGroup Gets the Page’s StructureGroup. Shortcut for @Page.StructureGroup. Note that the template must be able to access the Page property. <strong> This SG contains @StructureGroup.StructureGroups.Count StructureGroups in it. </strong> Template Template Gets the Tridion Compound Template being executed. @Template.Id : @Template.Title TridionUtilities TridionHelper Gets a helper class that contains some utility functions for Tridion. the Tridion Engine and Package object. @TridionHelper.Engine.GetObject(“tcm:15-5502”) @TridionHelper.Package.GetValue(“ValueToGet”) Also exposes bool IsComponentTemplate Gets whether or not the template is a Component Template. @if (IsComponentTemplate) { <div>Component Title: @Component.Title</div> } bool IsPageTemplate Gets whether or not the template is a Page Template. @if (IsPageTemplate) { <div>Page Title: @Page.Title</div> } List<ComponentPresentationModel> ComponentPresentations Gets a list of the component presentations. There must be a “Components” items in the package (like in a Page Template). @foreach (var cp in ComponentPresentations) { cp.RenderComponentPresentation(); } List<ComponentPresentationModel> GetComponentPresentationsByTemplate(string templateName) Gets a list of Component Presentations filtered by the template name. @foreach (var cp in GetComponentPresentationsByTemplate(“News Content Summary”)) { cp.RenderComponentPresentation(); } String RenderComponentPresentation(TcmUri componentID, TcmUri templateID) String RenderComponentPresentation(string componentID, string templateID) Renders a component presentation. @RenderComponentPresentation(“tcm:3-1343”, “tcm:3-2334-32”) String HtmlDecode(string textToDecode) Converts a HTML encoded string into a decoded string. @HtmlDecode(Fields.Header) String HtmlEncode(string textToEncode) Converts a string into a HTML encoded string. @HtmlEncode(Fields.Header) String UrlDecode(stringToDecode) Converts an URL encoded string into a decoded string. @UrlDecode(MetaData.BaseUrl) String UrlEncode(string textToEncode) Converst a string into a URL encoded string. @UrlEncode(MetaData.BaseUrl) String StripHtml(string text) Strips a string of html elements. @StripHtml(Fields.BodyText) String RenderComponentField(string fieldExpression, int fieldIndex) String RenderComponentField(string fieldExpression, int fieldIndex, string value) String RenderComponentField(string fieldExpression, int fieldIndex, bool htmlEncodeResult, bool resolveHtmlAsRTFContent) The Tridion Razor Template Base also offers the following Built In Functions, which can be used just like equivalent in the Dreamweaver Templates (useful for SiteEdit). ModelUtilities The ModelUtilities class provides a wrapper of the engine.GetObject() to easily retrieve the specially wrapped Model classes. You can access the ModelUtilities directly from the @Models property of the base template. ComponentModel GetComponent(string itemUriOrWebDavUrl) ComponentModel GetComponent(TcmUri tcmUri) Retrieves a Component from the CMS. @Models.GetComponent(“tcm:15-200”).Fields.FieldName @foreach (dynamic c in Models.GetComponent(“tcm:17-2345”).Fields.SomeComponentLinks) { <div>@c.Title</div> } FolderModel GetFolder(string itemUriOrWebDavUrl) FolderModel GetFolder(TcmUri tcmUri) Retrieves a Folder from the CMS. @Models.GetFolder(“tcm:15-201-2”).Title KeywordModel GetKeyword(string itemUriOrWebDavUrl) KeywordModel GetKeyword(TcmUri tcmUri) Retrieves a Keyword from the CMS. @Models.GetKeyword(“tcm:15-3456-1024”).Key PageModel GetPage(string itemUriOrWebDavUrl) PageModel GetPage(TcmUri tcmUri) Retrieves a Page from the CMS. @Models.GetPage(“tcm:15-202-64”).FileName StructureGroupModel GetStructureGroup(string itemUriOrWebDavUrl) StructureGroupModel GetStructureGroup(TcmUri tcmUri) Retrieves a StructureGroup from the CMS. @Models.GetStructureGroup(“tcm:15-300-4”).Parent.Title ComponentPresentationModel Represents a ComponentPresentation, and has the following properties and methods. String ComponentID String ComponentUri Gets the Component’s Tcm Uri. @foreach(var cp in ComponentPresentations) { <div>@cp.ComponentID</div> } String TemplateID String TemplateUri Gets the Template’s Tcm Uri. @foreach(var cp in ComponentPresentations) { <div>@cp.TemplateID</div> } ComponentModel Component Gets the Component. @foreach(var cp in ComponentPresentations) { <div>@cp.Component.Fields.FieldName</div> } ComponentTemplate Template Gets the ComponentTemplate @foreach(var cp in ComponentPresentations) { <div>@cp.Template.Title</div> } String RenderComponentPresentation() Renders the Component Presentation. @foreach(var cp in ComponentPresentations) { <text>@cp.RenderComponentPresentation()</text> } PublicationModel A wrapper class for the Tridion Publication object. DynamicItemFields Fields DynamicItemFields MetaData DynamicItemFields Metadata Gets the Publication’s metadata fields. @Publication.Fields.FieldName TcmUri ID TcmUri Id Gets the Publication’s Tcm Uri. @Publication.Id or @Publication.ID String MultimediaPath Gets the path to the directory containing published binaries. @Publication.MultimediaPath String MultimediaUrl Gets the URL to the directory containing published binaries. @Publication.MultimediaUrl String PublicationPath Gets the publication publish path. @Publication.PublicationPath String PublicationUrl Gets the publication publish URL. @Publication.PublicationUrl FolderModel RootFolder Gets the Publication’s root Folder. @Publication.RootFolder.ID StructureGroupModel RootStructureGroup Gets the Publication’s root StructureGroup. @Publication.RootStructureGroup.Title String Title Gets the Publication’s title. @Publication.Title String WebDavUrl Gets the Publication’s WebDavUrl @Publication.WebDavUrl String ToString() Returns the Publication’s Title. @Publication @* Will display the tcm uri of the Publication *@ AbstractRepositoryLocalObject All of the Model wrapped classes, with the exception of the PublicationModel and ComponentPresentationModel above, inherit this class and will have access to the following properties. DynamicItemFields Fields DynamicItemFields MetaData DynamicItemFields Metadata Gets the Item’s Metadata fields. @StructureGroup.Metadata.SomeField TcmUri ID TcmUri Id Gets the Item’s Tcm Uri. @Folder.Id or @Folder.ID Bool IsLocalized Gets whether or not the Item is localized in the current context Publication. @if (Component.IsLocalized) { <span>The component is localized.</span> } Bool IsShared Gets whether or not the Item is shared in the current context Publication. @if (Page.IsShared) { <span>The page is shared.</span> } Dynamic OrganizationalItem Gets the organizational item that contains this Tridion object. Will return a Category, FolderModel, StructureGroupModel or VirtualFolder. @Publication.Id or @Publication.ID String Path Gets the full path to the item. @Component.Path PublicationModel Publication Gets the Item’s Context Repository. @Component.Publication.Id String Title Gets the Item’s title. @Page.Title T TridionObject Gets the underlying Tridion Object. @Page.TridionObject @* will return the underlying Tridion Page object *@ String WebDavUrl Gets the WebDAV URL of the Item. @Component.WebDavUrl String ToString() Returns the Item’s title. @Page ComponentModel The ComponentModel has all the properties of the AbstractRepositoryLocalObject, with the following addition or overwritten ones. Schema Schema Gets the Component’s Schema. @Component.Schema DynamicItemFields Fields Gets the Component’s fields. @Component.Fields.FieldName FolderModel Folder Gets the WebDAV URL of the Item. @Component.WebDavUrl String ToString() Returns the Component’s Tcm Uri. @Component FolderModel The FolderModel represents a Tridion Folder, and has all the properties from AbstractRepositoryLocalObject, with the following additional or overwritten properties. List<ComponentModel> Components Gets the child Components of this Folder (non-recursive). @foreach(var component in Folder.Components) { <div>@component.Title</div> } List<FolderModel> Folders Gets the child Folders of this Folder (non-recursive). @foreach(var folder in Component.Folder.Folders) { <div>@folder.Title</div> } Bool IsRoot Whether or not the Folder is the root. @if (Folder.IsRoot) { <span>@Folder.Title is the root.</span> } FolderModel Parent Gets the parent folder. @Folder.Parent.Title KeywordModel String Description Gets the description of the keyword. @Fields.KeywordField.Description Bool IsAbstract Gets whether or not the Keyword is abstract. @if (Fields.KeywordField.IsAbstract) { <span>@Fields.KeywordField.Title is Abstract!!!</span> } Bool IsRoot Gets whether or not the Keyword is a root keyword (no parent keywords) @if (Fields.KeywordField.IsRoot) { <span>@Fields.KeywordField.Title is a root keyword!!! Yay.</span> } String Key Gets the key of the keyword. @Fields.KeywordField.Key PageModel The PageModel represents a Tridion Page, and has all the properties from AbstractRepositoryLocalObject, with the following additional or overwritten properties. List<ComponentPresentationModel> ComponentPresentations Gets the Page’s Component Presentations. @foreach (var cp in Page.ComponentPresentations) { <text>@cp.RenderComponentPresentation()</text> } String FileName Gets the Page’s filename. @Page.FileName StructureGroupModel StructureGroup Gets the Page’s StructureGroup. @Page.StructureGroup.Title String PublishLocationPath Gets the publish path for the Page, including the filename and extension. @Page.PublishLocationPath String PublishLocationUrl Gets the publish URL for the Page. @Page.PublishLocationUrl String PublishPath Gets the publish path of the page, excluding filename and extension. @Page.PublishPath StructureGroupModel The StructureGroupModel represents a Tridion StructureGroup, and has all the properties from AbstractRepositoryLocalObject, with the following additional or overwritten properties. Bool IsRoot Gets whether or not this is the root StructureGroup in a Publication. @if (StructureGroup.IsRoot) { <div>It’s the root!</div> } List<PageModel> Pages Gets all the Pages that are contained within this StructureGroup. @foreach (var page in Page.StructureGroup.Pages) { <div>@page.Title</div> } StructureGroupModel Parent Gets the parent StructureGroup. @Page.StructureGroup.Parent.Title List<StructureGroupModel> StructureGroups Gets all the children StructureGroups of this StructureGroup (non-recursive). @foreach (var sg in StructureGroup.StructureGroups) { <div>@sg.Title</div> } Future of the Razor Mediator Planned Version 1.1-1.4 : Bug Fixes, Performance Enhancements, Minor Features Requests Version 1.5 : Helper and Template Includes Support – Ability to include helper and template functions from either another Razor TBB or even externally from a file on the server. Version 2.0 : Master Templates – Have your templates share the layout from a Master Template. Bugs / Feature Requests For any bugs found or requests for features in future versions of the Tridion Razor Mediator, feel free to contact me at alex@tahzoo.com. Please add “Razor Mediator” to the subject line.