/
Notification/Certificate Template Development Guide
Table of Contents

Introduction

Creating new notification or certificate templates has its challenges since rendering (code execution) is happening in a black box where debugging is difficult and no breakpoints possible.

In order to help with debugging error handling needs to be done more explicitly. For example if a code line throws an Object reference not set to an instance of an object or similar exception we don’t know where and why it happened (no line number or stack trace).

Throwing explicit exceptions and checking variables whether an object lookup was successful would help with debugging and on live systems to look into issues.

Template for the certificate template: https://rippleops.atlassian.net/browse/SUCO-677

Other (real world) examples can be found in Git Core repository in

  • CustomerAssets\certificateTemplates

  • CustomerAssets\notificationTemplates

Example of a ‘Bad’ Template

As an example, we have a notification template ‘ProctorExam’ on BCF which tries to access an ExamInstanceAudit to pull information like grade. Due to partial RTS sync the notification is processed before the corresponding ExamInstanceAudit has been synced. As a result, the notification template can’t be rendered and throws a general exception which doesn’t reveal what was missing or where the error happened.

On top of the rendering exception the notification rule target generator ExamProctor doesn’t find the proctor to whom the notification should be sent as well - omitting a recipient if the template did render OK.

Template Code

Line 4 tries to accesses the examInstance's Id but examRepo.QueryById didn't find the exam instance audit and returned null resulting in a null reference exception in line 4 without any knowledge why this happened.

1var examRepo = Model.RepositoryFinder.GetRepository<IExamInstanceAuditRepository>(); 2var examInstanceId = Model.TvmDictionary[TemplateParameterKeyConstants.EXAM_INSTANCE_ID]; 3var examInstance = examRepo.QueryById(new Guid(examInstanceId)); 4var urlExamInstanceId = examInstance.Id.ToString();

Error

12021-10-17 09:26:28,652 [ERROR] {Email-NotificationChannel Thread} |NotificationManager.Impl.NotificationChannelEmail| *Core-Service-BCF* Service - Email-NotificationChannel: Could not render email. Template 'ProctorExam' (queue item Id = 'f2d7e15f-2f66-11ec-80fa-0cc47ad9ca93') - Discarding notification - from:no-reply@marinels.com, to:[email address removed (PII)] 2MarineLMS.Model.Interfaces.TemplateRenderingException: Razor rendering failed ---> System.NullReferenceException: Object reference not set to an instance of an object. 3 at CompiledRazorTemplates.Dynamic.edcbfeaacddafcfbc.Execute() 4 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context) 5 at MarineLMS.Model.Impl.TemplateHelper.RenderTemplate(String templateString, IDictionary`2 parameters, IRepositoryFinder repositoryFinder) 6 --- End of inner exception stack trace --- 7 at MarineLMS.Model.Impl.TemplateHelper.RenderTemplate(String templateString, IDictionary`2 parameters, IRepositoryFinder repositoryFinder) 8 at MarineLMS.NotificationManager.Impl.NotificationChannelEmail.DeliverItem(ICoreUnitofWork uow, IChannelQueueItem item)

Pitfalls for Template Rendering

Lookup of information which are not present in Model.TvmDictionary should be used with caution (i.e. lookup model object via Id from the DB). Not all information may be available at the time of template rendering (keep partial RTS sync in mind).

Always check if the requested object does exist - check for null. If an object was expected and is required for rendering throw an explicit error with as much detail as possible so debugging and live-site-investigations is easier.

Develop Print Layout

Chrome has the ability to render a print version of a page instead of needing to open the print menu to see the print layout. This could reduce dev time for the print version.

Open Chrome > Dev Tools (F11)-> three dots -> More tools -> Rendering -> emulate CSS media type

Set page size to whatever page you need to print:

Testing Print Layout

The preceding Dev Tools printing emulation should be viewed with caution. There are still many bugs with the tool as of this writing (Feb 2023). For example: print margins and positions are not accurately reflected when actually printing:

For this reason, any testing using this print emulation would be invalid. They should only be used for development.

Known Issues

Render Notification Template for Deleted Course

If a course gets deleted, the course name is not available anymore. Therefore, some notifications fail to get rendered because assembling the TVM dictionary entries fails. This is a known bug in GetAllTemplateParameters.

This issue mainly happens for pre-expiry notifications IsCategory(Certificate,PreExpiry) - see error below.

Error

12024-10-27 17:00:10,343 [ERROR] {Email-NotificationChannel Thread} |NotificationManager.Impl.NotificationChannelEmail| *Core-Service-Lindblad* Service - Email-NotificationChannel: Unexpected exception for queue item Id = '9100852c-94bf-11ef-911f-ac1f6b46ac39' 2System.NullReferenceException: Object reference not set to an instance of an object. 3 at MarineLMS.Model.Impl.CertificateNotification.GetAllTemplateParameters(TimeZoneInfo targetTimeZone) 4 at MarineLMS.NotificationManager.Impl.NotificationChannelEmail.AppendTemplateParametersFromTarget(ICoreUnitofWork uow, IChannelQueueItem item, String emailTo) 5 at MarineLMS.NotificationManager.Impl.NotificationChannelEmail.DeliverItem(ICoreUnitofWork uow, IChannelQueueItem item) 62024-10-27 17:00:10,359 [ERROR] {Email-NotificationChannel Thread} |NotificationManager.Impl.NotificationChannelEmail| *Core-Service-Lindblad* Service - Email-NotificationChannel: Unexpected exception for queue item Id = '9100852e-94bf-11ef-911f-ac1f6b46ac39' 7System.NullReferenceException: Object reference not set to an instance of an object. 8 at MarineLMS.Model.Impl.CertificateNotification.GetAllTemplateParameters(TimeZoneInfo targetTimeZone) 9 at MarineLMS.NotificationManager.Impl.NotificationChannelEmail.AppendTemplateParametersFromTarget(ICoreUnitofWork uow, IChannelQueueItem item, String emailTo) 10 at MarineLMS.NotificationManager.Impl.NotificationChannelEmail.DeliverItem(ICoreUnitofWork uow, IChannelQueueItem item)

Workaround

Ignore the error because the pre-expiry notification should not be sent.

Related Documents

https://rippleops.atlassian.net/wiki/spaces/MLSPS/pages/5440504718

https://rippleops.atlassian.net/wiki/spaces/MLSPS/pages/5440510574

https://rippleops.atlassian.net/wiki/spaces/CMD/pages/5432397319

https://rippleops.atlassian.net/wiki/spaces/CMD/pages/5432380983