Использование Razor для генерации содержимого сообщения email

Многие веб-приложения в процессе работы отправляют email-сообщения. И содержимое сообщений могут содержать как простой текст, так и HTML-разметку. Последний вариант предпочтительнее, если хочется видеть красиво отформатированное сообщение. Встает вопрос - а как генерировать эту разметку?

Существует множество библиотек, которые так или иначе решают эту задачу. Однако, если мы присмотримся, то увидим, что Razor - движок представлений в ASP.NET MVC - решает именно эту задачу, но для выдачи в браузер. Так почему же не приспособить Razor для генерации содержимого сообщений электронной почты?

  1. Для получения представления нужно воспользоваться методом ViewEngines.Engines.FindPartialView.
  2. Чтобы сгенерировать результат потребуется объект ViewContext, который содержит информацию о текущем контексте (ViewData, модель, параметры) - его просто нужно создать и определить начальные значения.
  3. Для генерации результата потребуется объект StringWriter - это стандартный прием, используемый движками представлений ASP.NET MVC.
  4. Чтобы получить результат следует вызвать метод Render и передать туда необходимые параметры.
  5. После получения результата следует освободить ресурсы, занимаемые представлением. Для этого используется метод ReleaseView.

Можно сделать метод-расширение, который выполняет эти действия:

public static class ViewEngineExtensions
{
  public static string RenderPartialView(this ControllerContext context,
      string viewName, object model = null)
  {
    StringBuilder result = new StringBuilder();

    using (var writer = new StringWriter(result))
    {
      var viewData = new ViewDataDictionary {Model = model};

      var view = ViewEngines.Engines.FindPartialView(context, viewName);
      var viewContext = new ViewContext(context, view.View, viewData,
          new TempDataDictionary(), writer);

      view.View.Render(viewContext, writer);
      view.ViewEngine.ReleaseView(context, view.View);
    }

    return result.ToString();
  }
}

Для генерации результата необходимо создать представление. Пусть это будет представление с именем _Message.cshtml, размещенное в папке Views/Shared:

@model int
<p>Value is <b>@Model</b></p>

Тогда код генерации результата и отправки email-сообщения будет выглядеть следующим образом:

using (SmtpClient smtp = new SmtpClient())
{
  MailMessage message = new MailMessage
  {
    Subject = "Test Message",
    IsBodyHtml = true,
    Body = ControllerContext.RenderPartialView("_Message", 22)
  };

  message.To.Add(@"[email protected]");

  smtp.Send(message);
}