Могу ли я настроить шаблоны HTML / электронной почты с ASP.NET? - PullRequest
94 голосов
/ 06 марта 2009

Я работаю над сайтом, который будет рассылать значительное количество писем. Я хочу настроить как верхний, так и нижний колонтитулы или, возможно, даже шаблоны, чтобы пользователи могли легко редактировать эти электронные письма, если им это необходимо.

Если я вставлю HTML-код в строковые литералы C #, это будет ужасно, и им придется беспокоиться о побеге. Включение плоских файлов для верхнего и нижнего колонтитула может сработать, но что-то в этом не так.

Что было бы идеально, если бы каким-то образом использовать страницу .ASPX в качестве шаблона, а затем просто указать мой код для обслуживания этой страницы и использовать HTML-код, возвращенный для электронной почты.

Есть ли хороший и простой способ сделать это? Есть ли лучший способ решить эту проблему?

Изменено:
Я добавил ответ, который позволяет использовать стандартную страницу .aspx в качестве шаблона электронной почты. Просто замените все переменные, как обычно, используйте привязку данных и т. Д. Затем просто запишите выходные данные страницы и вуаля! У вас есть электронная почта в формате HTML!

ОБНОВЛЕНО CAVEAT !!!:
Я использовал класс MailDefinition на некоторых страницах aspx просто отлично, но при попытке использовать этот класс во время запущенного серверного процесса он не удался. Я полагаю, что это потому, что метод MailDefinition.CreateMailMessage () требует действительный элемент управления для ссылки, даже если он не всегда что-то делает. По этой причине я бы порекомендовал свой подход с использованием страницы aspx или подход Маня с использованием страницы ascx, что выглядит немного лучше.

Ответы [ 23 ]

0 голосов
/ 06 марта 2009

Если вы можете разрешить ASPNET и связанным пользователям разрешение на чтение и запись файла, вы можете легко использовать HTML-файл со стандартными String.Format() заполнителями ({0}, {1:C} и т. Д.), Чтобы выполнить это ,

Просто читать в файле в виде строки, используя классы из пространства имен System.IO. Получив эту строку, передайте ее в качестве первого аргумента String.Format() и предоставьте параметры.

Держите эту строку рядом и используйте ее как тело письма, и вы, по сути, закончили. Мы делаем это на десятках (по общему признанию, небольших) сайтов сегодня, и у нас не было проблем.

Я должен отметить, что это работает лучше всего, если (а) вы не отправляете миллионы электронных писем одновременно, (б) вы не персонализируете каждое электронное письмо (в противном случае вы съедаете кучу строк) и (c) сам файл HTML является относительно небольшим.

0 голосов
/ 31 августа 2014

@ bardev предоставляет хорошее решение, но, к сожалению, оно не идеально во всех случаях. Мой был одним из них.

Я использую веб-формы на веб-сайте (клянусь, я больше никогда не буду использовать веб-сайт - что за PITA) в VS 2013.

Я попробовал предложение Razor, но, поскольку я был веб-сайтом, я не получил все необходимое IntelliSense, которое IDE предоставляет в проекте MVC. Мне также нравится использовать дизайнер для моих шаблонов - идеальное место для UserControl.

Снова Nix на Razor.

Так что вместо этого я придумал этот небольшой фреймворк (советы для @mun для UserControl и @imatoria для строгой типизации). Единственная потенциальная проблема, которую я вижу, это то, что вы должны быть осторожны, чтобы синхронизировать имя файла .ASCX с именем класса. Если вы заблудитесь, вы получите ошибку во время выполнения.

FWIW: В моем тестировании, по крайней мере, вызов RenderControl () не понравился элементу управления Page, поэтому я использовал UserControl.

Я почти уверен, что включил все здесь; дайте мне знать, если я что-то пропустил.

НТН

Использование:

Partial Class Purchase
  Inherits UserControl

  Private Sub SendReceipt()
    Dim oTemplate As MailTemplates.PurchaseReceipt

    oTemplate = MailTemplates.Templates.PurchaseReceipt(Me)
    oTemplate.Name = "James Bond"
    oTemplate.OrderTotal = 3500000
    oTemplate.OrderDescription = "Q-Stuff"
    oTemplate.InjectCss("PurchaseReceipt")

    Utils.SendMail("{0} <james.bond@mi6.co.uk>".ToFormat(oTemplate.Name), "Purchase Receipt", oTemplate.ToHtml)
  End Sub
End Class

Базовый класс:

Namespace MailTemplates
  Public MustInherit Class BaseTemplate
    Inherits UserControl

    Public Shared Function GetTemplate(Caller As TemplateControl, Template As Type) As BaseTemplate
      Return Caller.LoadControl("~/MailTemplates/{0}.ascx".ToFormat(Template.Name))
    End Function



    Public Sub InjectCss(FileName As String)
      If Me.Styler IsNot Nothing Then
        Me.Styler.Controls.Add(New Controls.Styler(FileName))
      End If
    End Sub



    Private ReadOnly Property Styler As PlaceHolder
      Get
        If _Styler Is Nothing Then
          _Styler = Me.FindNestedControl(GetType(PlaceHolder))
        End If

        Return _Styler
      End Get
    End Property
    Private _Styler As PlaceHolder
  End Class
End Namespace

"Фабрика" Класс:

Namespace MailTemplates
  Public Class Templates
    Public Shared ReadOnly Property PurchaseReceipt(Caller As TemplateControl) As PurchaseReceipt
      Get
        Return BaseTemplate.GetTemplate(Caller, GetType(PurchaseReceipt))
      End Get
    End Property
  End Class
End Namespace

