Razor Mediator Version 1.3.2 Released

A new minor version of the Razor Mediator has been released and can be found at the Google Code site. For anyone who is interested in installing Razor Mediator on Tridion 2013, you will find this release especially important to you. Prior to this version, the Installer will throw an error and the installation will fail.

Besides being able to install without an error, this version also changes how the configuration is done slightly. Prior to 1.3.2, the template ID for Razor Mediator was generated during installation by selecting the highest free available ID. With an out of the box Tridion setup, this would normally have resulted in a template type of “8″. Tridion 2013 comes with a new XSLT Mediator, but they have left the ID’s of 8 and 9 empty. So, installation for 1.3.2 will attempt to use 8 if its available, otherwise it’ll pick the ID just like it use to do.

An important thing to note is that you may have to manually modify this ID if you are porting from another system that used a different ID for the Mediator. If the ID’s don’t match up, you will get an error during the content porter process.

Thanks to Nicholas Vander Ende, Frank Taylor, and Piti Itharat for reporting and troubleshooting the installation error in 2013. A special thanks to Nicholas for actually finding the fix to the problem as well.

ComponentPresentations and ComponentTemplateModel

Thanks to Chris Curry for spotting that ComponentPresentationModel’s Template property was not returning a ComponentTemplateModel type, but rather just the Tridion’s ComponentTemplate type. This means you would have to grab the ItemFields in order to fetch fields. This version fixes the CompoenntPresentationModel’s Template property.

@foreach (var cp in ComponentPresentations) {
    <div>cp.Template.Fields.FieldName</div>
}

Get Version From Template

Although you can get the Razor Mediator version by looking at the Tridion.ContentManager.config file, sometimes you may not have access to the server and need another quick way to get the version. 1.3.2 comes with a “Version” property in the base template that you can output to check the version.

    <div>Version: @Version</div>

Models.GetComponentTemplate

The ModelUtilities class now comes with a GetComponentTemplate method to easily pull out ComponentTemplateModels.

@{
    var ct = Models.GetComponentTemplate("tcm:1-2345-32");
}

Thanks again to everyone for your feedback and suggestions!

Razor Mediator Version 1.3.1 Released

The next version of the Razor Mediator, version 1.3.1, is now up and ready to be downloaded at its Google Code site, and its updated documentation can be found here. This update includes mainly fixes for issues reported, though it does include a couple of new (or features that were missing) features as well. If after upgrading to version 1.3 and you have been receiving errors while attempting to do imports from the configuration, this may be the release for you!

Fixes for Imports

As mentioned, version 1.3 caused some issues when trying to use the new Where Used functionality along with global imports from the configuration. Errors included messages similar to “tcm:0-234-2048 does not exist”.

Fixes to Documentation

Thanks to Robert Curlette for supplying documentation that removed the smart quotes from the code samples in the documentation. The new version of the documentation and forward will be based off of his ascii documentation.

Non-Cache DynamicPackage

Thanks to Dominic Cronin for supplying a patch for the DynamicPackage to make it not cache the package’s values. This will ensure you don’t run into issues if the context of those package items gets changed during the razor’s scope.

Indexes for DynamicItemFields and DynamicPackage

You can now access fields for ItemFields and for the Package using indexers. This can help when creating generic templates, or when working with package items that contain dots in the item names.

@Fields["FieldName"]
@Package["SomeName"]
@Package["Some.Name.With.Dots"]

GetFields and GetFieldNames

Also to assist with the creation of making generic templates, DynamicItemFields now has a GetFields() and a GetFieldNames() method. GetFieldNames() returns an array of strings containing the field names, while GetFields() returns the underlying Dictionary<string, object> that represents the ItemFields.

@foreach (string name in @Fields.GetFieldNames()) {
    <span><strong>@name</strong>: @Fields[name]</span>
}

// var field is of type KeyValuePair<string, object>
@foreach (var field in @Fields.GetFields()) {
    <span><strong>@field.Key</strong>: @field.Value</span>
}

Fix to IsSiteEditEnabled

The IsSiteEditEnabled property would throw an error when working with a Publication Target that never had its Site Edit enabled or disabled yet. This is now fixed.

ParentKeywords and RelatedKeywords

These properties have been added to the KeywordModel, and both return a List of KeywordModel’s.

