4

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}'", name));


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.

4

5 回答 5

5

您是否考虑过使用 Castle 的NVelocityTemplateEngine

从“TemplateEngine 组件 1.1 - 2009 年 9 月 29 日”部分下载并引用以下程序集:

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

然后你可以简单地调用:

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

在哪里:

  • _templateEngine是你的 NVelocityTemplateEngine
  • data是您的信息字典(我使用字典使我能够通过模板中的键 ($objectKeyName) 访问对象。
  • _templateContents是实际的模板字符串本身。

我希望这对你有帮助!

只是要补充一点,您当然希望将其放入返回字符串的静态方法中!

于 2010-01-22T08:25:11.007 回答
3

最近有这个问题 - NVelocity 需要使用模板文件的位置进行初始化。在这种情况下mergeValues是匿名类型,所以在我的模板中我可以参考$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();
        }
    }
于 2010-08-20T05:09:28.650 回答
2

尝试设置 file.resource.loader.path

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

于 2010-05-24T23:20:47.450 回答
1

好的 - 所以我设法让一些东西工作,但它有点像黑客,并且离我想要的解决方案不远,但它有一些工作。

基本上,我手动将模板加载到一个字符串中,然后将该字符串传递给velocityEngine.Evaluate() 方法,该方法将结果写入给定的StringWriter。这样做的副作用是模板中的#parse 指令不起作用,因为它仍然找不到文件。

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

在上面的代码中 templateName 是无关紧要的,因为它没有被使用。template 是包含已从磁盘预加载的整个模板的字符串。

我仍然很感激任何更好的解决方案,因为我真的不喜欢这样。

于 2009-12-21T15:48:33.877 回答
0

测试是最终权威:

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

或者,您可以使用TemplateEngine 组件,它是 NVelocity 的一个薄包装器,使事情变得更容易。

于 2009-12-31T21:44:39.147 回答