Question

I wanted to try getting NVelocity to automatically HTML encode certain strings in my MonoRail app.

I looked through the NVelocity source code and found EventCartridge, which seems to be a class which you can plugin to change various behaviours.

In particular this class has a ReferenceInsert method which would seem to do exactly what I want. It basically gets called just before the value of a reference (e.g. $foobar) gets output, and allows you to modify the results.

What I can't work out is how I configure NVelocity/the MonoRail NVelocity view engine to use my implementation?

The Velocity docs suggest that velocity.properties can contain an entries for adding specific event handlers like this, but I can't find anywhere in the NVelocity source code that looks for this configuration.

Any help greatly appreciated!


Edit: A simple test that shows this working (proof of concept so not production code!)

private VelocityEngine _velocityEngine;
private VelocityContext _velocityContext;

[SetUp]
public void Setup()
{
    _velocityEngine = new VelocityEngine();
    _velocityEngine.Init();

    // creates the context...
    _velocityContext = new VelocityContext();

    // attach a new event cartridge
    _velocityContext.AttachEventCartridge(new EventCartridge());

    // add our custom handler to the ReferenceInsertion event
    _velocityContext.EventCartridge.ReferenceInsertion += EventCartridge_ReferenceInsertion;
}

[Test]
public void EncodeReference()
{
    _velocityContext.Put("thisShouldBeEncoded", "<p>This \"should\" be 'encoded'</p>");

    var writer = new StringWriter();

    var result = _velocityEngine.Evaluate(_velocityContext, writer, "HtmlEncodingEventCartridgeTestFixture.EncodeReference", @"<p>This ""shouldn't"" be encoded.</p> $thisShouldBeEncoded");

    Assert.IsTrue(result, "Evaluation returned failure");
    Assert.AreEqual(@"<p>This ""shouldn't"" be encoded.</p> &lt;p&gt;This &quot;should&quot; be &#39;encoded&#39;&lt;/p&gt;", writer.ToString());
}

private static void EventCartridge_ReferenceInsertion(object sender, ReferenceInsertionEventArgs e)
{
    var originalString = e.OriginalValue as string;

    if (originalString == null) return;

    e.NewValue = HtmlEncode(originalString);
}

private static string HtmlEncode(string value)
{
    return value
        .Replace("&", "&amp;")
        .Replace("<", "&lt;")
        .Replace(">", "&gt;")
        .Replace("\"", "&quot;")
        .Replace("'", "&#39;"); // &apos; does not work in IE
}
Was it helpful?

Solution

Try attaching a new EventCartridge to the VelocityContext. See these tests as reference.

Now that you've confirmed that this approach works, inherit from Castle.MonoRail.Framework.Views.NVelocity.NVelocityEngine, override BeforeMerge and set the EventCartridge and event there. Then configure MonoRail to use this custom view engine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top