@foreach (var kw in @Fields.SomeKeyword.ParentKeywords) {
    <span>@kw.Title</span>
}

Thanks again to everyone who has been posting suggestions, issues, and fixes. Special thanks to Robert Curlette who has been the guinea pig for most of these updates!

Razor Mediator Version 1.3 Released

Its taken much longer than I had originally anticipated, but the next version of the Razor Mediator has just been submitted to the SDL team. As usual, you can find the installer for this package here and the updated documentation for this version here. So what exactly is new in this package?

Working Where Used Functionality

Have a lot of Razor Imports and sad because its hard to track down where exactly they are used? Or have the blues from Content Porting since you have to make sure you CP your import files first before the rest of your Razor Templates? The great news is that with Version 1.3, including razor imports either through importRazor(“path”) statements or via the razor.mediator configuration setting will now finally be set as a reference so that these imports show up as Where Used! Just in case for some odd reason you absolutely do not like this features, there is also a new element in the config called “importSettings”, which allows you to turn on/off this feature. You can even turn on/off imports from importRazor statements and imports from the configuration separately.

<importSettings includeConfigWhereUsed="true" includeImportWhereUsed="true" replaceRelativePaths="false" />

The Where Used won’t kick in automatically once you upgrade to this version… you’ll have to Save your Razor Templates for the references to take place.

Relative WebDav URLs Supported!

Thanks’s to Will Price for suggesting this one! Import statements in version 1.2 only accepted TcmUri’s and full lengthy WebDav URL’s. As of Version 1.3, you can now supply relative WebDav URL paths! These paths to the imports are relative to the Razor Template that’s calling them.

@importRazor("Same Level Helper Functions.cshtml")
@importRazor("./Also Same Level Helper Functions.cshtml")
@importRazor("My Helper Functions/Global Helper Functions.cshtml")
@importRazor("My Helper Functions/Nav Functions/Main Navigation Functions.cshtml")
@importRazor("../Previous Level Functions.cshtml")
@importRazor("../../Even More Previous Level Functions.cshtml")

You probably noticed that “replaceRelativePaths” attribute in the previous importSettings config example? When set to “false” (out of the box setting), your relative import paths will stay relative. But if for some reason you would like these to automatically be transformed into the full WebDav URL, set this to true and upon saving your templates, the paths will be turned into the full paths.

Site Edit Enabled!

Razor Mediator 1.3 now includes a property named “IsSiteEditEnabled”. As the name may suggest, this property will check the Publication Target you are publishing to to see whether or not SiteEdit (inline editing) is enabled. This is useful for when you want to render specific HTML (like regions!) only for your editable staging site. This only works for Tridion UI 2012, and not previous versions of SiteEdit.

@if (IsSiteEditEnabled) {
    <strong>This page is SiteEdit Enabled!</strong>
}

Also added by default to version 1.3 is an enhancement request that came in for the RenderComponentField methods. Prior to Version 1.3, these methods would throw an error if the field was empty. Now these methods will spit out an empty tcdl tag. You can also have it spit out an empty string by using the new last argument to this field. The following is assuming that “Fields.FieldName” is empty.

@RenderComponentField("Fields.FieldName", 0)
@RenderComponentField("Fields.FieldName", 0, false)

In the first example, an empty tcdl tag like <tcdl:ComponentField name=”Fields.FieldName” index=”0″></tcdl:ComponentField> will get output so that you still have a section on your staging page for adding text to this area. The second example will just output an empty string and no tcdl tag.

Template Models

Version 1.3 now includes Template Models for the quick and easy access to template metadata that you have grown use to! @ComponentTemplate (accessible only from Component Templates), @PageTemplate and @Page.PageTemplate (accessible only when there’s a page that’s accessible), and @RazorTemplate (the Razor Template Building Block itself).

@if (IsComponentTemplate) {
    <span>@ComponentTemplate.Metadata.FieldName</span>
}

@if (Page != null) {
    <text>The following can be accessed from both Page Templates and Component Templates (only when a Page object is available though)</text>
    <span>@PageTemplate.Metadata.FieldName or @Page.PageTemplate.Metadata.FieldName</span>
}

@if (IsPageTemplate) {
    <text>While this example will only work when its a Page Template.</text>
    <span>@PageTemplate.Metadata.FieldName or @Page.PageTemplate.Metadata.FieldName</span>
}

