I have several concerns with how the custom providers works https://www.limilabs.com/static/mail/documentation/html/T_Limilabs_Mail_Templates_ITemplateDataProvider.htm
I have list of history items:
public class HistoryItem {
public string FieldName {get;set;}
public string OldValue {get;set;}
public string NewValue {get;set;}
}
FieldName
is basically name of some property like Title
or StartDate
. I would like to provide all history items as the data source for the email template and access them via the FieldName as a key:
[if Title]
Old Title: <b>[Title.Old]</b>, New Title: <b>[Title.New]</b> <br/>
[end]
[if StartDate]
Old StartDate: <b>[StartDate.Old]</b>, New StartDate: <b>[StartDate.New]</b> <br/>
[end]
[if EndDate]
Old EndDate: <b>[EndDate.Old]</b>, New EndDate: <b>[EndDate.New]</b> <br/>
[end]
I render template with the Custom Provider:
IList<HistoryItem> changes
Template temp = Template.Create(template).DataFrom(new CustomProvider(changes));
I have created custom provider as something like that:
internal class CustomProvider : ITemplateDataProvider
{
private IList<HistoryItem> changes;
public CustomProvider(IList<HistoryItem> changes)
{
this.changes = changes;
}
public object GetValue(string key)
{
var fieldName = key;
if (fieldName.Contains("."))
{
var strings = fieldName.Split('.');
fieldName = strings[0];
change = changes.SingleOrDefault(x => x.FieldName == fieldName);
switch (strings[1].ToLower())
{
case "old":
return change.NewValue;
case "new":
return change.OldValue;
}
}
return key;
}
public bool HasValue(string name)
{
var fieldName = name;
if (fieldName.Contains("."))
{
var strings = fieldName.Split('.');
fieldName = strings[0];
}
return changes.Any(x => x.FieldName == fieldName);
}
}
The catch is that changes
list does not always have all the properties referenced in the template. So sometimes it's going to be one element with FieldName Title
, or sometimes two elements with FieldNames Title
and EndDate
and so on.
First problem is with the HasValue
method in the provider. When it returns false
whole thing just throws an exception. For example if changes
does not contain the StartDate
item, HasValue
return false and then I get exception:
'StartDate' was not found.
So the solution is to always return true from this method (what is the purpose of this method then?)
public bool HasValue(string name)
{
return true;
}
But in this case there is a problem with [if]
statements in the template. Basically there is no distinction between using [if Title]
and [Title]
. Both of them will fall under GetValue
method with "Title" as a key
attribute, but one of them requires to return boolean
and other one string
. For example if I use [if Title]
in the template and GetValue
method will return string
- I'm going to get invalid cast exception.
I imagine the solution would be as if the HasValue
returns false
- then do not call the GetValue
method (instead of throwing exception).
What am I missing here?