In this post I will describe how you can use NVelocity template engine in Sharepoint and what issues will occur with it. Main problem is that NVelocity works well if it is installed in bin folder of you web application. But in Sharepoint development most common case when assemblies are installed into GAC. Ofcourse you can still add NVelocity.dll into bin folder of target Sharepoint web site (if you use WSPBuilder see this post which describes how to install dll into bin folder instead of GAC). But what if you need still install assemblies into GAC (e.g. because of security reasons)? Unfortunately by default NVelocity can not be used from GAC. I will show how to fix this problem for such scenario. Although I will use examples for Sharepoint this post can be used in other cases when you need to use NVelocity from GAC.
First of all a few words about NVelocity. It is template engine ported from Java world into .Net (when I talk about NVelocity I mean implementation from Castle project instead original version – there are several convenient improvements which will be described below). It is quite useful for many scenarios when you need to generate template-based content using set of parameters. For example you need to send emails which are generated based on template. In this case you can use create custom template with placeholders (using curly brackets) and replace them in runtime using regular expressions for example. It will work, but what if you need add iterative blocks into your template? You will need to add this functionality into your custom template engine, fixing more bugs, add more test, etc. Why do we need to create own implementation of things which are already exists? Lets see how NVelocity may help.
It is quite powerful framework which has native supports of loops inside template. Also with NVelocity you can use C# like syntax for your templates. Lets see example. Suppose that we have the following model classes for our email:
Letter has header and several blocks. Now create template for this email using NVelocity:
Here you can find more detailed description of NVelocity improvements made in Castle project. As you can see template code is quite straightforward as we use C# like syntax. We used nested properties $letter.Header.Title and foreach macro for expanding list of blocks. In order to generate email based on this template you can use the following code:
If you use this code in Sharepoint you template files can be located in 12/template/layouts folder. But there is another problem if you install NVelocity.dll into GAC. Running this code the following exception will be thrown:
The specified class for Resourcemanager (NVelocity.Runtime.Resource.ResourceManagerImpl,NVelocity) does not exist.
There are lot of mentions of this problem in internet (e.g. here) but I didn’t find any working complete solution. As you can see NVelocity doesn’t use assembly strong name for type resolution. So if assembly is installed into GAC, this type can not be resolved. Fortunately there are several extension points in NVelocity which can be used to resolve this and several other similar exceptions. We need to add the following code into NVelocity initialization process:
Unfortunately this is not enough as after you added this code you will get another exception:
Could not resolve type NVelocity.Runtime.Directive.Include,NVelocity
at NVelocity.Runtime.Directive.DirectiveManager.Register(String directiveTypeName)
at NVelocity.Runtime.RuntimeInstance.Init(ExtendedProperties p)
at NVelocity.App.VelocityEngine.Init(ExtendedProperties p)
In order to resolve this error we need to dig into NVelocity source code located currently at GitHub and change it. Lets see falling code of RuntimeInstance.initializeDirectives() method:
So it reads values from manifest resource stream (manifest resource name DEFAULT_RUNTIME_DIRECTIVES = NVelocity.Runtime.Defaults.directive.properties) which contains list of classes and creates instances of these classes. File with these classes is located in Runtime/Defaults/directive.properties file in NVelocity solution:
As you can see it doesn’t contains assembly strong name. In order to fix mentioned problem we need to modify this file by adding strong name:
We also need to modify RuntimeInstance.initializeDirectives() method in order to allow NVelocity to read assemblies strong names:
Now recompile NVelocity and reinstall it in GAC. After this you will be able to use it from GAC.