Шаблон класса:

Namespace MailTemplates
  Public MustInherit Class PurchaseReceipt
    Inherits BaseTemplate

    Public MustOverride WriteOnly Property Name As String
    Public MustOverride WriteOnly Property OrderTotal As Decimal
    Public MustOverride WriteOnly Property OrderDescription As String
  End Class
End Namespace

Заголовок ASCX:

<%@ Control Language="VB" ClassName="_Header" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<!--
  See https://www.campaignmonitor.com/blog/post/3317/ for discussion of DocType in HTML Email
-->

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
  <asp:PlaceHolder ID="plcStyler" runat="server"></asp:PlaceHolder>
</head>
<body>

Нижний колонтитул ASCX:

<%@ Control Language="VB" ClassName="_Footer" %>

</body>
</html>

Шаблон ASCX:

<%@ Control Language="VB" AutoEventWireup="false" CodeFile="PurchaseReceipt.ascx.vb" Inherits="PurchaseReceipt" %>

<%@ Register Src="_Header.ascx" TagName="Header" TagPrefix="uc" %>
<%@ Register Src="_Footer.ascx" TagName="Footer" TagPrefix="uc" %>

<uc:Header ID="ctlHeader" runat="server" />

  <p>Name: <asp:Label ID="lblName" runat="server"></asp:Label></p>
  <p>Order Total: <asp:Label ID="lblOrderTotal" runat="server"></asp:Label></p>
  <p>Order Description: <asp:Label ID="lblOrderDescription" runat="server"></asp:Label></p>

<uc:Footer ID="ctlFooter" runat="server" />

Шаблон ASCX CodeFile:

Partial Class PurchaseReceipt
  Inherits MailTemplates.PurchaseReceipt

  Public Overrides WriteOnly Property Name As String
    Set(Value As String)
      lblName.Text = Value
    End Set
  End Property



  Public Overrides WriteOnly Property OrderTotal As Decimal
    Set(Value As Boolean)
      lblOrderTotal.Text = Value
    End Set
  End Property



  Public Overrides WriteOnly Property OrderDescription As Decimal
    Set(Value As Boolean)
      lblOrderDescription.Text = Value
    End Set
  End Property
End Class

Помощники:

'
' FindNestedControl helpers based on tip by @andleer
' at http://stackoverflow.com/questions/619449/
'

Public Module Helpers
  <Extension>
  Public Function AllControls(Control As Control) As List(Of Control)
    Return Control.Controls.Flatten
  End Function



  <Extension>
  Public Function FindNestedControl(Control As Control, Id As String) As Control
    Return Control.Controls.Flatten(Function(C) C.ID = Id).SingleOrDefault
  End Function



  <Extension>
  Public Function FindNestedControl(Control As Control, Type As Type) As Control
    Return Control.Controls.Flatten(Function(C) C.GetType = Type).SingleOrDefault
  End Function



  <Extension>
  Public Function Flatten(Controls As ControlCollection) As List(Of Control)
    Flatten = New List(Of Control)

    Controls.Traverse(Sub(Control) Flatten.Add(Control))
  End Function


  <Extension>
  Public Function Flatten(Controls As ControlCollection, Predicate As Func(Of Control, Boolean)) As List(Of Control)
    Flatten = New List(Of Control)

    Controls.Traverse(Sub(Control)
                        If Predicate(Control) Then
                          Flatten.Add(Control)
                        End If
                      End Sub)
  End Function



  <Extension>
  Public Sub Traverse(Controls As ControlCollection, Action As Action(Of Control))
    Controls.Cast(Of Control).ToList.ForEach(Sub(Control As Control)
                                               Action(Control)

                                               If Control.HasControls Then
                                                 Control.Controls.Traverse(Action)
                                               End If
                                             End Sub)
  End Sub



  <Extension()>
  Public Function ToFormat(Template As String, ParamArray Values As Object()) As String
    Return String.Format(Template, Values)
  End Function



  <Extension()>
  Public Function ToHtml(Control As Control) As String
    Dim oSb As StringBuilder

    oSb = New StringBuilder

    Using oSw As New StringWriter(oSb)
      Using oTw As New HtmlTextWriter(oSw)
        Control.RenderControl(oTw)
        Return oSb.ToString
      End Using
    End Using
  End Function
End Module



Namespace Controls
  Public Class Styler
    Inherits LiteralControl

    Public Sub New(FileName As String)
      Dim _
        sFileName,
        sFilePath As String

      sFileName = Path.GetFileNameWithoutExtension(FileName)
      sFilePath = HttpContext.Current.Server.MapPath("~/Styles/{0}.css".ToFormat(sFileName))

      If File.Exists(sFilePath) Then
        Me.Text = "{0}<style type=""text/css"">{0}{1}</style>{0}".ToFormat(vbCrLf, File.ReadAllText(sFilePath))
      Else
        Me.Text = String.Empty
      End If
    End Sub
  End Class
End Namespace



Public Class Utils
  Public Shared Sub SendMail(Recipient As MailAddress, Subject As String, HtmlBody As String)
    Using oMessage As New MailMessage
      oMessage.To.Add(Recipient)
      oMessage.IsBodyHtml = True
      oMessage.Subject = Subject.Trim
      oMessage.Body = HtmlBody.Trim

      Using oClient As New SmtpClient
        oClient.Send(oMessage)
      End Using
    End Using
  End Sub
End Class
0 голосов
/ 30 марта 2009

Посмотрите на SubSonic (www.subsonicproject.com). Они делают именно это для генерации кода - шаблон является стандартным ASPX, и он выводит c #. Этот же метод можно использовать повторно для вашего сценария.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...