<span>@RazorTemplate.Metadata.FieldName</span>

Other Changes and Fixes

For a full list of updates and fixes that were made in this version, please check out the Change Log.

Thanks To You

And I just wanted to personally thank everyone who has supported this project through kind comments, reporting issues, bugs and suggestions, and for testing the many features. This project definitely would not have come this far without you guys. :)

Razor Helpers and Functions

Now that the latest version of the Razor Mediator for Tridion (v 1.2) allows you to import, I thought perhaps it would be helpful if I go over the Razor syntax for creating Razor Helper functions, or just adding normal functions in general.  Using these in your Razor Templates greatly enhances the functionality that you can perform in your templates.  On my latest project at a client, we developed some pretty advanced templates, and I found myself thinking (and shuddering) of how it would have to have been done if done using Dreamweaver templating.

Normal Functions

You can declare functions in your Razor code and call it just like you were calling any of the built in functions using @functions. Remember, you can have as many @functions sections as you want in your templates, you are not just limited to one.

@functions {
    public string HelloWorld(string name) {
        return "Hello " + name;
    }
}

The above defines a function called “HelloWorld” that you can start using in your template code (or callable in other functions).

<strong>@HelloWorld("John")</strong>

Helper Functions

Helper Functions are also callable via your template code, however Helper Functions allows for Razor syntax and HTML markup from within the function itself.

@helper HelloWorld(string name) {
    <div>Hello <em>@name</em>!</div>
}

The Helper Function would then work exactly the same as the non-Helper Function created above.

<strong>@HelloWorld("John")</strong>

You can mix and match your functions as well.  Following is just a couple more quick examples.

@functions {
    public string GetExtraAttributes(Models.ComponentModel component) {
        string attributes = String.Empty;
        if (component.Metadata.KeyValuePairs != null) {
            foreach (var values in component.Metadata.KeyValuePairs) {
                attributes += String.Format("{0}="{1}"", values.Key, values.Value);
            }
        }
        return attributes;
    }
}

@helper RenderComponentLink(Models.ComponentModel component) {
    <a href="@component.ID" @GetExtraAttributes(component)>@component.Title</a>
}

@helper WrapInParagraphTags(string input) {
    if (input != null && !input.StartsWith("<p")) {
        <p>@input</p>
    } else {
        @input
    }
}

Razor Mediator 4 Tridion Version 1.2 Released

Hi readers! My apologies for the lack of blog writing over the past month, but things have been extremely busy on the development front. After much feedback and help with testing from colleagues, I am pleased to announce the release of the Razor Mediator Version 1.2. I put it up for submission to SDL Tridion World yesterday, but if you can’t wait, you can also grab it at its Google Code Project Site. There are a lot of fixes, updates, and new features added to this version, so you can probably expect some more posts coming soon with even more examples and tutorials than what is in the new updated documentation. So, what are some of these new updates and features you ask?

Ability to Import!

That’s right, you heard correctly. You can now import other Razor Template Building Blocks or even external Razor Templates stored in text files on the CMS Server to your templates. You can do this globally via the configuration to allow you to import templates to all of your Razor Templates (or even to all of your Razor Templates in one publication), or at the Template level via the @importRazor(“PathToYourTemplate”) command.

Updated GetComponentPresentationsByTemplate and GetComponentPresentationsBySchema

These methods have been updated to accept multiple parameters. So, that means you can now do something like:

@foreach (var cp in GetComponentPresentationsByTemplate("Template One Name", "Template Two Name", "Template Three Name")) {

}

RenderComponentPresentations and RenderComponentPresentationsByTemplate

Two new utility methods have been added to the base template that allows you to just render templates quickly. RenderComponentPresentations() will render all ComponentPresentations on the Page, while RenderComponentPresentationsByTemplate(param string[] templateNames) will only render the ComponentPresentations given the passed template names.

<div id="allTemplates">
    @RenderComponentPresentations()
</div>
<div id="someTemplates">
    @RenderComponentPresentationsByTemplate("Template One Name", "Template Two Name")
</div>

Better Compile Error Message

When you receive a compile error upon saving your Razor Template, you will now be shown a more informative message that also displays the line of code in question. Remember though, that the line of code that is shown is the generated C# code, and not your actual Razor code. This means that “<span>@blasadsfdsaf</span>” would show the line as being “Write(blasadsfdsaf);”. Also, the error displayed to the user in Tridion will no longer include Warning messages.

