Шаблоны e-mail сообщений в ASP.NET
Задача подготовки е-мейл сообщений на основе шаблонов в ASP.NET оказывается нетривиальной. Среди вариантов решения: использование стороннего шаблонизатора, использование XSLT. Но, если ASP.NET — тоже шаблонизатор, пусть и весьма специфический, почему бы не поручить работу по подготовке е-мейлов ему?
Пример будет рассматривать генерацию e-mail сообщений в формате HTML, но вполне подойдёт и для plain-text сообщений.
Идея состоит в следующем: в качестве шаблона использовать Web User Control, который затем будет рендерится в строку. Для реализации необходимы следующие компоненты:
User Control
Контрол содержит шаблон сообщения, внутри можно использовать обычные контролы, например, Repeater'ы, а в code-behind — привычные
методы доступа к данным.
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="OrderConfirmation.ascx.cs" Inherits="MailTemplates_OrderConfirmation" %>
<style>
*
{
font-family: Arial, Sans-Serif;
}
</style>
<p>Добрый день!</p>
<p>Спасибо за ваш заказ на сайте <a href="http://example.com">example.com</a>. Номер вашего заказа: <%=OrderId %></p>
<asp:Repeater runat="server" ID="rCart">
<HeaderTemplate>
<table cellpadding="5" cellspacing="0" border="1" summary="Товары">
<tr>
<td>
<strong>Наименование</strong>
</td>
<td>
<strong>Количество</strong>
</td>
<td>
<strong>Цена, грн</strong>
</td>
<td>
<strong>Сумма, грн</strong>
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%# ((GoodCustom)Container.DataItem).Producer.ProducerName %>
<%# ((GoodCustom)Container.DataItem).GoodName %></td>
<td align="center">
<%# Cart.GetOne(((GoodCustom)Container.DataItem).NGood).Quantity %>
</td>
<td align="right">
<%# Cart.GetOne(((GoodCustom)Container.DataItem).NGood).Price.ToString("N") %>
</td>
<td align="right">
<%# (Cart.GetOne(((GoodCustom)Container.DataItem).NGood).Quantity * Cart.GetOne(((GoodCustom)Container.DataItem).NGood).Price).ToString("N") %>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
<p>Итого: <strong><asp:Literal ID="ltTotal" runat="server"></asp:Literal></strong> грн</p>
<hr />
<p>
ПОЖАЛУЙСТА, НЕ ОТВЕЧАЙТЕ НА ЭТО ПИСЬМО, ОНО СГЕНЕРИРОВАНО АВТОМАТИЧЕСКИ
</p>
Метод, отвечающий за рендеринг
Идея подсмотрена в одном хорошем блоге и состоит в создании фиктивного класса страницы.
public static string ProcessControl(string path, Dictionary<string, object> parameters)
{
Page page = new Page();
Control myControl = page.LoadControl(path);
StringBuilder sb = new StringBuilder();
Type type = myControl.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (KeyValuePair<string, object> kvp in parameters)
{
foreach (PropertyInfo property in properties)
{
if (kvp.Key == property.Name)
{
property.SetValue(myControl, kvp.Value, null);
}
}
}
page.Controls.Add(myControl);
using (StringWriter sw = new StringWriter(sb))
{
page.Server.Execute(page, sw, false);
}
return sb.ToString();
}
Генерация е-мейла
string emailBody = UtilsTemplate.ProcessControl("~/MailTemplates/OrderConfirmation.ascx", new Dictionary<string, object> { { "OrderId", orderId } });
Недостатком способа является то, что параметры контрола передаются в виде нетипизированного Dictionary.
