using System.Threading.Tasks;
public class MailWrapper {
public async Task Send(string recipientEmailAddress, string recipientDisplayName, string subject, string htmlBody) {}
public string To { get; set; }
public string ToName { get; set; }
public abstract class MessageController<TMessage> where TMessage : Message
private readonly MailWrapper _mailWrapper;
protected abstract string TemplatePath { get; }
protected abstract string Subject { get; }
protected MessageController(MailWrapper mailWrapper)
_mailWrapper = mailWrapper;
public async Task Send(TMessage message) =>
await _mailWrapper.Send(message.To, message.ToName, RenderSubject(message), await RenderEmail(message));
private string RenderSubject(Message message) =>
message.GetType().GetProperties().Aggregate(Subject, (current, property) =>
current.Replace("{{" + property.Name + "}}", property.GetValue(message)?.ToString(),
StringComparison.InvariantCultureIgnoreCase));
public virtual async Task<string> RenderEmail(Message message) =>
message.GetType().GetProperties().Aggregate(
await new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(TemplatePath)!)
current.Replace("{{" + property.Name + "}}", property.GetValue(message)?.ToString(),
StringComparison.InvariantCultureIgnoreCase));
public class ClaimMessage : Message
public int ClaimId { get; set; }
public abstract class ClaimMessageController<TMessage> : MessageController<ClaimMessage>
private readonly MailWrapper _mailWrapper;
protected ClaimMessageController(MailWrapper mailWrapper) : base(mailWrapper)
_mailWrapper = mailWrapper;
public override Task<string> RenderEmail(TMessage message)
return base.RenderEmail(message);
public override async Task<string> RenderEmail(TMessage message) => (await base.RenderEmail((ClaimMessage)message)).Replace(
"{{ClaimUrl}}", $"https://foo/claim/{((ClaimMessage)message).ClaimId}",
StringComparison.InvariantCultureIgnoreCase);