Index, IsFirst, and IsLast Properties

To further help you write cleaner code, the properties “Index”, “IsFirst” and “IsLast” has been added to the ComponentPresentationModel, ComponentModel, KeywordModel, and DynamicItemFields classes. For ComponentPresentationModels, these properties are automatically set when accessing the ComponentPresentations via the ComponentPresentations property of the base template, or by either of the GetComponentPresentationsByTemplate() or GetComponentPresentationsBySchema() methods.

@foreach (var cp in ComponentPresentations) {
    @if (cp.IsFirst) {
        <div>@cp.Component.Title is the first item.
    } else if (cp.IsLast) {
        <div>@cp.Component.Title is the last item.
    }
}

For ComponentModel and KeywordModel, these properties are automatically set when accessing them via the DynamicItemFields (that is, when they are set as a multi-valued field of course).

@foreach (var kw in Component.Fields.SomeKeywords) {
    <div class="@(kw.Index % 2 == 0 ? "alt1" : "alt2")">@kw.Title</div>
}
@foreach (var comp in Fields.SomeComponents) {
    @if (comp.IsLast) {
        <span>We only wanted the last ComponentLink item!</span>
    }
}

These properties are automatically set for DynamicItemFields when it is accessed via the DynamicItemFields as a multi-valued EmbeddedSchemaField.

@foreach (var embeddedFields in Fields.SomeEmbeddedFields) {
    <div class="@(embeddedFields.IsLast ? "last" : String.Empty)">@embeddedFields.Address (@embeddedFields.ZipCode)</div>
}

Quick Access to Debug Writing

Pre version 1.2, the Razor Mediator documentation said that you could write logging statements like @Log.Debug(“Your Message”). This was actually incorrect and would have thrown an error… you would of had to write them as @{ Log.Debug(“Your Message”); }. As of version 1.2, you can now do @Debug(“Your Debug”), @Info(“Your Info”), @Warning(“Your Warning”), and @Error(“Your Error”).

Of Fixes and More

There are a couple other minor goodies that have been added, as well as some critical fixes and updates that include caching and thread safety (for publishing) fixes. If you are already using a previous version of the Razor Mediator, I would definitely recommend updating to version 1.2. You can view the Change Log on the Google Code project for a full list of all the updates and fixes made in this release.

Version 1.3?

Yes, a Version 1.3 is now in the works, with even more helpers/utilities to make your templating life a bit less difficult, and some more features to help empower your abilities. And of course any more bugs or issues that you report to me. Much thanks to you for your feedback!

Razor Mediator Version 1.1 Released

I am happy to announce that the Razor Mediator version 1.1 has been submitted to SDL to be updated on SDL Tridion World. In the meantime, you can grab the v1.1 installer at its Google Code project site. So what exactly has been updated since version 1.0?

KeywordModel

Just like the other Tridion items that have been wrapped in Model classes, the Keyword class has finally been wrapped as well.  This means you can easily access a Keyword’s metadata just like the other objects as well.

@Fields.SomeKeywordField.Metadata.SomeMetaField

All fields that would normally return a KeywordField will now return a KeywordModel (or List<KeywordModel> for multi-valued fields).  The @Models.GetKeyword(string) method also returns a KeywordModel.

GetComponentPresentationsBySchema(string schemaName)

A new utility method has been added to the base template class to allow you to easily grab all Component Presentations filtered by the component’s schema title.

@foreach (var cp in GetComponentPresentationsBySchema("Article Schema")) {
    <text>@cp.RenderComponentPresentation()</text>
}

DynamicPackage

This feature was listed in version 1.0 but wasn’t actually used.  All calls to the @Package property was really just returning the Tridion Package instance.  So, what exactly can you do with DynamicPackage?  You can easily grab package items and parameter values in your templates using dot notation.  For backwards compatibility, GetByName(string name), GetByType(ContentType type), and GetValue(string name).  The following would all work assuming there was either a package item of a string type named “ItemName” or a parameter field with xml name of “ItemName”.

@Package.ItemName
@Package.GetByName("ItemName").GetAsString()
@Package.GetValue("ItemName")

And some fixes…

