Error
As of Rock v17 DotLiquid will no longer be supported and the engine is being removed.
In many cases, you might just need to add:
using Rock.Lava;
And then include this above your Template.RegisterFilter(...):
Template.RegisterFilter(...)
LavaService.RegisterFilters( typeof( org.mydomain.MyCustomPluginsLavaFilters ) );
In many cases, you might just need to change how you get your Template from this:
var lavaTemplate = Template.Parse( GetAttributeValue( MY_LAVA_TEMPLATE ) );
to this:
using Rock.Lava; ... var parseResult = LavaService.ParseTemplate( GetAttributeValue( MY_LAVA_TEMPLATE ) ); var lavaTemplate = parseResult.Template;
Replace : DotLiquid.Drop with : LavaDataObject
: DotLiquid.Drop
: LavaDataObject
If you have plug-in code that uses Lava and DotLiquid objects prior to Rock v13, it will need to be modified to support the new Lava library implementation.
Rock v13 supports a number of different Lava processing modes, with the primary goal of easing the transition to the Lava library by providing backward compatibility and side-by-side verification and testing.
Fluid Mode - Fluid is the new rendering framework used by the Lava library, and it offers greater rendering speed and resource efficiency for your Rock environment. In this mode, Rock processes Lava templates using the framework which will become the default processor in future versions of Rock.
DotLiquid Mode (Deprecated/Obsolete) - In this configuration, Rock continues to render Lava templates using the pre-v13 DotLiquid framework. This mode offers complete backward compatibility with existing custom code and plugins, and is available as a fallback if your custom code does not yet operate correctly with the new Lava library.
DotLiquid (Fluid Verification) Mode (Deprecated/Obsolete) - As with DotLiquid mode, Lava output is rendered using the pre-v13 DotLiquid framework. However, the same Lava is also processed by the Fluid engine as a background process and any errors or discrepancies in the final output are recorded in the Rock Exception Log. This provides a means of testing your custom Lava for compatibility with the Fluid framework before selecting it as your Lava renderinf engine of choice.
The Lava Engine Liquid Framework Global Attribute controls which engine Rock will use for processing Lava.
Adding support for the Lava library to your plug-in or custom code involves a number of changes. The most important thing to understand is that to be fully compatible with Rock v13 and allow your components to operate in both Fluid and DotLiquid modes, your custom code must provide support for both of these Lava implementations until the transition period is over and DotLiquid is no longer supported (likely v15).
For that reason, adding compatibility for the Lava library involves adding an alternate implementation to your code rather than modifying existing code.
In previous versions of Rock, custom filter methods were registered as follows:
Template.RegisterFilter( typeof(MyFilterClass) );
In the Lava Library, filter registration is now accomplished using the Lava engine:
LavaService.RegisterFilters( typeof(MyFilterClass) );
Add a Reference to the Rock.Lava.Shared assembly to your project. This assembly holds all of the data objects and interfaces that are needed to interact with the Lava Engine.
Rock.Lava.Shared
Remove the reference to the DotLiquid.dll assembly from your project. Objects from the DotLiquid library should be replaced with the equivalent Lava library object, as shown in the following table.
DotLiquid.dll
DotLiquid.Context
ILavaRenderContext
LavaService.NewRenderContext
DotLiquid.DropBase
LavaDataObject
DotLiquid.LiquidType
LavaType
Rock.Data.LavaInclude
LavaVisible
Rock.Data.LavaIgnore
LavaHidden
DotLiquid.Hash
LavaDataDictionary
IDictionary<string, object>
Prior to v13, the properties of a class could be exposed to a Lava template by one of these methods:
Template.RegisterSafeType
DotLiquid.ILiquidizable
Rock.Lava.RockDynamic
The ILiquidizable interface has been replaced by ILavaDataDictionarySource. The purpose of this interface is the same – it signals that the class is capable of providing a data object that can be referenced in a Lava template.
ILiquidizable
ILavaDataDictionarySource
Prior Version:
public class MyLavaClass : ILiquidizable { public string Property1 { get; set; } public string Property2 { get; set; } public virtual object ToLiquid() { var dictionary = new Dictionary() { { "Property1", Property1 }, { "Property2", Property2 } }; return dictionary; } }
Lava Library:
public class MyLavaClass : ILavaDataDictionarySource { public string Property1 { get; set; } public string Property2 { get; set; } public virtual ILavaDataDictionary GetLavaDataDictionary() { var dictionary = new LavaDataDictionary() { { "Property1", Property1 }, { "Property2", Property2 } }; return dictionary; } }
In the previous implementation, the ILiquidizable.ToLiquid function returned an untyped object, whereas ILavaDataDictionarySource.GetLavaDataDictionary returns a strongly-typed ILavaDataDictionary. This change is intended to add a measure of type-safety and prevent incompatible types being returned to the Lava engine. If the type you wish to return does not directly implement ILavaDataDictionary, it can be wrapped in a LavaDataObject to provide dynamic access to the wrapped object properties using .NET Reflection.
ILiquidizable.ToLiquid
ILavaDataDictionarySource.GetLavaDataDictionary
ILavaDataDictionary
Some additional types have been added to the Lava library to assist with migrating current code. Each of these types directly implements the ILavaDataDictionary interface.
The DotLiquid.DropBase abstract class has been replaced by the Rock.Lava.LavaDataObject class. The purpose of this class is the same – to allow customised storage and retrieval for the properties of a Lava-accessible data object.
Rock.Lava.LavaDataObject
public class DataRowLava : DotLiquid.Drop { private readonly DataRow _dataRow; public DataRowDrop( DataRow dataRow ) { _dataRow = dataRow; } public override object BeforeMethod( string method ) { if ( _dataRow.Table.Columns.Contains( method ) ) { return _dataRow[method]; } return null; } }
private class DataRowLava : LavaDataObject { private readonly DataRow _dataRow; public DataRowDrop( DataRow dataRow ) { _dataRow = dataRow; } protected override bool OnTryGetValue( string key, out object result ) { if ( _dataRow.Table.Columns.Contains( key ) ) { result = _dataRow[key]; return true; } result = null; return false; } }
public static string MyLavaFilter( DotLiquid.Context context, object input )
public static string MyLavaFilter( ILavaRenderContext context, object input )
using DotLiquid;
IRockLavaBlock
IRockLavaTag
Template.RegisterTagTemplate.RegisterBlockTemplate.RegisterShortcode<>
IRockStartup
Parse(List<string> tokens)
DotLiquid.Block.NodeList
OnParsed(List<string> tokens)
A custom Rock Block that fetches its own parser from the DotLiquid Template class should be adjusted to use the LavaService to get a template. To make it compatible with both engines through the transition period, you can implement a check to see which engine is currently running:
using Rock.Lava; ... // LavaService.RockLiquidIsEnabled is the old engine (a Rock fork of the DotLiquid engine) if ( LavaService.RockLiquidIsEnabled ) { var lavaTemplate = Template.Parse( GetAttributeValue( YOUR_LAVA_TEMPLATE ) ); output = lavaTemplate.Render( Hash.FromDictionary( mergeFields ) ); } else { var parseResult = LavaService.ParseTemplate( GetAttributeValue( YOUR_LAVA_TEMPLATE ) ); var lavaTemplate = parseResult.Template; output = lavaTemplate.Render( mergeFields ); }
Any code that simply uses the ResolveMergeFields() extension method will continue to work without modification.
ResolveMergeFields()
var template = this.GetAttributeValue( MY_LAVA_TEMPLATE ); output = template.ResolveMergeFields( mergeFields );