I'm looking to use NVelocity in my ASP.NET MVC application, not as a view engine, just for rendering some email templates.
However, I cann开发者_StackOverflow社区ot for the life of me get it to work. I have downloaded it from the castle project and followed the example at http://www.castleproject.org/others/nvelocity/usingit.html#step1
No matter what I try I don't seem to be able to load a template located in my site. The example suggests using the absolute path, which I have tried to no avail:
Template t = engine.GetTemplate("/Templates/TestEmail.vm");
So please can someone give me two examples. One of loading a template located in the web site directory and secondly one parsing a string variable (as it is likely that my templates will be stored in a database).
Many thanks Ben
I've used this class in one of my past projects:
public interface ITemplateRepository
{
string RenderTemplate(string templateName, IDictionary<string, object> data);
string RenderTemplate(string masterPage, string templateName, IDictionary<string, object> data);
}
public class NVelocityTemplateRepository : ITemplateRepository
{
private readonly string _templatesPath;
public NVelocityTemplateRepository(string templatesPath)
{
_templatesPath = templatesPath;
}
public string RenderTemplate(string templateName, IDictionary<string, object> data)
{
return RenderTemplate(null, templateName, data);
}
public string RenderTemplate(string masterPage, string templateName, IDictionary<string, object> data)
{
if (string.IsNullOrEmpty(templateName))
{
throw new ArgumentException("The \"templateName\" parameter must be specified", "templateName");
}
var name = !string.IsNullOrEmpty(masterPage)
? masterPage : templateName;
var engine = new VelocityEngine();
var props = new ExtendedProperties();
props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, _templatesPath);
engine.Init(props);
var template = engine.GetTemplate(name);
template.Encoding = Encoding.UTF8.BodyName;
var context = new VelocityContext();
var templateData = data ?? new Dictionary<string, object>();
foreach (var key in templateData.Keys)
{
context.Put(key, templateData[key]);
}
if (!string.IsNullOrEmpty(masterPage))
{
context.Put("childContent", templateName);
}
using (var writer = new StringWriter())
{
engine.MergeTemplate(name, context, writer);
return writer.GetStringBuilder().ToString();
}
}
}
In order to instantiate the NVelocityTemplateRepository
class you need to provide an absolute path where your templates root is. Then you use relative paths to reference your vm
files.
I also added the following method to process a string instead of a template file (say if retrieving the template content from a database):
public string RenderTemplateContent(string templateContent, IDictionary<string, object> data)
{
if (string.IsNullOrEmpty(templateContent))
throw new ArgumentException("Template content cannot be null", "templateContent");
var engine = new VelocityEngine();
engine.Init();
var context = GetContext(data);
using (var writer = new StringWriter()) {
engine.Evaluate(context, writer, "", templateContent);
return writer.GetStringBuilder().ToString();
}
}
And used StructureMap to initialize the service:
ForRequestedType<ITemplateService>()
.TheDefault.Is.ConstructedBy(()=>
new NVelocityTemplateService(HttpContext.Current.Server.MapPath("~/Content/Templates/")));
You might find the TemplateEngine component useful.
It's an abstraction over template engines with a NVelocity implementation, similar to Darin's answer, but it should perform marginally better since it uses a single instance of the VelocityEngine (as opposed to initializing one instance per render) and has optional caching. It also has a couple other features, like logging, NVelocity property overriding and loading templates from assembly resources.
精彩评论