Besides the several new features, some fixes were also added.  For a complete list of fixes, feel free to check out the Change Log page.  If you come across more issues, please let me know so that I can get them fixed ASAP. And if you have some cool ideas for possible features that you want to see in the Razor Mediator, shoot them over as well.

What’s Next?

I’m planning on putting an easy way to extend your Razor templates using reusable helper methods and functions.  So look forward to version 1.2 coming out sometime in the hopefully near future, as well as another blog post to show you examples of creating helper methods in your current templates!

Razor Mediator: Including Code From An External DLL

The Razor Mediator allows you to easily add other libraries and namespaces to your Razor templates.  Due to an issue found with version one, you will want to get the latest installer from the Google Code site (or just download the latest version 1.0.1 installer here).  If you have version 1.0.1 or later you should be in the clear and hopefully problem free.

For this tutorial we’re just going to create a really simple class in a separate project and then allow our Razor templates to use that new class. After this tutorial you should have a pretty good understanding of how to use the namespaces and assemblies sections of the razor.mediator configuration.

First, create a new project in Visual Studio.  We’ll name it “RazorSample.Test”.

Next, create the following class in your new project.

namespace RazorSample.Test
{
    public class MyClass
    {
        public static string Hello()
        {
            return "Hello World!";
        }

        public static string Hello(string name)
        {
            return "Hello " + name + "!";
        }
    }
}

I did mention that it would be a simple class! We’ve got two methods and I think it can be safe to assume that I don’t need to explain what they do. Compile the project, and copy the newly created DLL to your CMS server. For this tutorial, I’ve put mine at C:MyLibraryRazorSample.Test.dll.

Next you’ll want to modify the Tridion.ContentManager.config file located at %Tridion Install Path%config on your Tridion CMS server. Search for the razor.mediator section, then update the assemblies section to add your newly created DLL.

<assemblies>
      <add assembly="C:MyLibraryRazorSample.Test.dll" />
</assemblies>

Go ahead and restart the Tridion COM+ package.

Now go ahead and create a new Template Building Block in Tridion called “Razor Test” (or whatever you wish to name it). From the Source tab, make sure to select “RazorTemplate” for the Template Type, and then add the following:

<div>@RazorSample.Test.MyClass.Hello()</div>
<div>@RazorSample.Test.MyClass.Hello(Component.Title)</div>

Save and close. Now go ahead and open up Template Builder and create a new Compound Component Template. Add the “Razor Test” building block from the previous step, and then Run the template using any Component. You should see both of your newly created method returns in the output:

<div>Hello World!</div>
<div>A Test Component!</div>

Congratulations, you’ve just executed code from another assembly in your Razor Template! That’s great and all, but what if you want to load an assembly that’s in the GAC instead of on the file system? In order to get our sample assembly into the GAC, we’ll have to give it a strong name key. If you are unfamiliar with this, just proceed with the following steps.

  1. Right click the RazorSample.Test project in the Solution Explorer of Visual Studio and click Properties.
  2. In the left column, select the Signing tab.
  3. Check the “Sign the assembly” check box.
  4. In the dropdown underneath the “Choose a strong name key file:” label, select “”.
  5. In the Create Strong Name Key dialog, enter “RazorSample.Test” for the Key file name and uncheck the “Protect my key file with a password” option.
  6. Click OK.
  7. Save the project and recompile.

Once you have your RazorSample.Test project recompiled with a Strong Name Key, deploy it to the GAC on the Tridion server. For simplicity, I made the RazorSample.Test project target .NET 3.5 so that I could just drag and drop the DLL to C:Windowsassembly. Once your DLL is deployed to the GAC, edit the assemblies section in the Tridion.ContentManager.config file to look like the following.

<assemblies>
    <add assembly="RazorSample.Test, Version=1.0.1.0, Culture=neutral, PublicKeyToken=60ad7434f03dfcdc" />
</assemblies>

You’ll notice that the only difference in the config between loading it from the GAC and from the file system is that the file system is an absolute file path while the GAC is the fully qualified name.  Remember, your Public Key Token will be different than the one you see above.  If you are unsure how to get the Public Key Token, find your DLL at C:Windowsassembly (assuming that DLL is .NET 3.5 or less).  You’ll see the info you need in the Public Key Token column, or by right clicking your DLL and selecting Properties.  Once the configuration is saved, restart the Tridion COM+ package again. Running the template in Template Builder again should result in the same output.

