diff --git a/Examples/ConsoleApp/Program.cs b/Examples/ConsoleApp/Program.cs
index ae9b669..66faaf4 100644
--- a/Examples/ConsoleApp/Program.cs
+++ b/Examples/ConsoleApp/Program.cs
@@ -22,6 +22,7 @@ public class Program
{
public static string root = @"..\..\";
public static bool debug = true;
+ public static HandleFailAction modelEntryFailAction = HandleFailAction.exception;
static void Main(string[] args)
{
@@ -40,7 +41,7 @@ static void Generate(string name, object model)
Console.WriteLine("Generating " + name);
- var doc = Templ.Load(file).Build(model, debug).SaveAs(output);
+ var doc = Templ.Load(file).Build(model, debug, modelEntryFailAction).SaveAs(output);
if (debug) doc.Debugger.SaveAs(output);
}
}
diff --git a/Templ.NET/ModelEntry.cs b/Templ.NET/ModelEntry.cs
index 3d68728..8c35923 100644
--- a/Templ.NET/ModelEntry.cs
+++ b/Templ.NET/ModelEntry.cs
@@ -7,6 +7,22 @@
namespace TemplNET
{
+ public class ModelEntryException : Exception
+ {
+ public ModelEntryException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+
+ ///
+ /// List of ways in which an exception in a module handler can be handled
+ ///
+ /// Example: {txt:user.name} // user.name is not a property in the model
+ public enum HandleFailAction
+ {
+ exception, ignore, remove
+ };
+
///
/// Represents a reference-by-reflection to a Entry (a field/property/member) within an object.
/// The entry's nested Path is defined with a string.
@@ -189,23 +205,28 @@ private static MemberValue GetPrimitive(object model, string path)
///
public static TemplModelEntry Get(object model, string path)
{
- MemberValue propVal;
- var primitive = GetPrimitive(model, path);
- if (primitive == null)
- {
- propVal = MemberValue.FindPath(model, path.Trim());
+ try {
+ MemberValue propVal;
+ var primitive = GetPrimitive(model, path);
+ if (primitive == null)
+ {
+ propVal = MemberValue.FindPath(model, path.Trim());
+ }
+ else
+ {
+ propVal = primitive;
+ }
+ return new TemplModelEntry()
+ {
+ Model = model,
+ Path = path.Trim(),
+ Info = propVal.Info,
+ Value = propVal.Value
+ };
}
- else
- {
- propVal = primitive;
+ catch (Exception ex) {
+ throw new ModelEntryException($"Failed to retrieve entry from the model at path '{path}'", ex);
}
- return new TemplModelEntry()
- {
- Model = model,
- Path = path.Trim(),
- Info = propVal.Info,
- Value = propVal.Value
- };
}
///
diff --git a/Templ.NET/Module.cs b/Templ.NET/Module.cs
index c355346..d917623 100644
--- a/Templ.NET/Module.cs
+++ b/Templ.NET/Module.cs
@@ -65,7 +65,7 @@ protected TemplModule AddPrefix(string prefix)
/// Applies all changes to the document.
/// automatically executes it for all .
///
- public abstract void Build(DocX doc, object model);
+ public abstract void Build(DocX doc, object model, HandleFailAction modelEntryFailAction);
}
///
@@ -127,7 +127,6 @@ private bool RemoveExpired(T m)
/// Verifies the number of fields in the supplied Match's placeholder is within the min/max expected for this Module.
/// Throws exception if problems are found.
///
- ///
private T CheckFieldCount(T m)
{
var l = m.Fields.Length;
@@ -141,10 +140,11 @@ private T CheckFieldCount(T m)
}
return m;
}
+
///
/// Handle and/or remove a collection of Matches from the document
///
- public void BuildFromScope(DocX doc, object model, IEnumerable scope)
+ public void BuildFromScope(DocX doc, object model, IEnumerable scope, HandleFailAction modelEntryFailAction)
{
var watch = Stopwatch.StartNew();
// Mark module instance as "used" if any matches are being processed
@@ -154,35 +154,51 @@ public void BuildFromScope(DocX doc, object model, IEnumerable scope)
// Note how we are constantly "committing" the changes using ToList().
// This ensures order is preserved (e.g. all "finds" happen before all "handler"s)
scope.Select( m => CheckFieldCount(m) ).ToList()
- .Select( m => Handler(doc, model, m)).ToList()
+ .Select( m => TryHandler(doc, model, m, modelEntryFailAction)).ToList()
.Where( m =>!RemoveExpired(m)).ToList()
.Select( m => CustomHandler(doc, model, m)).ToList()
.ForEach(m => RemoveExpired(m));
Statistics.millis = watch.ElapsedMilliseconds;
}
+
+ private T TryHandler(DocX doc, object model, T m, HandleFailAction modelEntryFailAction)
+ {
+ try
+ {
+ return Handler(doc, model, m);
+ }
+ catch (ModelEntryException)
+ {
+ switch (modelEntryFailAction)
+ {
+ case HandleFailAction.exception:
+ throw;
+ case HandleFailAction.remove:
+ m.Expired = true;
+ break;
+ }
+ return m;
+ }
+ }
+
///
/// Find and build all content from the document
///
- public override void Build(DocX doc, object model)
+ public override void Build(DocX doc, object model, HandleFailAction modelEntryFailAction)
{
- BuildFromScope(doc, model, Regexes.SelectMany(rxp => FindAll(doc, rxp)));
+ BuildFromScope(doc, model, Regexes.SelectMany(rxp => FindAll(doc, rxp)), modelEntryFailAction);
}
///
/// Module-specific Match handler.
/// Implementations should modify the Matched content, or mark expired to delete
///
- ///
- ///
- ///
public abstract T Handler(DocX doc, object model, T m);
///
/// Module-specific finder.
/// Implementations should retrieve all regex-matching content from the document.
///
- ///
- ///
public abstract IEnumerable FindAll(DocX doc, TemplRegex rxp);
}
diff --git a/Templ.NET/Modules.cs b/Templ.NET/Modules.cs
index 8ea33f3..da67c30 100644
--- a/Templ.NET/Modules.cs
+++ b/Templ.NET/Modules.cs
@@ -64,7 +64,7 @@ public void BuildFromScope(DocX doc, object model, IEnumerable paragr
{
Path = path;
Paragraphs = paragraphs;
- Build(doc, model);
+ Build(doc, model, HandleFailAction.exception);
Path = "";
paragraphs = new List();
}
diff --git a/Templ.NET/Templ.cs b/Templ.NET/Templ.cs
index 465e168..d326bb1 100644
--- a/Templ.NET/Templ.cs
+++ b/Templ.NET/Templ.cs
@@ -127,7 +127,7 @@ public static Templ Load(string templatePath, bool useDefaultModules = true)
///
///
///
- public Templ Build(object model, bool debug = TemplConst.Debug)
+ public Templ Build(object model, bool debug = TemplConst.Debug, HandleFailAction modelEntryFailAction = HandleFailAction.exception)
{
if (debug)
{
@@ -135,7 +135,7 @@ public Templ Build(object model, bool debug = TemplConst.Debug)
}
ActiveModules.ForEach(module =>
{
- module.Build(Document.Docx, model);
+ module.Build(Document.Docx, model, modelEntryFailAction);
if (debug && module.Used)
{
Debugger.AddState(Document, module.Name);