by

Make a Debugging TBB for Tridion 2011 using Razor Mediator

Folks that work with me know that I’m not a super-awesome programmer; I’m a front-end guy who dables with programs. I’m way more comfortable telling you what went wrong with your CSS in Internet Explorer 8 than what happened with your Razor template in Tridion 2011. Razor Mediator for Tridion is a blend of C# and .NET that just operates about two levels higher than where I am most of the time. As a result, I often spend time trying to figure out what information there is on a component and how to grab it. So a few weeks ago, I went from knowing that Razor could access TOM.NET to actually understanding it, and as a result I wrote a little debugging TBB to help other front-end guys looking to figure this thing out.

Razor for Front-End Guys

If you’re a front-end guy who’s spent any time writing page templates and component templates in Tridion, you’re well-acquainted with DWT (Dreamweaver templating). DWT is the least programmy way to put together a page —it’s just some customized HTML tags.  Because DWT isn’t very programmy, it’s perfect for front-end guys whose programming experience hasn’t gone further than JavaScript.  DWT has tons of limitations, though. The moment you want to access something that isn’t on the component itself,  things get exponentially harder as you have to start writing helper TBBs, C# blocks, or worse.  In a Tridion implementation where the only option is DWT, it’s hard for a pure front-end guy to be very useful for very long.

When I encountered Razor for the first time, it was a bit rocky. Because I was more designer than developer, it was harder for me to accept the new way of seeing my TBBs; I had to get used to seeing more ‘programmy’ things mixed in with the markup. Getting used seeing programming gunk mixed with markup is a small hurdle, though. Getting used to the Razor syntax was another. Writing foreach , if,  switch, and other statements was a bit  more difficult because I didn’t know anything about C#. But, JavaScript and C# come from the same family of languages, so if you can write well-formed JavaScript, you can figure out how to write Razor with a little trial and error. Once you get through the learning curve, Razor will save days if not weeks of development time for CTs and PTs. Not only that, the guy writing the HTML can actually build the templates.

Razor for Sharpening Templates

Now, as a front-end guy, I knew that Razor was .NET, and that it accessed the TOM.NET API. But I didn’t always understand that. Again, as a front-end guy, Razor just made it easier to take fields and wrap them in HTML. My understanding of Razor was limited to simply the methods that Alex had put in his documentation.

Razor isn’t just for accessing a few fields on a component, though. Razor lets you access whatever you want on that component. Alex has written kind of ‘short-hand’ methods for things like getting fields and metadata, but the options don’t end with what he wrote in the documentation. You can actually get any property or method that exists on a component — because Razor accesses TOM.NET. All you have to do is access the TridionObject first. So if you’re dealing with a binary schema, and you wanted to get the file name, you can: @Component.TridionObject.BinaryContent.Filename. If you wanted to get the root element of the component’s schema, it’s just @Component.TridionObject.Schema.RootElementName. So not only does Razor make templating more efficient, it makes Tridion templates more powerful.

Building a Debugging TBB for Components

Once it clicked that I could access previously-unavailable properties by starting with TridionObject, I made a ‘debugger TBB’. I cracked open the TOM.NET API documentation, looked at all the properties that exist for the the Component class, and decided to output them. Once I did that, I wrapped it in some pretty HTML, and added a touch of CSS so that it would be easier to read. So take this Razor that you see and add it to a TBB. Then make a Component Template that uses it, and link that CT to all of your schemas in your dev environment. Now you have both a list of stuff you can access, and a way to see all of the stuff you need, for any given component.

What this Razor will tell you:

This will output everything you can imagine:

  • Fields and their values
  • Multimedia information: Filename, filesize, type
  • Schema Information
  • Metadata fields and values
  • Version History
  • Containing folders or publications
  • Keywords
  • Items it uses

Problems you might run into

I’m using Razor 1.3.2 which has the GetFields() method. If you aren’t on 1.3.2, either upgrade, or remove these code blocks.

I also wrote this using HTML5’s summary and details elements, which are browser-based expand/collapse elements. So, when you preview a component using this TBB, use Chrome first.

@using System.IO