Now what about the namespaces section? Well unless you don’t mind using the full namespace to your classes, this is where that section will come in hand. Reopen the Tridion.ContentManager.config file once again and modify to look like the following.

<namespaces>
  <add namespace="RazorSample.Test" />
</namespaces>
<assemblies>
  <add assembly="RazorSample.Test, Version=1.0.1.0, Culture=neutral, PublicKeyToken=60ad7434f03dfcdc" />
</assemblies>

After restarting the Tridion COM+ package, reopen your “Razor Test” Razor Template and modify the razor to look like:

<div>@MyClass.Hello()</div>
<div>@MyClass.Hello(Component.Title)</div>

Save and close. Restart the Tridion COM+ package. Retest your template. And enjoy the bliss of adding your own useful functionality to your Razor templates.

Razor Mediator

The story is almost the same from client to client who is using Tridion 5.3 or higher.  They love Compound Templating and like the easiness of the Dreamweaver syntax… however, the power and flexibility of Dreamweaver Templates leaves them feeling like there is just something completely lacking.  How can they get the fields from a Component Link?  How can they get the TemplateRepeatIndex value from an outter repeating region?  How can they do. . . the list of questions and possible frustration just continue to grow from there.

Although a powerful and slick XSLT Mediator already exists on the Tridion eXtensions web site, unless you are comfortable and proficient with XSLT, you may just have an easier time sticking with Dreamweaver Templates and writing C# Template Building Blocks and Custom Functions to get the job done.  Having done a lot of work with ASP.NET MVC, I was really fond of the Razor Templating syntax, and thought it would be pretty cool if we could use that syntax for Tridion templating.  And so a few months ago, I began developing a Razor Mediator, which has now been reviewed and released by SDL Tridion as of the beginning of January.

The mediator can be found at the eXtension site, and the latest code with fixes can be found on its Google Code site.  (Btw, if you want to be a tester or developer on the Razor Mediator project, feel free to contact me and sign up!)

If you haven’t gone over to one of the sites and want to see a quick Razor syntax example, look no further:

<div class=”@Component.Fields.NewsStyle”>
    <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>
    <ul>
    @* Now we'll loop over a ComponentLink field and grab the component title and a field *@
    @foreach (dynamic linkItem in Fields.RelatedItems) {
        <li>@linkItem.Title - @linkItem.Fields.Summary</li>
    }
    </ul>
</div>

The above example shows a typical Component Template.  Notice how easy it is to grab the fields of a multi-valued Component Link field?  Also notice how you can easily format a DateField?  Best yet, notice that when you get the value of a field, the Razor Mediator already knows the field type.  Component Link fields return Components (well, ComponentModels), Text and RichText fields return strings, Date fields return DateTimes, and so on.  No need to worry about your templators needing to learn about casting here.

<html>
<head>
    <title>@(Page.MetaData.HasValue("BrowserTitle") ? Page.MetaData.BrowserTitle : Page.Title)</title>
    <meta name="description" content="@Page.MetaData.MetaDescription" />
    <meta name="keywords" content="@Page.MetaData.Keywords" />
</head>
<body>
    <div id="page">
    @foreach (var cp in ComponentPresentations) {
        <text>@cp.RenderComponentPresentation()</text>
    }
    </div>
</body>
</html>

The above sample demonstrates a typical Page Template that you encounter, where one would want to get the Page’s Meta Data fields as well as output the page’s Component Presentations.  The two samples really only scratch the surface of features and functionality that the Razor Mediator has to offer.  From convenient features to utility functions and even the ability to customize and extend the mediator through the configuration, the mediator will hopefully allow you to do more while writing far less.  And did I mention the installer?

One of the pitfalls of this mediator would probably be the C# style syntax for the templating.  Although developers and programmers might adapt ever so quickly, designers and non-programmer templators might have a bit more difficulty while learning it.  Though, as one of my non-programming designer co-workers said, “Despite the higher learning curve, its much better than working with Dreamweaver Templates.”

For the next few weeks, I’ll be writing some more articles and tutorials regarding the Razor Mediator which will include some cool and advanced tricks that you can do with it, as well as some sneak peeks into the next versions of the Razor Mediator.