开发者

NVelocity not finding the template

I'm having some difficulty with using NVelocity in an ASP.NET MVC application. I'm using it as a way of generating emails.

As far as I can make out the details I'm passing are all correct, but it fails to load the template.

Here is the code:

private const string defaultTemplatePath = "Views\\EmailTemplates\\";

...

velocityEngine = new VelocityEngine();
basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, defaultTemplatePath);
ExtendedProperties properties = new ExtendedProperties();
properties.Add(RuntimeConstants.RESOURCE_LOADER, "file");
properties.Add(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, basePath);
velocityEngine.Init(properties);

The basePath is the correct directory, I've pasted the value into explorer to ensure it is correct.

if (!velocityEngine.TemplateExists(name))
    throw new InvalidOperationException(string.Format("Could not find a template named '{0}'", n开发者_Go百科ame));


Template result = velocityEngine.GetTemplate(name);

'name' above is a valid filename in the folder defined as basePath above. However, TemplateExists returns false. If I comment that conditional out and let it fail on the GetTemplate method call the stack trace looks like this:

   at NVelocity.Runtime.Resource.ResourceManagerImpl.LoadResource(String resourceName, ResourceType resourceType, String encoding)
   at NVelocity.Runtime.Resource.ResourceManagerImpl.GetResource(String resourceName, ResourceType resourceType, String encoding)
   at NVelocity.Runtime.RuntimeInstance.GetTemplate(String name, String encoding)
   at NVelocity.Runtime.RuntimeInstance.GetTemplate(String name)
   at NVelocity.App.VelocityEngine.GetTemplate(String name)
...

I'm now at a bit of an impasse. I feel that the answer is blindingly obvious, but I just can't seem to see it at the moment.


Have you considered using Castle's NVelocityTemplateEngine?

Download from the "TemplateEngine Component 1.1 - September 29th, 2009" section and reference the following assemblies:

using Castle.Components.Common.TemplateEngine.NVelocityTemplateEngine;
using Castle.Components.Common.TemplateEngine;

Then you can simply call:

using (var writer = new StringWriter())
{
    _templateEngine.Process(data, string.Empty, writer, _templateContents);
    return writer.ToString();
}

Where:

  • _templateEngine is your NVelocityTemplateEngine
  • data is your Dictionary of information (I'm using a Dictionary to enable me to access objects by a key ($objectKeyName) in my template.
  • _templateContents is the actual template string itself.

I hope this is of help to you!

Just to add, you'll want to put that into a static method returning a string of course!


Had this issue recently - NVelocity needs to be initialised with the location of the template files. In this case mergeValues is an anonymous type so in my template I can just refer to $Values.SomeItem:

    private string Merge(Object mergeValues)
    {
        var velocity = new VelocityEngine();
        var props = new ExtendedProperties();
        props.AddProperty("file.resource.loader.path", @"D:\Path\To\Templates");
        velocity.Init(props);
        var template = velocity.GetTemplate("MailTemplate.vm");
        var context = new VelocityContext();
        context.Put("Values", mergeValues);

        using (var writer = new StringWriter())
        {
            template.Merge(context, writer);
            return writer.ToString();
        }
    }


Try setting the file.resource.loader.path

http://weblogs.asp.net/george_v_reilly/archive/2007/03/06/img-srchttpwwwcodegenerationnetlogosnveloc.aspx


Okay - So I'm managed to get something working but it is a bit of a hack and isn't anywhere near a solution that I want, but it got something working.

Basically, I manually load in the template into a string then pass that string to the velocityEngine.Evaluate() method which writes the result into the the given StringWriter. The side effect of this is that the #parse instructions in the template don't work because it still cannot find the files.

using (StringWriter writer = new StringWriter())
{
    velocityEngine.Evaluate(context, writer, templateName, template);
    return writer.ToString();
}

In the code above templateName is irrelevant as it isn't used. template is the string that contains the entire template that has been pre-loaded from disk.

I'd still appreciate any better solutions as I really don't like this.


The tests are the ultimate authority:

http://fisheye2.atlassian.com/browse/castleproject/NVelocity/trunk/src/NVelocity.Tests/Test/ParserTest.cs?r=6005#l122

Or you could use the TemplateEngine component which is a thin wrapper around NVelocity that makes things easier.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