<style type="text/css">
table{color: #333; text-align: left; min-width: 400px; border-collapse: collapse; border:1px solid gray;}
th, td {padding: .618em} 
thead th, thead td { font-size: 1.15em; border-bottom: 2px solid #494949; background: #f1f1f1}
tbody th, tbody td {border-bottom:1px solid #555}
tbody td:nth-child(2){}
caption{font-size: .95em}
.compInfo {color: #333}
h1, h2, h3 {border-bottom: 1px solid #456}
details, summary {outline:none}
details {font-size: .75em; paddingborder: 2px solid #f1f1f1; background: #fdfdfd}
summary {font-size: 1.25em; padding: .618em; background: #f1f1f1; border-bottom: 1px solid #456}
summary > * {display:inline-block; margin:0; border:none}
details summary ~ *{margin-left: 1em }
</style>
<div class="compInfo">
	<h1>Title: 
	@Component.Title
	</h1>
	<details>
		<summary>
			<h3>Fields and Values</h3>
		</summary>
		<table>
			<thead>
				<tr>
					<th>Field</th>
					<th>Value</th>
				</tr>
			</thead>
			<tbody>
		@foreach (var field in @Fields.GetFields()) {
		    	<tr>
		    		<th>@field.Key</th>
		    		<td>@field.Value</td>
		    	</tr>
		}
			</tbody>
		</table>
	</details>
	<details>
		<summary>
			<h3>ComponentType: @Component.TridionObject.ComponentType</h3>
		</summary>
		@if(Component.TridionObject.ComponentType.ToString() =="Multimedia"){
			<table>
				<tr>
					<th>
						FileName
					</th>
					<td>
						@Component.TridionObject.BinaryContent.Filename
					</td>
				</tr>
				<tr>
					<th>
						Filesize
					</th>
					<td>
						@Component.TridionObject.BinaryContent.FileSize
					</td>
				</tr>
				<tr>
					<th>
						Is external
					</th>
					<td>
						@Component.TridionObject.BinaryContent.IsExternal
					</td>
				</tr>
				<tr>
					<th>
						MultimediaType
					</th>
					<td>
						@Component.TridionObject.BinaryContent.MultimediaType
						<br />

					</td>
				</tr>
				<tr>
					<th>
						UploadFromFile
					</th>
					<td>
						@Component.TridionObject.BinaryContent.UploadFromFile
					</td>
				</tr>
				<tr>
					<th>
						UploadFromStream
					</th>
					<td>
						@Component.TridionObject.BinaryContent.UploadFromStream
					</td>
				</tr>
			</table>
		}
	</details>
	<details>
		<summary>
			<h3>Schema: @Component.Schema</h3>
		</summary>
	<table>
		<caption>Schema information</caption>
		<tr>
			<th>
				Title
			</th>
			<td>
				@Component.TridionObject.Schema.Title
			</td>
		</tr>
		<tr>
			<th>
				Purpose
			</th>
			<td>
				@Component.TridionObject.Schema.Purpose
			</td>
		</tr>
		<tr>
			<th>
				root element
			</th>
			<td>
				@Component.TridionObject.Schema.RootElementName
			</td>
		</tr>
	</table>
</details>
	<details>
		<summary>
			<h3>Metadata: @(Component.Metadata != null ? "has metadata" : "no metadata ")</h3>
		</summary>
		<h4>metadata schema: 
		@Component.MetadataSchema
		</h4>
		<table>
			<caption>Metadata Fields and Content</caption>
			<thead>
				<tr>
					<th>Field</th>
					<th>Value</th>
				</tr>
			</thead>
			<tbody>
		@foreach (var field in @Component.Metadata.GetFields()) {
		    	<tr>
		    		<th>@field.Key</th>
		    		<td>@field.Value</td>
		    	</tr>
		}
			</tbody>
		</table>
	</details>
	<details>
		<summary>
			<h3>Version and Revision Info</h3>
		</summary>
		<table>
			<tr>
				<th>
					Version
				</th>
				<td>
					@Component.TridionObject.Version
				</td>
			</tr>
			<tr>
				<th>
					Revision Date
				</th>
				<td>
					@Component.TridionObject.RevisionDate
				</td>
			</tr>
			<tr>
				<th>
					Revision
				</th>
				<td>
					@Component.TridionObject.Revision
				</td>
			</tr>	
		</table>
		<table>
			<tr>
				<th>Revisor</th>
				<td>
					@Component.TridionObject.Revisor
				</td>
			<tr>
				<th>description</th>
				<td>
					@Component.TridionObject.Revisor.Description
				</td>
			<tr>
				<th>title</th>
				<td>@Component.TridionObject.Revisor.Title
				</td>
			<tr>
				<th>is admin</th>
				<td>
					@Component.TridionObject.Revisor.IsSystemAdministrator
				</td>
		</table>
	</details>

	<h3>WebDav Url: 
	@Component.WebDavUrl
	</h3>
	<h3>path: 
	@Component.Path
	</h3>
	<h3>Session: 
	@Component.TridionObject.Session
	</h3>
	<details>
		<summary>
			<h3>Owning repository: 
			@Component.TridionObject.OwningRepository
			</h3>
		</summary>
		<table>
			<tr>
				<th>
					Title
				</th>
				<td>
					@Component.TridionObject.OwningRepository.Title
				</td>
			</tr>
			<tr>
				<th>
					Publication Key
				</th>
				<td>
					@Component.TridionObject.OwningRepository.Key
				</td>
			</tr>
			<tr>
			<tr>
				<th>
					Multimedia Path
				</th>
				<td>
					@Component.TridionObject.OwningRepository.MultimediaPath
				</td>
			</tr>
			<tr>
				<th>
					Multimedia URL
				</th>
				<td>
					@Component.TridionObject.OwningRepository.MultimediaUrl
				</td>
			</tr>
			<tr>
				<th>
					HasChildren
				</th>
				<td>
					@Component.TridionObject.OwningRepository.HasChildren
				</td>
			</tr>
			<tr>
				<th>
					RootFolder
				</th>
				<td>
					@Component.TridionObject.OwningRepository.RootFolder
					<br />
					( @Component.TridionObject.OwningRepository.RootFolder.Title	)				
				</td>
			</tr>
			<tr>
				<th>
					RootStructureGroup
				</th>
				<td>
					@Component.TridionObject.OwningRepository.RootStructureGroup
					<br />
					( @Component.TridionObject.OwningRepository.RootStructureGroup.Title )
				</td>
			</tr>

		</table>
	</details>
	<h3>Organization item: 
	@Component.TridionObject.OrganizationalItem
	</h3>

	<h3>LockType: 
	@Component.TridionObject.LockType
	</h3>
	<h3>LoadState: 
	@Component.TridionObject.LoadState
	</h3>
	<h3>IsShared: 
	@Component.IsShared
	</h3>
	<h3>IsPublishedInContext: 
	@Component.TridionObject.IsPublishedInContext
	</h3>
	<h3>IsLocalized: 
	@Component.IsLocalized
	</h3>
	<h3>Allowed Actions: 
	@Component.TridionObject.AllowedActions
	</h3>
	<h3>ApprovalStatus: 
	@Component.TridionObject.ApprovalStatus
	</h3>
</div>
<details>
	<summary>
		<h3>Keywords</h3>
	</summary>
	<table>
	@foreach (var keyword in Component.TridionObject.GetUsedKeywords()){
		<tr>
			<td>@keyword.Id</td>
			<td> @keyword.Title</td>
		</tr>
	}
	</table>
</details>
<details>
	<summary>
		<h3>Items this uses</h3>
	</summary>
	<table>
	@foreach(var usedItem in Component.TridionObject.GetUsedItems()){
		<tr>
			<td>@usedItem.Id</td>
			<td> @usedItem.Title</td>
		</tr>
	}
	</table>
</details>
<details>
	<summary>
		<h3>Items this is used in</h3>
	</summary>
	<table>
	@foreach(var usedItem in Component.TridionObject.GetUsingItems()){
		<tr>
			<td>@usedItem.Id</td>
			<td> @usedItem.Title</td>
		</tr>
	}
	</table>
</details>

2 Comments


  1. //

    Good to see you expanding your comfort-zone. Maybe others will take heart from this and take on the deadly TOM! The best programmers always write code to help them write code, and this is a good example of that. There is some ready-made tooling that might also come in useful in this area. I’m thinking of the ItemXml power tool, and of course, Tridion’s own (often ignored?) default templates.


    1. //

      Thanks Dominic. I’m vaguely aware of the ItemXML Power Tool, but I don’t have it installed with the other power tools I’m using for this particular implementation. But you’re right, that’s a good developer utility.

      And you know… I’m just as guilty as anyone for ignoring those default templates. Good Point.

Comments are closed.